使用RSA编码字符串

时间:2011-08-23 20:57:35

标签: c# encryption rsa

我正在使用API​​,该API指定必须使用“RSA / ECB / PKCS1Padding”编码传递某些文本。公钥以.PEM格式提供;我我成功地将它转换为XML格式,现在我正在使用这个C#代码:

    RSACryptoServiceProvider rsa1 = new RSACryptoServiceProvider();
    rsa1.FromXmlString(testpublickey);

    System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
    byte[] textBytes = encoding.GetBytes(plainstring);
    byte[] encryptedOutput = rsa1.Encrypt(textBytes, false);
    string outputB64 = Convert.ToBase64String(encryptedOutput);
    Console.WriteLine(outputB64);
    return outputB64;

但是,返回的字符串与预期的字符串不匹配 - API提供了以下OpenSSL命令作为示例:

openssl rsautl -encrypt -in PIN.txt -inkey public_key_for_pin.pem -pubin | openssl base64 > PIN.base64

OpenSSL的输出与我的代码输出不匹配。任何人都可以看到我的代码有任何问题;我是否需要指定特定的填充,或者我是否可能在从PEM到XML的转换中破坏了公钥文件?

3 个答案:

答案 0 :(得分:3)

我这样做是用公钥加密数据。

首先将PEM数据加载到X509Certificate2类中,它具有您可以使用的导入方法。

然后我使用以下代码:

using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography;

public static string EncryptString(string clearText, X509Certificate2 cert)
{
    try
    {
        byte[] encodedCypher = EncryptData(Encoding.UTF8.GetBytes(clearText), cert);
        string cipherText = Convert.ToBase64String(encodedCypher);

        return cipherText;
    }
    catch (Exception ex)
    {
        throw new EncryptionException("Could not Encrypt String. See InnerException for details.", ex);
    }
}

private static byte[] EncryptData(byte[] clearText, X509Certificate2 cert)
{
    ContentInfo payloadInfo = new ContentInfo(clearText);
    EnvelopedCms payloadEnvelope = new EnvelopedCms(payloadInfo);
    CmsRecipient certHandle = new CmsRecipient(cert);
    payloadEnvelope.Encrypt(certHandle);
    return payloadEnvelope.Encode();
}

答案 1 :(得分:0)

输出不应匹配。出于安全原因,使用PKCS#1块类型2的RSA公钥加密会插入随机填充。

答案 2 :(得分:0)

在用公钥加密花了一些时间之后,我认为我会为这个旧线程做出贡献,所以有人可能会发现它在将来很有用。

使用仅包含public.key的文件初始化X509Certificate2对象的实例不起作用。它需要一个证书,因此"无法找到所请求的对象"错误。

以下是仅使用public.key文件加密某些内容所必须做的事情。

using System;
using System.IO;
using System.IO.Compression;
using System.Security.Cryptography;
using System.Text;
namespace Program
{
    class Program
    {
        static void Main( string[] args ) {

            // Load client's public key file.
            //
            RSAPublicKey = File.ReadAllText( @"public.key" );

            // Decode it
            //
            byte[] PEMPublicKey = DecodeOpenSSLPublicKey( RSAPublicKey );

            if( PEMPublicKey == null ){
                throw new Exception( "Could not decode RSA public key." );
            }

            //Create a new instance of RSACryptoServiceProvider with appropriate public key
            //
            RSACryptoServiceProvider RSA = DecodeX509PublicKey( PEMPublicKey );


            // Should you want to save your XMLPublicKey for future use of RSA.FromXmlString( XMLPublicKey );
            //
            // String XMLPublicKey = RSA.ToXmlString( false );


            byte[] cypher = RSA.Encrypt( Encoding.ASCII.GetBytes( "This is a test" ), false );
            File.WriteAllBytes( @"cypher.txt", cypher );

            return;

        }

        // The following code has been obtained from:
        // http://csslab.s3.amazonaws.com/csslabs/Siva/opensslkey.cs
        // All credits go to the unknown author
        //
        // --------   Get the binary RSA PUBLIC key   --------
        //
        public 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;
        }


        //------- Parses binary asn.1 X509 SubjectPublicKeyInfo; returns RSACryptoServiceProvider ---
        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(); }

        }

        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 byte[] Combine( byte[] first, byte[] second ) {
            byte[] ret = new byte[ first.Length + second.Length ];
            Buffer.BlockCopy( first, 0, ret, 0, first.Length );
            Buffer.BlockCopy( second, 0, ret, first.Length, second.Length );
            return ret;
        }

    }
}

您可以使用openssl测试您的结果,如下所示: openssl decrypt