RSA加密及其在C#中的使用

本文介绍了在Java和C#之间如何进行RSA公私钥的转换,以适应不同平台的加密和解密需求。通过BouncyCastle库,实现了Java格式的公私钥到C#支持的XML格式的转换,并提供了相应的转换方法。同时,展示了C#中使用RSA进行加解密的接口和测试示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

RSA算法简介

笔者使用场景

Java作为服务端生成一对公私钥,C#作为客户端拥有公钥。
C#使用公钥对上行byte[]类型数据进行加密,服务端Java使用私钥解密。

规范

  • 公私钥都是base64字符串

过程

1,Java服务端开发人员给到客户端这边公、私钥(之所以给了私钥是方便客户端这边自己来测试)

2,C#客户端这边发现Java给到的公私钥,客户端这边并不能直接用。C#支持的公私钥格式有点类似XML格式。

比如Java公钥,其在C#中对应的格式如下:

    public string java_publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCv2NbWPuQwPegAcydw3+xO3GOCKMMyUme9bUuEEmds4CogvasV1f2savwiXA5mKqawoxDjbsjUgdgPHQbmlrhpNBBMa83Us9w5xjgl5tZFyDusnO/r8IQa9pGW7NAJ6xJX5vYbv4rZWon1D8/N7l/ybsR6nZTt+rEcL1V78POXIwIDAQAB";

    public string csharp_publicKey = "<RSAKeyValue><Modulus>r9jW1j7kMD3oAHMncN/sTtxjgijDMlJnvW1LhBJnbOAqIL2rFdX9rGr8IlwOZiqmsKMQ427I1IHYDx0G5pa4aTQQTGvN1LPcOcY4JebWRcg7rJzv6/CEGvaRluzQCesSV+b2G7+K2VqJ9Q/Pze5f8m7Eep2U7fqxHC9Ve/DzlyM=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";

可见二者不仅仅是加了几个XML标签那么简单,内容也发生了变化,因此需要提供工具把Java公钥转换为C#支持的格式。

3,C#控制台应用实现把Java公私钥转换为C#支持的格式
笔者使用BouncyCastle.Cryptography库,可以使用NuGet安装。实现了C#和Java的公私钥格式互转。
核心代码

using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using System;
using System.Xml;
using System.Security.Cryptography;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.X509;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Pkcs;

namespace RSA_Java2CSharp
{
    /// <summary>  
    /// RSA密钥格式转换  
    /// </summary>  
    public class RSAKeyConvert
    {
        /// <summary>  
        /// RSA私钥格式转换,java->.net  
        /// </summary>  
        /// <param name="privateKey">java生成的RSA私钥</param>  
        /// <returns></returns>  
        public static string RSAPrivateKeyJava2DotNet(string privateKey)
        {
            var data = Convert.FromBase64String(privateKey);
            RsaPrivateCrtKeyParameters privateKeyParam = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKey));

            return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent><P>{2}</P><Q>{3}</Q><DP>{4}</DP><DQ>{5}</DQ><InverseQ>{6}</InverseQ><D>{7}</D></RSAKeyValue>",
                Convert.ToBase64String(privateKeyParam.Modulus.ToByteArrayUnsigned()),
                Convert.ToBase64String(privateKeyParam.PublicExponent.ToByteArrayUnsigned()),
                Convert.ToBase64String(privateKeyParam.P.ToByteArrayUnsigned()),
                Convert.ToBase64String(privateKeyParam.Q.ToByteArrayUnsigned()),
                Convert.ToBase64String(privateKeyParam.DP.ToByteArrayUnsigned()),
                Convert.ToBase64String(privateKeyParam.DQ.ToByteArrayUnsigned()),
                Convert.ToBase64String(privateKeyParam.QInv.ToByteArrayUnsigned()),
                Convert.ToBase64String(privateKeyParam.Exponent.ToByteArrayUnsigned()));
        }

        /// <summary>  
        /// RSA私钥格式转换,.net->java  
        /// </summary>  
        /// <param name="privateKey">.net生成的私钥</param>  
        /// <returns></returns>  
        public static string RSAPrivateKeyDotNet2Java(string privateKey)
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(privateKey);
            BigInteger m = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Modulus")[0].InnerText));
            BigInteger exp = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Exponent")[0].InnerText));
            BigInteger d = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("D")[0].InnerText));
            BigInteger p = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("P")[0].InnerText));
            BigInteger q = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Q")[0].InnerText));
            BigInteger dp = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("DP")[0].InnerText));
            BigInteger dq = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("DQ")[0].InnerText));
            BigInteger qinv = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("InverseQ")[0].InnerText));

            RsaPrivateCrtKeyParameters privateKeyParam = new RsaPrivateCrtKeyParameters(m, exp, d, p, q, dp, dq, qinv);

            PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateKeyParam);
            byte[] serializedPrivateBytes = privateKeyInfo.ToAsn1Object().GetEncoded();
            return Convert.ToBase64String(serializedPrivateBytes);
        }

        /// <summary>  
        /// RSA公钥格式转换,java->.net  
        /// </summary>  
        /// <param name="publicKey">java生成的公钥</param>  
        /// <returns></returns>  
        public static string RSAPublicKeyJava2DotNet(string publicKey)
        {
            RsaKeyParameters publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(publicKey));
            return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent></RSAKeyValue>",
                Convert.ToBase64String(publicKeyParam.Modulus.ToByteArrayUnsigned()),
                Convert.ToBase64String(publicKeyParam.Exponent.ToByteArrayUnsigned()));
        }

        /// <summary>  
        /// RSA公钥格式转换,.net->java  
        /// </summary>  
        /// <param name="publicKey">.net生成的公钥</param>  
        /// <returns></returns>  
        public static string RSAPublicKeyDotNet2Java(string publicKey)
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(publicKey);
            BigInteger m = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Modulus")[0].InnerText));
            BigInteger p = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Exponent")[0].InnerText));
            RsaKeyParameters pub = new RsaKeyParameters(false, m, p);

            SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pub);
            byte[] serializedPublicBytes = publicKeyInfo.ToAsn1Object().GetDerEncoded();
            return Convert.ToBase64String(serializedPublicBytes);
        }

    }
}

