如何解密 .NET 中的 RSA 内容?

Posted

技术标签:

【中文标题】如何解密 .NET 中的 RSA 内容?【英文标题】:How to decrypt RSA content in .NET? 【发布时间】:2016-03-04 03:36:58 【问题描述】:

我正在使用 OpenSSL 生成 RSA 私钥和公钥,将公钥发送到 html 页面以加密用户名和密码(使用 JSEncrypt)。加密的内容发送到服务器以使用私钥解密。

这是我的解密函数:

public string RsaDecrypt(string xmlPrivateKey, string mStrDecryptString)

    string str2;
    try
    
        RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
        provider.FromXmlString(xmlPrivateKey);
        byte[] rgb = Convert.FromBase64String(mStrDecryptString);
        byte[] buffer2 = provider.Decrypt(rgb, false);
        str2 = new UnicodeEncoding().GetString(buffer2);
    
    catch (Exception exception)
    
        throw exception;
    
    
    return str2;

xmlPrivateKey 值为:

MIICWwIBAAKBgQCt8y + vx9Y3Iik9l / 8r6x + wjcrgPskbjVpt7fSJqtpCA / XaYl / 3O2uvrRUPzyqr1wA + ejsdhdm285nYSbSaHTPem1 + N / JHynp + cLQiBV6a8PayOvtrSBaHLZDDhgvntk / BLeplU406kiMltnVDko33H + Y3yaNuY2TNDEMe5Z8OlUQIDAQABAoGAdYIChMyKeVQqZ + F2D0UWcz5V / oZrdKFYpUpKF3XDWzUxsAUkru8FH / fccoGQYeUr1QjdRmRVXrHRC7s + tZ1km68oiUFD6sbCYyPQy0Se95050FncM3lEndGUJTiTelVqAYh + DPVnRURcfgA + HSvWek1 / YnOZ8UNZJ36jiogSKcECQQDbRfn / UODXud7MKO7zfYOLvPhtFMgtA0Ac5w6tTJ / llZs0QtjMKCNHF9bGRxKdFvKTMA1DGBNN0chdWAc7UET / AkEAyxXUJAk1 + 46fRhzTH4uXRX7SEMCwEjY79DHqE23pPx8Q8VC3j2aPETQerT4EHNzaMBg6hneJE2p7xB5Rm / SFrwJAIWasaT7psRLIJHNLyt1gr2WOthcHUwv + tShhLPbSGIfMh45zNc4baZXxCm0DIdjABLm6G3FMZ3tAOS / Ski9tAwJAMYWQJn1sgXwk0KcEwIN8jsC / HsCt7rL06bYmOzipEPBVZFLnf / tlVa + c72fY / UTH + 8RcuR96 + JYVuhwekGYPFwJAQXbsOkyVTvZGcqRk9 + SF7AUsGcHYPrImH6iafYEBsVCOrMJfjEai0zmd / 9A1j + NHFq31KPAQGV0zHmV2NXscDg ==

mStrDecryptString 是:

fW9H + /新西兰/ yp6my / EwY0I + KP1CX / QPY8TL3bFDvfJYJDJ50LHEPfiR / RGhHl9rvViXOgD4IiXYF2 / KbNPQNmno + Bioi3r8Xc5 + PVNyFDJy + X4 / YjX4O830g9vAhyRJ1RKbJOmJYWT4sdP0jfxwaRL2 + FAl6yIsrcsH / 7bRZvjDTU = P>

在服务器端解密时,报错:

第 1 行中的语法无效

我该怎么做才能使它正确?

【问题讨论】:

xmlPrivateKey 不是 XML 字符串,所以不能使用 provider.FromXmlString 你最好显示加密代码。 【参考方案1】:

OpenSSL 生成的 RSA 格式与 .NET 不同,需要将 OpenSSL RSA xmlPrivateKey 转换为 XML 格式,以便RSACryptoServiceProvider 能够识别。

private static RSACryptoServiceProvider DecodeRsaPrivateKey(string priKey)

    var privkey = Convert.FromBase64String(priKey);
    byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;

    // ---------  Set up stream to decode the asn.1 encoded RSA private key  ------
    var mem = new MemoryStream(privkey);
    var binr = new BinaryReader(mem);   // wrap Memory Stream with BinaryReader for easy reading
    try
    
        var 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;
            
        var bt = binr.ReadByte();
        if (bt != 0x00)
            return null;

        //------  all private key components are Integer sequences ----
        var 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 -----
        var rsa = new RSACryptoServiceProvider();
        var rsAparams = new RSAParameters
        
            Modulus = MODULUS,
            Exponent = E,
            D = D,
            P = P,
            Q = Q,
            DP = DP,
            DQ = DQ,
            InverseQ = IQ
        ;
        rsa.ImportParameters(rsAparams);
        
        return rsa;
    
    catch (Exception e)
    
        LogHelper.Logger.Error("DecodeRsaPrivateKey failed", e);
        return null;
    
    finally
    
        binr.Close();
    



private static int GetIntegerSize(BinaryReader binary)

    byte binaryReadByte = 0;
    var count = 0;
    
    binaryReadByte = binary.ReadByte();
    if (binaryReadByte != 0x02)      // expect integer
        return 0;
        
    binaryReadByte = binary.ReadByte();
    if (binaryReadByte == 0x81)
    
        count = binary.ReadByte();   // data size in next byte
    
    else
    
        if (binaryReadByte == 0x82)
        
            var highbyte = binary.ReadByte();
            var lowbyte = binary.ReadByte();
            byte[] modint =  lowbyte, highbyte, 0x00, 0x00 ;
            count = BitConverter.ToInt32(modint, 0);
        
        else
        
            count = binaryReadByte; // we already have the data size
        
    
    
    while (binary.ReadByte() == 0x00)
        //remove high order zeros in data
        count -= 1;
    
    binary.BaseStream.Seek(-1, SeekOrigin.Current);   // last ReadByte wasn't a removed zero, so back up a byte
    
    return count;

所以RSACryptoServiceProvider 可以解密原始上下文。

【讨论】:

能否使用相同的代码 (DecodeRsaPrivateKey) 构建使用公钥加密 (OpenSSL) 所需的 RSACryptoServiceProvider? 为了继续使用密钥导出到 PFX,我必须设置一个 csp KeyContainerName。代替 new RSACryptoServiceProvder(),执行 new RSACryptoServiceProvider(new CspParameters() KeyContainerName = Guid.NewGuid().ToString("B").ToUpper() );名称的内容可能根本不重要,但大写括号 GUID 是我在其他地方看到的,现在我可以 X509Certificate2.Export 并保留私钥。

以上是关于如何解密 .NET 中的 RSA 内容?的主要内容,如果未能解决你的问题,请参考以下文章

.NET 中的 RSA 加密/解密问题

.NET Core加解密实战系列之——RSA非对称加密算法

在.NET中实现RSA公钥/私钥解密到Java/Spring

使用 RSA/ECB/OAEPWithSHA-256AndMGF1Padding 的 Java 加密无法在 .NET 中解密

使用预先存在的 RSA SSH 密钥解密 C# 中的文本

java 中的Cipher类RSA方式能不能用私钥加密公钥解密,完整解释下