Как загрузить открытый ключ RSA из файла на C #

Мне нужно загрузить следующий открытый ключ RSA из файла для использования с классом RSACryptoServiceProvider. Как я могу это сделать?

-----BEGIN PUBLIC KEY-----
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/syEKqEkMtQL0+d
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+izR
KbGMRtur2TYklnyVkjeeHfAggo8vWQmWesnOG55vQYHbOOFoJbk0EkwEr5R/PbKm
byXPPN8zwnS5/XXXXXXXXXXXX
-----END PUBLIC KEY-----

Этот код работает с моим ключом публикации: http://www.jensign.com/opensslkey/

Вот код, который я использую

        static string RSA(string input)
        {
            RSACryptoServiceProvider rsa = DecodeX509PublicKey(Convert.FromBase64String(GetKey()));

            return (Convert.ToBase64String(rsa.Encrypt(Encoding.ASCII.GetBytes(input), false)));
        }

        static string GetKey()
        {
            return File.ReadAllText("master.pub").Replace("-----BEGIN PUBLIC KEY-----", "").Replace("-----END PUBLIC KEY-----", "");
            //.Replace("\n", "");
        }

        private static bool CompareBytearrays(byte[] a, byte[] b)
        {
            if (a.Length != b.Length)
                return false;
            int i = 0;
            foreach (byte c in a)
            {
                if (c != b[i])
                    return false;
                i++;
            }
            return true;
        }

        public static RSACryptoServiceProvider DecodeX509PublicKey(byte[] x509key)
        {
            // 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[] seq = new byte[15];
            // ---------  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);

                byte firstbyte = binr.ReadByte();
                binr.BaseStream.Seek(-1, SeekOrigin.Current);

                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;
            }
            catch (Exception)
            {
                return null;
            }

            finally { binr.Close(); }

        }

Просто вызовите метод RSA с текстом, который вы хотите зашифровать, и все готово.


person Umar Jamil    schedule 16.07.2012    source источник
comment
Используя IO.StreamReader?   -  person Mr47    schedule 16.07.2012
comment
возможное дублирование? stackoverflow.com/questions/243646/   -  person Phil    schedule 16.07.2012
comment
Я попытался преобразовать строку в байты с помощью Convert.FromBase64String, а затем передать байты в конструктор RSACryptoServiceProvider, но он выдает исключение. То же самое происходит с X509Certificate.CreateFromFile   -  person Umar Jamil    schedule 16.07.2012
comment
Возможно, вы можете сначала попробовать протестировать свой код с помощью известного действительного файла открытого ключа, а затем протестировать его с указанным выше ключом.   -  person Mike Atlas    schedule 16.07.2012
comment
Сейчас я использую следующий код: jensign.com/opensslkey, похоже, работает ...   -  person Umar Jamil    schedule 16.07.2012


Ответы (4)


Вы можете создать RSACryptoServiceProvider из файла PEM, используя следующий класс (метод GetRSAProviderFromPemFile).

Предупреждение. Не копируйте код из StackOverflow без проверки! Тем более криптокод! В этом коде есть ошибки (см. Комментарии). Вы можете написать и запустить тесты, прежде чем использовать это в производстве (если у вас действительно нет лучшего варианта). Я отказываюсь редактировать код, чтобы исправить это, поскольку он был бы так же ненадежен, как и раньше, без тестов и активный сопровождающий.

Источник: Похоже, этот код взят с opensslkey этого сайта. Авторское право (c) 2000 JavaScience Consulting, Мишель Галлан. Исходный пакет был выпущен под лицензией типа BSD, поэтому, вероятно, его можно использовать (но вы можете дважды проверить). Существует также пакет NuGet того же автора.

Вот скопированный исходный код, изначально отправленный в этот ответ:

RSACryptoServiceProvider provider = PemKeyUtils.GetRSAProviderFromPemFile(  @"public_key.pem" );


