需求:接口改成SHA256withRSA加密访问
材料:自己电脑生成的RSA公钥和私钥(这里公钥提供给接口方配置,私钥我们留着自己用来加密。)
公钥私钥生成方式:
在自己电脑上使用openssl(类似cmd的界面,然后运行以下命令生成,生成后,你会在你【C:\Users\用户名】的路径下找到private_key.pem和public_key.pem这两个文件。
-public_key.pem提供给接口方,我们用private_key.pem进行加密(自留,不外传)。)

openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048openssl rsa -pubout -in private_key.pem -out public_key.pem
代码:
这里引用Portable.BouncyCastle

private void button1_Click(object sender, EventArgs e){#regionstring publicKeyPath = @"C:\Users\T709\1\public_key.pem";string privateKeyPath = @"C:\Users\T709\1\private_key.pem";//生成32位随机字符串var requestNonceId = "";var requestDate = "";Guid newG = Guid.NewGuid();requestNonceId = newG.ToString().Replace("-", "");// 获取当前时间的Unix时间戳DateTime now = DateTime.UtcNow;TimeSpan span = now - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);long unixTimestamp = (long)span.TotalMilliseconds;requestDate = unixTimestamp.ToString();string requestUrl = "/api/auth/sign/v1";string signStr = requestNonceId + requestDate + requestUrl;#endregionstring privateKey = LoadPrivateContent(privateKeyPath);//SHA256withRSA//SHA-256withRSAvar s = RSASignJavaBouncyCastle(signStr, privateKey, "SHA256withRSA");var s2 = EncryptPrivateKeyJava(privateKey, signStr);}#region/// <summary> /// 基于BouncyCastle的RSA私钥加密 /// </summary> /// <param name="privateKeyJava"></param> /// <param name="data"></param> /// <returns></returns> public static string EncryptPrivateKeyJava(string privateKeyJava, string data, string encoding = "UTF-8") { RsaKeyParameters privateKeyParam = (RsaKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKeyJava)); byte[] cipherbytes = Encoding.GetEncoding(encoding).GetBytes(data); RsaEngine rsa = new RsaEngine(); rsa.Init(true, privateKeyParam);//参数true表示加密/false表示解密。 cipherbytes = rsa.ProcessBlock(cipherbytes, 0, cipherbytes.Length); return Convert.ToBase64String(cipherbytes); } #region 公钥解密 /// <summary> /// 基于BouncyCastle的RSA公钥解密 /// </summary> /// <param name="publicKeyJava"></param> /// <param name="data"></param> /// <param name="encoding"></param> /// <returns></returns> public static string DecryptPublicKeyJava(string publicKeyJava, string data, string encoding = "UTF-8") { RsaKeyParameters publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(publicKeyJava)); byte[] cipherbytes = Convert.FromBase64String(data); RsaEngine rsa = new RsaEngine(); rsa.Init(false, publicKeyParam);//参数true表示加密/false表示解密。 cipherbytes = rsa.ProcessBlock(cipherbytes, 0, cipherbytes.Length); return Encoding.GetEncoding(encoding).GetString(cipherbytes); } #endregion #region 加签 /// <summary> /// 基于BouncyCastle的RSA签名 /// </summary> /// <param name="data"></param> /// <param name="privateKeyJava"></param> /// <param name="hashAlgorithm">JAVA的和.NET的不一样,如:MD5(.NET)等同于MD5withRSA(JAVA)</param> /// <param name="encoding"></param> /// <returns></returns> public static string RSASignJavaBouncyCastle(string data, string privateKeyJava, string hashAlgorithm = "MD5withRSA", string encoding = "UTF-8") { RsaKeyParameters privateKeyParam = (RsaKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKeyJava)); ISigner signer = SignerUtilities.GetSigner(hashAlgorithm); signer.Init(true, privateKeyParam);//参数为true验签,参数为false加签 var dataByte = Encoding.GetEncoding(encoding).GetBytes(data); signer.BlockUpdate(dataByte, 0, dataByte.Length); //return Encoding.GetEncoding(encoding).GetString(signer.GenerateSignature()); //签名结果 非Base64String return Convert.ToBase64String(signer.GenerateSignature()); } #endregion #region 验签 /// <summary> /// 基于BouncyCastle的RSA签名 /// </summary> /// <param name="data">源数据</param> /// <param name="publicKeyJava"></param> /// <param name="signature">base64签名</param> /// <param name="hashAlgorithm">JAVA的和.NET的不一样,如:MD5(.NET)等同于MD5withRSA(JAVA)</param> /// <param name="encoding"></param> /// <returns></returns> public static bool VerifyJavaBouncyCastle(string data, string publicKeyJava, string signature, string hashAlgorithm = "MD5withRSA", string encoding = "UTF-8") { RsaKeyParameters publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(publicKeyJava)); ISigner signer = SignerUtilities.GetSigner(hashAlgorithm); signer.Init(false, publicKeyParam); byte[] dataByte = Encoding.GetEncoding(encoding).GetBytes(data); signer.BlockUpdate(dataByte, 0, dataByte.Length); //byte[] signatureByte = Encoding.GetEncoding(encoding).GetBytes(signature);// 非Base64String byte[] signatureByte = Convert.FromBase64String(signature); return signer.VerifySignature(signatureByte); }#endregion#endregionpublic static string LoadPrivateContent(string pemPath){string content = File.ReadAllText(pemPath);// 精确移除PEM头尾和所有空白字符content = content.Replace("-----BEGIN PUBLIC KEY-----", "").Replace("-----END PUBLIC KEY-----", "").Replace("-----BEGIN PRIVATE KEY-----", "").Replace("-----END PRIVATE KEY-----", "").Replace("-----BEGIN RSA PRIVATE KEY-----", "").Replace("-----END RSA PRIVATE KEY-----", "").Replace("\r", "").Replace("\n", "");//.Replace("\\s", ""); // 移除所有空白字符,包括换行、空格、制表符return content;}
注:
这里我代码自行解析正常,但是Java接口方调用老是显示签名验证错误。
可能的原因:对方配置的不是你提供的公钥。(我这个就是碰到)
另一个就是我用的PostMan中,【Content-Type】、【Content-Length】和【Host】没有勾选。(这里默认勾选的,我测试的时候不小心给去掉了。)

感谢:https://www.cnblogs.com/ggll611928/p/18028968
https://blog.csdn.net/zxy13826134783/article/details/126447948
https://www.cnblogs.com/Alex80/p/11526634.html
https://www.cnblogs.com/kevin860/p/9557859.html
https://www.cnblogs.com/dj258/p/18261075
