这个功能网上搜了好多资料。贡献一下,转载须注明并对卓二妹的无私奉献表示感谢。
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)公钥生成:
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了~~