Heim  >  Artikel  >  Backend-Entwicklung  >  PHP,C# 跟JAVARSA签名及验签

PHP,C# 跟JAVARSA签名及验签

WBOY
WBOYOriginal
2016-06-13 12:31:021408Durchsuche

PHP,C# 和JAVARSA签名及验签

这个功能网上搜了好多资料。贡献一下,转载须注明并对卓二妹的无私奉献表示感谢。

1)签名算法使用SHA1withRSA。

2)签名后的数据位base64编码的密文字符串。

3)三个环境进行签名的私钥的格式不同,需要openssl工具进行转换。

――――――――――――――――――――――――――――――――――――――――――

JAVA签名:

1)从包含公私钥的pfx证书中取得.key私钥:

F:\openssl-0.9.8k_WIN32\bin>openssl pkcs12 -in f:\certs\zhuo.pfx -out f:\certs\zhuo.pem
Enter Import Password:(输入导出时的密码)
MAC verified OK
Enter PEM pass phrase:(长度至少为4位的pem证书密码)
Verifying - Enter PEM pass phrase:(确认一次pem证书密码)
 
F:\openssl-0.9.8k_WIN32\bin>openssl pkcs8 -topk8 -inform PEM -outform DER -in f:\certs\zhuo.pem -out f:\certs\zhuo_der.key -nocrypt
Enter pass phrase for f:\certs\zhuo.pem:(输入pem证书密码)
??

该步骤生成的.key文件即为JAVA签名所需私钥文件。

2)生成公钥:直接从IE中导出X.509格式二进制编码的cer为后缀的公钥证书即可。

?

?

3)签名验签:

?

//签名:
/**
	 * 
	 * 函数功能说明: 签名数据
	 * created by zhuoyueping 2013-8-17
	 * modified by zhuoyueping 2013-8-17 
	 * 修改内容说明: 
	 * @param @param content:签名原文
	 * @param @param keyfile:私钥文件.key路径
	 * @param @return
	 * @param @throws Exception     
	 * @return String :base64签名
	 * @throws
	 */
	public String sign(String content, String keyfile) throws Exception {
		File file = new File(keyfile); //keyfile key文件的地址
		FileInputStream in;
		in = new FileInputStream(file);

		ByteArrayOutputStream bout = new ByteArrayOutputStream();
		byte[] tmpbuf = new byte[1024];
		int count = 0;
		while ((count = in.read(tmpbuf)) != -1) {
			bout.write(tmpbuf, 0, count);
			tmpbuf = new byte[1024];
		}
		in.close();

		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(bout
				.toByteArray());
		RSAPrivateKey privateKey = (RSAPrivateKey) keyFactory
				.generatePrivate(privateKeySpec);

		Signature dsa = Signature.getInstance("SHA1withRSA"); //采用SHA1withRSA加密
		dsa.initSign(privateKey);
		dsa.update(content.getBytes("UTF-8")); //voucher需要加密的String必须变成byte类型的
		byte[] sig = dsa.sign();

		String rtnValue = new String(Base64.encode(sig));

		return rtnValue;
	}

	/**
	 * <p>
	 * 验证签名
	 * </p>
	 *
	 * @param data 原文字节
	 * @param sign 数据签名[BASE64]
	 * @param certificatePath 证书存储路径
	 * @return
	 * @throws Exception
	 */
public static boolean verifySign(byte[] data, String sign,
			String certificatePath) throws Exception {
		// 获得证书
		X509Certificate x509Certificate = (X509Certificate) getCertificate(certificatePath);
		return verifySign(data,sign,x509Certificate);
	}

private static boolean verifySign(byte[] data, String sign, X509Certificate x509Certificate)throws Exception {
		PublicKey publicKey = x509Certificate.getPublicKey();
		Signature signature = Signature.getInstance(x509Certificate
				.getSigAlgName());
		signature.initVerify(publicKey);
		signature.update(data);
		return signature.verify(Base64.decode(sign.getBytes()));
	}

?

C#签名:

