php openssl_sign 对应 C#版 RSA签名
RSA Key Converter 在线转换工具:https://superdry.apphb.com/tools/online-rsa-key-converter
PHP 代码:
/ rsa 私钥复制到这里
$private_key = <<<EOD
PASTE YOUR RSA PRIVATE KEY IN HERE
EOD;
// 空着即可,不需要赋值
$binary_signature = "";
$algo = "SHA256";
openssl_sign($data, $binary_signature, $private_key, $algo);
// 最终生成的 signature
$signature = base64_encode($binary_signature)
C# 代码实现:
using System; using System.Text; using System.Security.Cryptography; using System.Web; using System.IO; using System.Security.Cryptography.X509Certificates; namespace User2MC { public class RSA { #region RSAWithSHA256 /// <summary> /// RSAWithSHA256 签名 /// </summary> /// <param name="data">数据</param> /// <returns>密文</returns> public static string Sign(string data) { //转换成适用于.Net的秘钥 var netKey = "<RSAKeyValue><Modulus>7XdZSrF+spbABFhYuxP7rfJKycvT0O7BmCoSJvU7yHWYqucc8msPDTi8ymdZOPOjHj2BuLUrqGsUm8Ljy8FVM2Bb51GaO2lgiBip9elFkzOJ8XP/ncHHvm4XCq5S201ovJefNC0xOxsXJU4fM+4B6ufYr4WqBmyuxTcZVHweE0k=</Modulus><Exponent>AQAB</Exponent><P>9ryI0kxJL9PupO9NEeWuCUo4xcl9x/M9+mtkfY3VoDDDV1E/eUjmoTfANYwrjcddiQrO0MLyEdootiLpN77qOw==</P><Q>9mG2//6moxVOsvFadUotnhlVM8+AlBCQV2FbBiXPugrMHdVtBG3+MsVdTII3Z4I/uuCWtedrPsBgF+0XRqMcSw==</Q><DP>wzX5HkFC6jdIKXA3TsCkSC9T6ZB4FplpYNZUxE1SRhIuisf6ay/1YHomdXc4Ak1IwKMva9XBBcTPzwKh9/vxfw==</DP><DQ>zsTCp6Q2hLblDRewKq7OCdiIwKpr5dbgy/RQR6CD7EYTdxYeH5GPu1wXKJY/mQaeJV9GG/LS9h7MhkfbONS6cQ==</DQ><InverseQ>dBEb5vloBDLcSQFDQO/VZ9SKFHCmHLXluhhIizYKGzgf3OXEGNDSAC3qy+ZTnLd3N5iYrVbK52UoiLOLhhNMqA==</InverseQ><D>iBOTTHUn6EjwoczKk/GgkI4+gyLVL24R7BN3sXFoH7gbkxu6/8OPrYDs1oOgoj0jJSoT0vemm+04swVcKh+QpTSniPswQl1n4KNW+B7G2RZrzSeP9RmIzWg4vpgfAfhm0+1j6kUJMrWt2ff7TvSoEH22dWe1s3+OrQt3t/S3tQ0=</D></RSAKeyValue>"; //RSAPrivateKeyJava2DotNet(privateKey); var rsa = new RSACryptoServiceProvider(); rsa.FromXmlString(netKey); //创建一个空对象 var rsaClear = new RSACryptoServiceProvider(); var paras = rsa.ExportParameters(true); rsaClear.ImportParameters(paras); //签名返回 using (var sha256 = new SHA256CryptoServiceProvider()) { var signData = rsa.SignData(Encoding.UTF8.GetBytes(data), sha256); return Convert.ToBase64String(signData); } } #endregion #region RSAWithSHA256 /// <summary> /// RSAWithSHA256 签名 /// </summary> /// <param name="data">数据</param> /// <param name="privateKeyPath">私钥文件路径</param> /// <returns>密文</returns> public static string Sign(string data, string privateKeyPath) { // using (RSACryptoServiceProvider rsa = opensslkey.DecodePrivateKeyInfo(merchantPrivateKey)) RSACryptoServiceProvider rsaCsp = LoadCertificateFile(privateKeyPath); byte[] dataBytes = Encoding.Default.GetBytes(data); byte[] signatureBytes = rsaCsp.SignData(dataBytes, "SHA256"); return Convert.ToBase64String(signatureBytes); } /// <summary> /// RSAWithSHA256 签名 /// </summary> /// <param name="data">数据</param> /// <param name="privateKey">私钥字符串(参数privateKey是Pem私钥文件中去除头(-----BEGIN RSA PRIVATE KEY-----)和尾(-----END RSA PRIVATE KEY-----)以及换行符后的字符串)</param> /// <returns>密文</returns> public static string SignByKey(string data, string privateKey) { using (RSACryptoServiceProvider rsaCsp = DecodeRSAPrivateKey(Convert.FromBase64String(privateKey))) { byte[] dataBytes = Encoding.Default.GetBytes(data); byte[] signatureBytes = rsaCsp.SignData(dataBytes, "SHA256"); return Convert.ToBase64String(signatureBytes); } } private static byte[] GetPem(string type, byte[] data) { string pem = Encoding.UTF8.GetString(data); string header = String.Format("-----BEGIN {0}-----\\n", 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 static RSACryptoServiceProvider LoadCertificateFile(string filename) { using (FileStream fs = 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 static 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 static 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; } #endregion } }