public class PemKeyUtils
{
    const String pemprivheader = "-----BEGIN RSA PRIVATE KEY-----";
    const String pemprivfooter = "-----END RSA PRIVATE KEY-----";
    const String pempubheader = "-----BEGIN PUBLIC KEY-----";
    const String pempubfooter = "-----END PUBLIC KEY-----";
    const String pemp8header = "-----BEGIN PRIVATE KEY-----";
    const String pemp8footer = "-----END PRIVATE KEY-----";
    const String pemp8encheader = "-----BEGIN ENCRYPTED PRIVATE KEY-----";
    const String pemp8encfooter = "-----END ENCRYPTED PRIVATE KEY-----";

    static bool verbose = false;

    public static RSACryptoServiceProvider GetRSAProviderFromPemFile( String pemfile )
    {
        bool isPrivateKeyFile = true;
        string pemstr = File.ReadAllText( pemfile ).Trim();
        if (pemstr.StartsWith( pempubheader ) && pemstr.EndsWith( pempubfooter ))
            isPrivateKeyFile = false;

        byte[] pemkey;
        if (isPrivateKeyFile)
            pemkey = DecodeOpenSSLPrivateKey( pemstr );
        else
            pemkey = DecodeOpenSSLPublicKey( pemstr );

        if (pemkey == null)
            return null;

        if (isPrivateKeyFile)
            return DecodeRSAPrivateKey( pemkey );
        else
            return DecodeX509PublicKey( pemkey );

    }



    //--------   Get the binary RSA PUBLIC key   --------
    static byte[] DecodeOpenSSLPublicKey( String instr )
    {
        const String pempubheader = "-----BEGIN PUBLIC KEY-----";
        const String pempubfooter = "-----END PUBLIC KEY-----";
        String pemstr = instr.Trim();
        byte[] binkey;
        if (!pemstr.StartsWith( pempubheader ) || !pemstr.EndsWith( pempubfooter ))
            return null;
        StringBuilder sb = new StringBuilder( pemstr );
        sb.Replace( pempubheader, "" );  //remove headers/footers, if present
        sb.Replace( pempubfooter, "" );

        String pubstr = sb.ToString().Trim();   //get string after removing leading/trailing whitespace

        try
        {
            binkey = Convert.FromBase64String( pubstr );
        }
        catch (System.FormatException)
        {       //if can't b64 decode, data is not valid
            return null;
        }
        return binkey;
    }

