三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

C#使用SHA256withRSA加密对接口进行访问

C#使用SHA256withRSA加密对接口进行访问

需求:接口改成SHA256withRSA加密访问

材料:自己电脑生成的RSA公钥和私钥(这里公钥提供给接口方配置,私钥我们留着自己用来加密。)

公钥私钥生成方式:

在自己电脑上使用openssl(类似cmd的界面,然后运行以下命令生成,生成后,你会在你【C:\Users\用户名】的路径下找到private_key.pem和public_key.pem这两个文件。

-public_key.pem提供给接口方,我们用private_key.pem进行加密(自留,不外传)。)

image

 

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

image

 

        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】没有勾选。(这里默认勾选的,我测试的时候不小心给去掉了。)

image

 

 

感谢: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

 

← 返回列表