1)从包含公私钥的pfx证书中取得.key私钥:

F:\openssl-0.9.8k_WIN32\bin> openssl rsa -in d:\\certs\\zhuo.pfx -nocerts -nodes -out d:\\certs\\zhuo.key

该步骤生成的.key文件即为C#签名所需私钥文件。
?

2)公钥生成:于java方式相同,都是二进制格式的x509证书3)签名及验签:

using System;
using System.Text;
using System.Security.Cryptography;
using System.Web;
using System.IO;
using System.Security.Cryptography.X509Certificates;  

namespace Safe
{
    public class SafeUtil
    {
        /// <summary>
        /// 验证签名
        /// </summary>
        /// <param name="OriginalString">原文:UTF8编码</param>
        /// <param name="SignatureString">签名:base64编码的字节</param>
        /// <param name="publicKeyPath">公钥路径</param>
        /// <returns> 验签结果</returns>
        public bool Verify(String OriginalString, String SignatureString,String publicKeyPath)
        {
               //将base64签名数据转码为字节 
                byte[] signedBase64 = Convert.FromBase64String(SignatureString);
                byte[] orgin = Encoding.UTF8.GetBytes(OriginalString);
 
                X509Certificate2 x509_Cer1 = new X509Certificate2(publicKeyPath);

                RSACryptoServiceProvider oRSA = new RSACryptoServiceProvider();
                oRSA.FromXmlString(x509_Cer1.PublicKey.Key.ToXmlString(false));

                bool bVerify = oRSA.VerifyData(orgin, "SHA1", signedBase64);
                return bVerify;

        }

        /// <summary>
        /// 验证签名
        /// </summary>
        /// <param name="data">原文:UTF8编码</param>
        /// <param name="privateKeyPath">证书路径:D:/certs/mycert.key</param>
        /// <returns> 验签</returns>
        public string Sign(string data, string privateKeyPath)
        {
            RSACryptoServiceProvider rsaCsp = LoadCertificateFile(privateKeyPath);
            byte[] dataBytes = Encoding.UTF8.GetBytes(data);
            byte[] signatureBytes = rsaCsp.SignData(dataBytes, "SHA1");
            return Convert.ToBase64String(signatureBytes);
        }

        private  byte[] GetPem(string type, byte[] data)
        {
            string pem = Encoding.UTF8.GetString(data);
            string header = String.Format("-----BEGIN {0}-----", type);
            string footer = String.Format("-----END {0}-----", type);
            int start = pem.IndexOf(header) + header.Length;
            int end = pem.IndexOf(footer, start);
 
            string base64 = pem.Substring(start, (end - start));
   
            return Convert.FromBase64String(base64);
        }

        private  RSACryptoServiceProvider LoadCertificateFile(string filename)
        {
            using (System.IO.FileStream fs = System.IO.File.OpenRead(filename))
            {
                byte[] data = new byte[fs.Length];
                byte[] res = null;
                fs.Read(data, 0, data.Length);
                if (data[0] != 0x30)
                {
                    res = GetPem("RSA PRIVATE KEY", data);
                }
                try
                {
                    RSACryptoServiceProvider rsa = DecodeRSAPrivateKey(res);
                    return rsa;
                }
                catch (Exception ex)
                {
                }
                return null;
            }
        }