    static RSACryptoServiceProvider DecodeX509PublicKey(byte[] x509Key)
    {
        // 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 };
        // ---------  Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob  ------
        using (var mem = new MemoryStream(x509Key))
        {
            using (var binr = new BinaryReader(mem))    //wrap Memory Stream with BinaryReader for easy reading
            {
                try
                {
                    var twobytes = binr.ReadUInt16();
                    switch (twobytes)
                    {
                        case 0x8130:
                            binr.ReadByte();    //advance 1 byte
                            break;
                        case 0x8230:
                            binr.ReadInt16();   //advance 2 bytes
                            break;
                        default:
                            return null;
                    }

                    var seq = binr.ReadBytes(15);
                    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;

                    var 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);

                    byte firstbyte = binr.ReadByte();
                    binr.BaseStream.Seek(-1, SeekOrigin.Current);

                    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 = binr.ReadByte();        // should only need one byte for actual exponent data (for all useful values)
                    byte[] exponent = binr.ReadBytes(expbytes);

                    // We don't really need to print anything but if we insist to...
                    //showBytes("\nExponent", exponent);
                    //showBytes("\nModulus", modulus);

                    // ------- create RSACryptoServiceProvider instance and initialize with public key -----
                    RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
                    RSAParameters rsaKeyInfo = new RSAParameters
                    {
                        Modulus = modulus,
                        Exponent = exponent
                    };
                    rsa.ImportParameters(rsaKeyInfo);
                    return rsa;
                }
                catch (Exception)
                {
                    return null;
                }
            }
        }
    }

    //------- Parses binary ans.1 RSA private key; returns RSACryptoServiceProvider  ---
    static RSACryptoServiceProvider DecodeRSAPrivateKey( byte[] privkey )
    {
        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 );

            Console.WriteLine( "showing components .." );
            if (verbose)
            {
                showBytes( "\nModulus", MODULUS );
                showBytes( "\nExponent", E );
                showBytes( "\nD", D );
                showBytes( "\nP", P );
                showBytes( "\nQ", Q );
                showBytes( "\nDP", DP );
                showBytes( "\nDQ", DQ );
                showBytes( "\nIQ", IQ );
            }

            // ------- create RSACryptoServiceProvider instance and initialize with public key -----
            RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
            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)
        {
            return null;
        }
        finally { binr.Close(); }
    }

    private static int GetIntegerSize( BinaryReader binr )
    {
        byte bt = 0;
        byte lowbyte = 0x00;
        byte highbyte = 0x00;
        int count = 0;
        bt = binr.ReadByte();
        if (bt != 0x02)     //expect integer
            return 0;
        bt = binr.ReadByte();

        if (bt == 0x81)
            count = binr.ReadByte();    // data size in next byte
        else
            if (bt == 0x82)
            {
                highbyte = binr.ReadByte(); // data size in next 2 bytes
                lowbyte = binr.ReadByte();
                byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
                count = BitConverter.ToInt32( modint, 0 );
            }
            else
            {
                count = bt;     // we already have the data size
            }



        while (binr.ReadByte() == 0x00)
        {   //remove high order zeros in data
            count -= 1;
        }
        binr.BaseStream.Seek( -1, SeekOrigin.Current );     //last ReadByte wasn't a removed zero, so back up a byte
        return count;
    }

    //-----  Get the binary RSA PRIVATE key, decrypting if necessary ----
    static byte[] DecodeOpenSSLPrivateKey( String instr )
    {
        const String pemprivheader = "-----BEGIN RSA PRIVATE KEY-----";
        const String pemprivfooter = "-----END RSA PRIVATE KEY-----";
        String pemstr = instr.Trim();
        byte[] binkey;
        if (!pemstr.StartsWith( pemprivheader ) || !pemstr.EndsWith( pemprivfooter ))
            return null;

        StringBuilder sb = new StringBuilder( pemstr );
        sb.Replace( pemprivheader, "" );  //remove headers/footers, if present
        sb.Replace( pemprivfooter, "" );

        String pvkstr = sb.ToString().Trim();   //get string after removing leading/trailing whitespace

        try
        {        // if there are no PEM encryption info lines, this is an UNencrypted PEM private key
            binkey = Convert.FromBase64String( pvkstr );
            return binkey;
        }
        catch (System.FormatException)
        {       //if can't b64 decode, it must be an encrypted private key
            //Console.WriteLine("Not an unencrypted OpenSSL PEM private key");  
        }

        StringReader str = new StringReader( pvkstr );

        //-------- read PEM encryption info. lines and extract salt -----
        if (!str.ReadLine().StartsWith( "Proc-Type: 4,ENCRYPTED" ))
            return null;
        String saltline = str.ReadLine();
        if (!saltline.StartsWith( "DEK-Info: DES-EDE3-CBC," ))
            return null;
        String saltstr = saltline.Substring( saltline.IndexOf( "," ) + 1 ).Trim();
        byte[] salt = new byte[saltstr.Length / 2];
        for (int i = 0; i < salt.Length; i++)
            salt[i] = Convert.ToByte( saltstr.Substring( i * 2, 2 ), 16 );
        if (!(str.ReadLine() == ""))
            return null;

        //------ remaining b64 data is encrypted RSA key ----
        String encryptedstr = str.ReadToEnd();

        try
        {   //should have b64 encrypted RSA key now
            binkey = Convert.FromBase64String( encryptedstr );
        }
        catch (System.FormatException)
        {  // bad b64 data.
            return null;
        }

        //------ Get the 3DES 24 byte key using PDK used by OpenSSL ----

        SecureString despswd = GetSecPswd( "Enter password to derive 3DES key==>" );
        //Console.Write("\nEnter password to derive 3DES key: ");
        //String pswd = Console.ReadLine();
        byte[] deskey = GetOpenSSL3deskey( salt, despswd, 1, 2 );    // count=1 (for OpenSSL implementation); 2 iterations to get at least 24 bytes
        if (deskey == null)
            return null;
        //showBytes("3DES key", deskey) ;

        //------ Decrypt the encrypted 3des-encrypted RSA private key ------
        byte[] rsakey = DecryptKey( binkey, deskey, salt ); //OpenSSL uses salt value in PEM header also as 3DES IV
        if (rsakey != null)
            return rsakey;  //we have a decrypted RSA private key
        else
        {
            Console.WriteLine( "Failed to decrypt RSA private key; probably wrong password." );
            return null;
        }
    }


    // ----- Decrypt the 3DES encrypted RSA private key ----------

    static byte[] DecryptKey( byte[] cipherData, byte[] desKey, byte[] IV )
    {
        MemoryStream memst = new MemoryStream();
        TripleDES alg = TripleDES.Create();
        alg.Key = desKey;
        alg.IV = IV;
        try
        {
            CryptoStream cs = new CryptoStream( memst, alg.CreateDecryptor(), CryptoStreamMode.Write );
            cs.Write( cipherData, 0, cipherData.Length );
            cs.Close();
        }
        catch (Exception exc)
        {
            Console.WriteLine( exc.Message );
            return null;
        }
        byte[] decryptedData = memst.ToArray();
        return decryptedData;
    }

    //-----   OpenSSL PBKD uses only one hash cycle (count); miter is number of iterations required to build sufficient bytes ---
    static byte[] GetOpenSSL3deskey( byte[] salt, SecureString secpswd, int count, int miter )
    {
        IntPtr unmanagedPswd = IntPtr.Zero;
        int HASHLENGTH = 16;    //MD5 bytes
        byte[] keymaterial = new byte[HASHLENGTH * miter];     //to store contatenated Mi hashed results


        byte[] psbytes = new byte[secpswd.Length];
        unmanagedPswd = Marshal.SecureStringToGlobalAllocAnsi( secpswd );
        Marshal.Copy( unmanagedPswd, psbytes, 0, psbytes.Length );
        Marshal.ZeroFreeGlobalAllocAnsi( unmanagedPswd );

        //UTF8Encoding utf8 = new UTF8Encoding();
        //byte[] psbytes = utf8.GetBytes(pswd);

        // --- contatenate salt and pswd bytes into fixed data array ---
        byte[] data00 = new byte[psbytes.Length + salt.Length];
        Array.Copy( psbytes, data00, psbytes.Length );      //copy the pswd bytes
        Array.Copy( salt, 0, data00, psbytes.Length, salt.Length ); //concatenate the salt bytes

        // ---- do multi-hashing and contatenate results  D1, D2 ...  into keymaterial bytes ----
        MD5 md5 = new MD5CryptoServiceProvider();
        byte[] result = null;
        byte[] hashtarget = new byte[HASHLENGTH + data00.Length];   //fixed length initial hashtarget

        for (int j = 0; j < miter; j++)
        {
            // ----  Now hash consecutively for count times ------
            if (j == 0)
                result = data00;    //initialize 
            else
            {
                Array.Copy( result, hashtarget, result.Length );
                Array.Copy( data00, 0, hashtarget, result.Length, data00.Length );
                result = hashtarget;
                //Console.WriteLine("Updated new initial hash target:") ;
                //showBytes(result) ;
            }

            for (int i = 0; i < count; i++)
                result = md5.ComputeHash( result );
            Array.Copy( result, 0, keymaterial, j * HASHLENGTH, result.Length );  //contatenate to keymaterial
        }
        //showBytes("Final key material", keymaterial);
        byte[] deskey = new byte[24];
        Array.Copy( keymaterial, deskey, deskey.Length );

        Array.Clear( psbytes, 0, psbytes.Length );
        Array.Clear( data00, 0, data00.Length );
        Array.Clear( result, 0, result.Length );
        Array.Clear( hashtarget, 0, hashtarget.Length );
        Array.Clear( keymaterial, 0, keymaterial.Length );

        return deskey;
    }

    static SecureString GetSecPswd( String prompt )
    {
        SecureString password = new SecureString();

        Console.ForegroundColor = ConsoleColor.Gray;
        Console.Write( prompt );
        Console.ForegroundColor = ConsoleColor.Magenta;

        while (true)
        {
            ConsoleKeyInfo cki = Console.ReadKey( true );
            if (cki.Key == ConsoleKey.Enter)
            {
                Console.ForegroundColor = ConsoleColor.Gray;
                Console.WriteLine();
                return password;
            }
            else if (cki.Key == ConsoleKey.Backspace)
            {
                // remove the last asterisk from the screen...
                if (password.Length > 0)
                {
                    Console.SetCursorPosition( Console.CursorLeft - 1, Console.CursorTop );
                    Console.Write( " " );
                    Console.SetCursorPosition( Console.CursorLeft - 1, Console.CursorTop );
                    password.RemoveAt( password.Length - 1 );
                }
            }
            else if (cki.Key == ConsoleKey.Escape)
            {
                Console.ForegroundColor = ConsoleColor.Gray;
                Console.WriteLine();
                return password;
            }
            else if (Char.IsLetterOrDigit( cki.KeyChar ) || Char.IsSymbol( cki.KeyChar ))
            {
                if (password.Length < 20)
                {
                    password.AppendChar( cki.KeyChar );
                    Console.Write( "*" );
                }
                else
                {
                    Console.Beep();
                }
            }
            else
            {
                Console.Beep();
            }
        }
    }

    static bool CompareBytearrays( byte[] a, byte[] b )
    {
        if (a.Length != b.Length)
            return false;
        int i = 0;
        foreach (byte c in a)
        {
            if (c != b[i])
                return false;
            i++;
        }
        return true;
    }

    static void showBytes( String info, byte[] data )
    {
        Console.WriteLine( "{0}  [{1} bytes]", info, data.Length );
        for (int i = 1; i <= data.Length; i++)
        {
            Console.Write( "{0:X2}  ", data[i - 1] );
            if (i % 16 == 0)
                Console.WriteLine();
        }
        Console.WriteLine( "\n\n" );
    }

}
person Sergey    schedule 27.08.2015
comment
Мне очень жаль, что OP не пометил ваш ответ как принятый. Это действительно хорошо. - person Ofer Zelig; 27.04.2017
comment
Что ж ... Это не работает, например, эти ключи openssl, ни из некоторых библиотек, вы можете посмотреть: github.com/dvsekhvalnov/jose-jwt/issues/ ^^ ' - person z3nth10n; 11.05.2018
comment
Этот код (особенно пропуск начальных нулей в GetIntegerSize) может вызвать CryptographicException в ImportParameters из-за слишком коротких значений. Это случается только спорадически. Если не пропускать начальные нули, это может привести к тому же исключению из-за слишком длинных значений. Неясно, могут ли значения оказаться слишком короткими без пропуска ведущих нулей в GetIntegerSize, поскольку это зависит от ввода. Подробнее см. Stackoverflow.com/a/39135984/2279059. - person Florian Winter; 23.08.2019