4,测试

CSharp加解密接口

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Security.Cryptography;


namespace RSA_Java2CSharp
{
    public class UEncrypt
    {
        /// <summary>
        /// 生成RSA私钥 公钥
        /// </summary>
        /// <param name="privateKey"></param>
        /// <param name="publicKey"></param>
        public static void RSAGenerateKey(ref string privateKey, ref string publicKey)
        {
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            privateKey = rsa.ToXmlString(true);
            publicKey = rsa.ToXmlString(false);
        }

        /// <summary>
        /// 用RSA公钥 加密
        /// </summary>
        /// <param name="data"></param>
        /// <param name="publicKey"></param>
        /// <returns></returns>
        public static byte[] RSAEncrypt(byte[] data, string publicKey)
        {
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            rsa.FromXmlString(publicKey);
            byte[] encryptData = rsa.Encrypt(data, false);
            return encryptData;
        }

        /// <summary>
        /// 用RSA私钥 解密
        /// </summary>
        /// <param name="data"></param>
        /// <param name="privateKey"></param>
        /// <returns></returns>
        public static byte[] RSADecrypt(byte[] data, string privateKey)
        {
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            rsa.FromXmlString(privateKey);
            byte[] decryptData = rsa.Decrypt(data, false);
            return decryptData;
        }
    }

}

测试

using RSA_Java2CSharp;
//java侧生成的RSA公钥 base64编码
string java_pubkey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCv2NbWPuQwPegAcydw3+xO3GOCKMMyUme9bUuEEmds4CogvasV1f2savwiXA5mKqawoxDjbsjUgdgPHQbmlrhpNBBMa83Us9w5xjgl5tZFyDusnO/r8IQa9pGW7NAJ6xJX5vYbv4rZWon1D8/N7l/ybsR6nZTt+rEcL1V78POXIwIDAQAB";

//java侧生成的RSA私钥 base64编码
string java_prikey = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAK/Y1tY+5DA96ABzJ3Df7E7cY4IowzJSZ71tS4QSZ2zgKiC9qxXV/axq/CJcDmYqprCjEONuyNSB2A8dBuaWuGk0EExrzdSz3DnGOCXm1kXIO6yc7+vwhBr2kZbs0AnrElfm9hu/itlaifUPz83uX/JuxHqdlO36sRwvVXvw85cjAgMBAAECgYAL/8fpJrF7eT3ziegPE7iUSQWhRBbNwEHD80lL4dWc4E7/nPGns8pzkXlS/uUco5xsQTRN0Klzlsiff2ORKIe8yLxPlq8CjK2+LmS08lUwFa3EFEXaZ2EC3yj/YS28I+MosqVk/TjnVJGOXURt8JWGNpnuG4KpsdpSBv6eXQcPQQJBAPdnMCh/fiq2jwZOYYKnIAQ1TTfrFP62wyhs4dPdBIoIO8RtPsXYV/DCAAfYp+QmwxRvfNWdXBM7tAqEaUZxuEcCQQC19R0B5do3nQfv1Wz50KtTfVd+GJuRb1UMNFyWI0KnJch0KSuYRbVOte3FZrUYOMu9PkgeBQLDDMUI2Bfz7bRFAkEAq2l8LWMAKFnqSIU//EUM4r2Hbcnb9wrrtnOSF7dXcMd5mYPTbUKS04Wmfck3sdTFbsA77skjRVQlTvAk/KDH+wJBAKzdX1+MNRKctwudIdj766h37gU376Ptt0jO/h8NBKezd4sUCfyyTRuoL2pYtzd5zeXOI8mRTRxtJ0vNsIPnklkCQQCs+JyzCxH6fFDAw6dg3oKLrBYS9tgsBzedzQDEzkISy5eXOIqcMaZOcfDERkoWX5rQfvQcY7LoluUmSi8xTrhP";


string csharp_pubKey = RSAKeyConvert.RSAPublicKeyJava2DotNet(java_pubkey);
Console.WriteLine("csharp_pubkey:" + csharp_pubKey);
string csharp_prikey = RSAKeyConvert.RSAPrivateKeyJava2DotNet(java_prikey);
Console.WriteLine("csharp_prikey:" + csharp_prikey);


string msg = "123666666哪里(=@__@=)hehe"; ;
byte[] msgCrypted = UEncrypt.RSAEncrypt(System.Text.Encoding.Default.GetBytes(msg), csharp_pubKey);

byte[] msgDecrypted = UEncrypt.RSADecrypt(msgCrypted, csharp_prikey);
string result = System.Text.Encoding.Default.GetString(msgDecrypted);

Console.WriteLine(result); 
Console.ReadLine();

扩展阅读

C#实现RSA加密解密

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

iningwei

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值