3

中央認証サーバーから Cookie を読み取る .Net クラスを作成しています。これには、UserId、いくつかのタイムスタンプ、および 2048 ビット RSA キーと SHA1 ハッシュを使用して openssl_sign() によって作成された署名が含まれています。

現在の公開鍵は、サーバー上で openssl PEM 形式で提供され、場合によって変更されます。.Net マネージ コードだけを使用して (まだ) キーを読み取ることができず、次の手順を実行して機能させました。

  • 公開鍵から指数とモジュラスを抽出する
  • チェックキーはまだ2048ビットです
  • キーの長さを格納し、ソースに係数を指数付けし、コンパイルして展開します (モジュラスから先頭のゼロを削除して機能させます)。

次に、クラスは を作成し、構造体を使用してパブリック コンポーネントを CSP にnew RSACryptoServiceProvider(2048)フィードします。RSAParametersその後、署名の検証は成功します。

キーが変更されるたびに新しいアセンブリを作成、コンパイル、および展開することなく、これを機能させたいと思います。興味深いものにするために、マネージド コードのみに固執したいと思います (私が見つけたほとんどの例を除外します)。完璧に聞こえるのは、インスタンスを作成するときの内部 ASN.1 Reader ですAsnEncodedData(oid, data)が、一致することがわかった唯一の oid、RSA 別名 1.2.840.113549.1.1.1 は機能せず、生のバイトのみを生成しました。

追加: 以前の公開鍵

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

openSSL のソースコードを使用してこれを解決しているように見える pempublic.cs を見つけまし。他の解決策があるかどうかを確認するために、質問を開いたままにします。

4

2 に答える 2

1

秘密鍵をロードするには、次のコードを使用しましょう。

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

公開鍵をロードするには、次のコードを使用しましょう。

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

ここで元の投稿を読んで詳細を確認できます

于 2014-11-15T16:35:50.367 に答える
-1

秘密鍵があるので、その鍵から自己署名証明書を生成する方がおそらく簡単です。証明書をロードして公開鍵を取得するにはSystem.Security.Cryptography.X509Certificates.X509Certificate、(PEM ではなく DER / ASN.1 形式の証明書が必要だと思います) を使用できます。X509Certificate.GetPublicKey()

于 2011-06-16T11:35:59.387 に答える