Если вы говорите о сертификате X509:

FileStream fs = new FileStream("your_cert_file.crt", FileMode.Open);
byte[] certBytes = new byte[fs.Length];
fs.Read(certBytes, 0, (Int32)fs.Length);
fs.Close();
System.Security.Cryptography.X509Certificates.X509Certificate x509cert = 
    new X509Certificate(certBytes);
Console.WriteLine(x509cert.GetPublicKey());
Console.WriteLine(x509cert.GetPublicKeyString());

ИЗМЕНЕНО после комментария @hkproj, сделанного в "16.07.2012 15:04:58 Z":

Осмотревшись здесь, я обнаружил «Чтение открытого ключа PEM RSA только с использованием Bouncy Castle». Я думаю, что вам нужно:

using (StreamReader reader = File.OpenText(@"c:\RSA.txt"))
{
    Org.BouncyCastle.OpenSsl.PemReader pr = 
        new Org.BouncyCastle.OpenSsl.PemReader(reader);
    Org.BouncyCastle.Utilities.IO.Pem.PemObject po = pr.ReadPemObject();

    Console.WriteLine("PemObject, Type: " + po.Type);
    Console.WriteLine("PemObject, Length: " + po.Content.Length);
}

Однако с вашим файлом я получаю ошибку: System.IO.IOException : base64 data appears to be truncated.

