Dolphin
Dolphin

Reputation: 38985

How to decrypt RSA content in .NET?

I am generating RSA private & public keys using OpenSSL, sending public key into HTML page to encrypt username & password (with JSEncrypt).The encrypted content sends to server to decrypt using private key.

This is my decrypt function:

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

The xmlPrivateKey value is:

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==


The mStrDecryptString is:

fW9H+/Nz/yp6my/EwY0I+KP1CX/QPY8TL3bFDvfJYJDJ50LHEPfiR/RGhHl9rvViXOgD4IiXYF2/KbNPQNmno+Bioi3r8Xc5+PVNyFDJy+X4/YjX4O830g9vAhyRJ1RKbJOmJYWT4sdP0jfxwaRL2+FAl6yIsrcsH/7bRZvjDTU=

When decrypting at server side, the error is:

Invalid grammar in line 1.

How could I do to make it right?

Upvotes: 4

Views: 2498

Answers (1)

Dolphin
Dolphin

Reputation: 38985

The RSA format generated by OpenSSL is different with .NET, you should convert OpenSSL RSA xmlPrivateKey to XML format so it could be recognized by 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;
}

So the RSACryptoServiceProvider can decrypt the original context.

Upvotes: 5

Related Questions