4

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?

2
  • 1
    xmlPrivateKey is not an XML string, so you can't use provider.FromXmlString. Commented Mar 4, 2016 at 9:27
  • You'd better show the encryption code. Commented Mar 4, 2016 at 10:44

1 Answer 1

5

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Can the same code (DecodeRsaPrivateKey) be used to build the RSACryptoServiceProvider needed to encrypt (OpenSSL) with public key?
In order to proceed from this to exporting to PFX with key, I had to set a csp KeyContainerName. Instead of new RSACryptoServiceProvder(), do new RSACryptoServiceProvider(new CspParameters() { KeyContainerName = Guid.NewGuid().ToString("B").ToUpper() }); The content of the name might not matter at all, but an uppercase bracketed GUID is what I see elsewhere, and now I can X509Certificate2.Export and keep the private key.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.