        private  RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey)
        {
            byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;
             
            // --------- Set up stream to decode the asn.1 encoded RSA private key ------  
            MemoryStream mem = new MemoryStream(privkey);
            BinaryReader binr = new BinaryReader(mem);  //wrap Memory Stream with BinaryReader for easy reading  
            byte bt = 0;
            ushort twobytes = 0;
            int elems = 0;
            try
            {
                twobytes = binr.ReadUInt16();
                if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)  
                    binr.ReadByte();    //advance 1 byte  
                else if (twobytes == 0x8230)
                    binr.ReadInt16();    //advance 2 bytes  
                else
                    return null;

                twobytes = binr.ReadUInt16();
                if (twobytes != 0x0102) //version number  
                    return null;
                bt = binr.ReadByte();
                if (bt != 0x00)
                    return null;


                //------ all private key components are Integer sequences ----  
                elems = GetIntegerSize(binr);
                MODULUS = binr.ReadBytes(elems);

                elems = GetIntegerSize(binr);
                E = binr.ReadBytes(elems);

                elems = GetIntegerSize(binr);
                D = binr.ReadBytes(elems);

                elems = GetIntegerSize(binr);
                P = binr.ReadBytes(elems);

                elems = GetIntegerSize(binr);
                Q = binr.ReadBytes(elems);

                elems = GetIntegerSize(binr);
                DP = binr.ReadBytes(elems);

                elems = GetIntegerSize(binr);
                DQ = binr.ReadBytes(elems);

                elems = GetIntegerSize(binr);
                IQ = binr.ReadBytes(elems);


                // ------- create RSACryptoServiceProvider instance and initialize with public key -----  
                CspParameters CspParameters = new CspParameters();
                CspParameters.Flags = CspProviderFlags.UseMachineKeyStore;
                RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(1024, CspParameters);
                RSAParameters RSAparams = new RSAParameters();
                RSAparams.Modulus = MODULUS;
                RSAparams.Exponent = E;
                RSAparams.D = D;
                RSAparams.P = P;
                RSAparams.Q = Q;
                RSAparams.DP = DP;
                RSAparams.DQ = DQ;
                RSAparams.InverseQ = IQ;
                RSA.ImportParameters(RSAparams);
                return RSA;
            }
            catch (Exception ex)
            {
                
                return null;
            }
            finally
            {
                binr.Close();
            }
        }

        private  int GetIntegerSize(BinaryReader binr)
        {
            byte bt = 0;
            byte lowbyte = 0x00;
            byte highbyte = 0x00;
            int count = 0;
            bt = binr.ReadByte();
            if (bt != 0x02)     //expect integer  
                return 0;
            bt = binr.ReadByte();

            if (bt == 0x81)
                count = binr.ReadByte();    // data size in next byte  
            else
                if (bt == 0x82)
                {
                    highbyte = binr.ReadByte(); // data size in next 2 bytes  
                    lowbyte = binr.ReadByte();
                    byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
                    count = BitConverter.ToInt32(modint, 0);
                }
                else
                {
                    count = bt;     // we already have the data size  
                }

            while (binr.ReadByte() == 0x00)
            {   //remove high order zeros in data  
                count -= 1;
            }
            binr.BaseStream.Seek(-1, SeekOrigin.Current);       //last ReadByte wasn't a removed zero, so back up a byte  
            return count;
        }  
    }
}

?

PHP签名:

1)从包含公私钥的pfx证书中取得.key私钥:于C#的证书一致

2)公钥生成:

F:\openssl-0.9.8k_WIN32\bin>openssl pkcs12 -in f:\certs\zhuo.pfx -out f:\certs\zhuo.pem

?

3)签名及验签:

/*
签名数据:
data:utf-8编码的订单原文,
privatekeyFile:私钥路径
passphrase:私钥密码
返回:base64转码的签名数据
*/
function sign($data, $privatekeyFile,$passphrase)
{ 
  $signature = '';
	$privatekey = openssl_pkey_get_private(file_get_contents($privatekeyFile), $passphrase);
  $res=openssl_get_privatekey($privatekey);
  openssl_sign($data, $signature, $res);
  openssl_free_key($res);  

  return base64_encode($signature);
}

/*
验证签名:
data:原文
signature:签名
publicKeyPath:公钥路径
返回:签名结果,true为验签成功,false为验签失败
*/
function verity($data, $signature, $publicKeyPath)
{
	$pubKey = file_get_contents('D:/certs/test.pem');
	$res = openssl_get_publickey($pubKey);
	$result = (bool)openssl_verify($data, base64_decode($signature), $res);
	openssl_free_key($res);

	return $result;
}

?* PHP需要注意版本和一些包的导入,如果有报错再google了~~

?

?

?

?

?

?

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn