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:2048

openssl rsa -pubout -in private_key.pem -out public_key.pem

 

代码:

这里引用Portable.BouncyCastle

image

 

        private void button1_Click(object sender, EventArgs e)
        {
            #region

            string 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;

            #endregion

            string privateKey = LoadPrivateContent(privateKeyPath);

            //SHA256withRSA
            //SHA-256withRSA
            var 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


        #endregion

        public 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

 

posted @ 2026-05-07 11:43  蜗牛的礼物  阅读(19)  评论(0)    收藏  举报