c# - 如何在 .NET 中解密 RSA 内容?

标签 c# encryption

我正在使用 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+/Nz/yp6my/EwY0I+KP1CX/QPY8TL3bFDvfJYJDJ50LHEPfiR/RGhHl9rvViXOgD4IiXYF2/KbNPQNmno+Bioi3r8Xc5+PVNyFDJy+X4/YjX4O830g9vAhyRJ1RKbJOmJYWT4sdP0jfxwaRL2+FAl6yIsrcsH/7bRZvjDTU=

在服务器端解密时,错误是:

Invalid grammar in line 1.

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

最佳答案

OpenSSL生成的RSA格式与.NET不同,需要转换OpenSSL RSA xmlPrivateKeyXML 格式,以便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可以解密原始上下文。

关于c# - 如何在 .NET 中解密 RSA 内容?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35787504/

相关文章:

c# - 了解使用 Windows native WPF 客户端进行 ADFS 登录

c# - Mediatr 行为管道中的验证

c# - 使用 lambda 聚合匿名类型

encryption - 使用初始 key 生成公钥/私钥对

c# - 退出递归函数搜索子目录

c# - 绑定(bind)到静态类属性

java - 密码函数 : WRONG FINAL BLOCK LENGTH Android Studio

java - 如何在 Android 上安全地存储存储敏感日期?

java - 使用 RC4 算法逐行加密后解密仅产生一行正确的行

c++ - 用 C++ 解密文件,用 openssl -aes-128-cbc 加密