如何将openSSL生成的RSA公钥加载到RSACryptoServiceProvider中?

[英]How to load RSA Public Key generated by openSSL into RSACryptoServiceProvider?


I am writing a .Net Class that reads a cookie from our central authentication server. It contains the UserId, some timestamps and a signature created by openssl_sign() using a 2048 Bit RSA key and a SHA1 Hash.

我正在编写一个从我们的中央身份验证服务器读取cookie的.Net类。它包含UserId,一些时间戳和openssl_sign()使用2048位RSA密钥和SHA1哈希创建的签名。

The current public key is provided in openssl PEM format on the server and changes on occasion. I cannot read the Key using .Net managed code alone (yet) and worked out the following procedure to get it working:

当前公钥在服务器上以openssl PEM格式提供,并且偶尔会更改。我无法单独使用.Net托管代码读取密钥(并且)并制定了以下过程以使其正常工作:

  • Extract Exponent and Modulus from the public key
  • 从公钥中提取指数和模数

  • Check key is still 2048 Bit
  • 检查键仍然是2048位

  • Store key length, exponent an modulus in Source, compile and deploy (Drop leading zeroes from the Modulus to make it work)
  • 存储密钥长度,在Source中指数模数,编译和部署(从模数中删除前导零以使其工作)

The Class then creates a new RSACryptoServiceProvider(2048) and feeds the public components using the RSAParameters structure into the CSP. Verification of the signature then succeeds.

然后,类创建一个新的RSACryptoServiceProvider(2048),并使用RSAParameters结构将公共组件提供给CSP。然后验证签名成功。

I would like to get this working without me creating, compiling and deploying a new Assembly each time the key changes. To make things interesting I would like to stick to managed code only (rules out most examples I found). Something that sounds perfect is the internal ASN.1 Reader when creating an instance of AsnEncodedData(oid, data) but the only oid I found that could match, RSA aka 1.2.840.113549.1.1.1, did not work and produced raw bytes only.

我想在没有我每次密钥更改时创建,编译和部署新程序集的情况下工作。为了让事情变得有趣,我想坚持使用托管代码(排除我发现的大多数示例)。听起来很完美的是内部ASN.1 Reader在创建AsnEncodedData(oid,data)的实例时,但我找到的唯一可以匹配的oid,RSA又名1.2.840.113549.1.1.1,不起作用,只产生原始字节。

Added: former public key

补充:以前的公钥

-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMW90O6C17fapbS35auKolsy7kI0FOE1
C08y5HqgZ0rMXoocV4nHSHYBm2HVx2QSR5OLQtERgWDmxOu+vwU1GXUCAwEAAQ==
-----END PUBLIC KEY-----

-----开始公共密钥----- MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMW90O6C17fapbS35auKolsy7kI0FOE1 C08y5HqgZ0rMXoocV4nHSHYBm2HVx2QSR5OLQtERgWDmxOu + vwU1GXUCAwEAAQ == ----- END PUBLIC KEY -----

I found pempublic.cs wich seems to solve this using (as it seems) sourcecode from openSSL. I will leave the question open to see if there are any other solutions.

我发现pempublic.cs似乎使用openSSL中的源代码来解决这个问题。我会打开问题,看看是否还有其他解决方案。

2 个解决方案

#1


2  

To load private key let's use this code:

要加载私钥,我们使用以下代码:

private RSACryptoServiceProvider GetPrivateKey(string privateKey)
    {
        byte[] privkey = Convert.FromBase64String(privateKey);
        byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;

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


            //------ all private key components are Integer sequences ----
            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 -----
            CspParameters CspParameters = new CspParameters();
            CspParameters.Flags = CspProviderFlags.UseMachineKeyStore;
            RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(1024, CspParameters);
            RSAParameters RSAparams = new RSAParameters();
            RSAparams.Modulus = MODULUS;
            RSAparams.Exponent = E;
            RSAparams.D = D;
            RSAparams.P = P;
            RSAparams.Q = Q;
            RSAparams.DP = DP;
            RSAparams.DQ = DQ;
            RSAparams.InverseQ = IQ;
            RSA.ImportParameters(RSAparams);
            return RSA;
        }
        catch (Exception ex)
        {
            return null;
        }
        finally
        {
            binr.Close();
        }
    }