Итак, измените свой файл на что-то вроде:

-----BEGIN PUBLIC KEY-----
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/syEKqEkMtQL0+d
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+izR
KbGMRtur2TYklnyVkjeeHfAggo8vWQmWesnOG55vQYHbOOFoJbk0EkwEr5R/PbKm
byXPPN8zwnS5/XXXXXXXXXXXXZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
-----END PUBLIC KEY-----

Результат:

PemObject, Type: PUBLIC KEY
PemObject, Length: 192
person Hailton    schedule 16.07.2012
comment
уже пробовал. Не сработало. Выдает исключение CryptographicException со следующим сообщением: Не удается найти запрошенный объект. - person Umar Jamil; 16.07.2012

Вы говорите о сертификатах, хранящихся в файле?

Если у вас есть объект вроде:

X509Certificate2 certificate;

вы можете использовать следующий код:

RSACryptoServiceProvider rsaprovider =
                    (RSACryptoServiceProvider)certificate.PublicKey.Key;

а затем используйте класс RSACryptoServiceProvider (см. http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.aspx).

Чтобы загрузить X509Certificate2, используйте его конструктор (см. http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509certificate2.aspx).

Эта программа у меня отлично работает:

    static void Main(string[] args)
    {
        try 
        {
            X509Certificate2 certificate = 
                new X509Certificate2("<PFX Certificate Path", "<Certificate-Password>");
            RSACryptoServiceProvider rsaprovider = (RSACryptoServiceProvider)certificate.PublicKey.Key;
        }
        catch(Exception e)
        {

        }
    }
person iSamnium    schedule 16.07.2012
comment
Выдает исключение CryptographicException со следующим сообщением: Не удается найти запрошенный объект. - person Umar Jamil; 16.07.2012
comment
Я знаю, что конструктор ждет двоичного сертификата (DER formar), а не base64 ... читая ваше решение, я заметил это FromBase64String, поэтому вы используете двоичный формат Base64? - person iSamnium; 16.07.2012
comment
Сертификат сохраняется в формате base64. Поэтому я использую FromBase64String для преобразования его в массив байтов, чтобы передать его конструктору. Кстати, решил. Если вы посмотрите на мое решение, я использую метод, который я украл из инструмента opensslkey (который является открытым исходным кодом). Надеюсь, это поможет. - person Umar Jamil; 16.07.2012

Начиная с .Net 5.0, вы можете импортировать открытый ключ RSA из такой строки:

var rsaPublicKey = RSA.Create();
rsaPublicKey.ImportFromPem(publicKeyString);

Если вы не знаете, как читать файл в строку, см.

Как прочитать весь файл в строку с помощью C #?

person Kevin    schedule 28.04.2021