To load public key let's use this code:

要加载公钥,我们使用以下代码:

private RSACryptoServiceProvider GetPublicKey(string publicKeyString)
    {
        // encoded OID sequence for  PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1"
        byte[] SeqOID = {0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00} ;
        byte[] x509key;
        byte[] seq = new byte[15];
        int x509size;

        x509key = Convert.FromBase64String(publicKeyString);
        x509size = x509key.Length;

        // ---------  Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob  ------
        MemoryStream mem = new MemoryStream(x509key);
        BinaryReader binr = new BinaryReader(mem);    //wrap Memory Stream with BinaryReader for easy reading
        byte bt = 0;
        ushort twobytes = 0;

        try
        {

            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;

            seq = binr.ReadBytes(15);       //read the Sequence OID
            if (!CompareBytearrays(seq, SeqOID))    //make sure Sequence for OID is correct
                return null;

            twobytes = binr.ReadUInt16();
            if (twobytes == 0x8103) //data read as little endian order (actual data order for Bit String is 03 81)
                binr.ReadByte();    //advance 1 byte
            else if (twobytes == 0x8203)
                binr.ReadInt16();   //advance 2 bytes
            else
                return null;

            bt = binr.ReadByte();
            if (bt != 0x00)     //expect null byte next
                return null;

            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();
            byte lowbyte = 0x00;
            byte highbyte = 0x00;

            if (twobytes == 0x8102) //data read as little endian order (actual data order for Integer is 02 81)
                lowbyte = binr.ReadByte();  // read next bytes which is bytes in modulus
            else if (twobytes == 0x8202)
            {
                highbyte = binr.ReadByte(); //advance 2 bytes
                lowbyte = binr.ReadByte();
            }
            else
                return null;
            byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };   //reverse byte order since asn.1 key uses big endian order
            int modsize = BitConverter.ToInt32(modint, 0);

            int firstbyte = binr.PeekChar();
            if (firstbyte == 0x00)
            {   //if first byte (highest order) of modulus is zero, don't include it
                binr.ReadByte();    //skip this null byte
                modsize -= 1;   //reduce modulus buffer size by 1
            }

            byte[] modulus = binr.ReadBytes(modsize);   //read the modulus bytes

            if (binr.ReadByte() != 0x02)            //expect an Integer for the exponent data
                return null;
            int expbytes = (int)binr.ReadByte();        // should only need one byte for actual exponent data (for all useful values)
            byte[] exponent = binr.ReadBytes(expbytes);

            // ------- create RSACryptoServiceProvider instance and initialize with public key -----
            RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
            RSAParameters RSAKeyInfo = new RSAParameters();
            RSAKeyInfo.Modulus = modulus;
            RSAKeyInfo.Exponent = exponent;
            RSA.ImportParameters(RSAKeyInfo);

            return RSA;
        }

        finally
        {
            binr.Close();
        }
    }

You can read the original post here to get more detail

您可以在此处阅读原始帖子以获取更多详细信息

#2


-1  

You have the private key, so it's probably easier to generate a self-signed certificate from the key. You can use System.Security.Cryptography.X509Certificates.X509Certificate (I think you should have the certificate in DER / ASN.1 format rather thant PEM) to load the certificate and X509Certificate.GetPublicKey() to get the public key.

您拥有私钥,因此从密钥生成自签名证书可能更容易。您可以使用System.Security.Cryptography.X509Certificates.X509Certificate(我认为您应该具有DER / ASN.1格式的证书而不是PEM)来加载证书和X509Certificate.GetPublicKey()以获取公钥。

智能推荐

注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:http://www.silva-art.net/blog/2011/05/11/a676f9d416ad6b98a83ca23bdbe5c653.html



 
© 2014-2019 ITdaan.com 粤ICP备14056181号  

赞助商广告