使用RSA在C#中使用正确的私钥和公钥对进行解密时出现错误数据异常

时间:2013-04-01 16:47:36

标签: c# rsa rsacryptoserviceprovider

这是我的解密过程代码:

    private RSACryptoServiceProvider _rsa;
    private string _privateKey;
    private string _publicKey;

    public RsaLibrary()
    {
        //initialsing the RSA object taking the option of a 1024 key size
        _rsa = new RSACryptoServiceProvider(1024);
        _privateKey = _rsa.ToXmlString(true);
        _publicKey = _rsa.ToXmlString(false);

    }

 public string Decrypt(string ciphertext, string privateKey_ = null)
    {
        if (String.IsNullOrEmpty(privateKey_))
        {
            return DecryptToBytes(ciphertext, _privateKey);
        }
        else
        {
            return DecryptToBytes(ciphertext, privateKey_);
        }
    }

    private string DecryptToBytes(string ciphertext, string privateKey)
    {
        if (String.IsNullOrEmpty(privateKey))
        {
            throw new ArgumentNullException("Error: No key provided.");
        }
        if (ciphertext.Length<=0)
        {
            throw new ArgumentNullException("Error: No message to decrypt.");
        }

        byte[] plaintext;
        byte[] ciphertext_Bytes = Encoding.Unicode.GetBytes(ciphertext);
        _rsa.FromXmlString(privateKey);

        plaintext = _rsa.Decrypt(ciphertext_Bytes, false);

        return Encoding.Unicode.GetString(plaintext);
    }

加密代码:

        private string EncryptToByte(string plaintext, string publicKey)
    {
        if (String.IsNullOrEmpty(publicKey))
        {
            throw new ArgumentNullException("Error: No key provided.");
        }
        if (plaintext.Length<=0)
        {
            throw new ArgumentNullException("Error: No message to incrypt");
        }


        byte[] ciphertext;
        byte[] plaintext_Bytes = Encoding.Unicode.GetBytes(plaintext);
        _rsa.FromXmlString(publicKey);

        ciphertext = _rsa.Encrypt(plaintext_Bytes, false);
        return Convert.ToBase64String(ciphertext);
    }

我看不出我错在哪里。我确保钥匙是正确的。我在构造函数中使用此行提取的公共一个:                            _publicKey = _rsa.ToXmlString(false); 此公钥显示在我创建的表单上。私人我用“真”而不是假。

有什么想法吗?

2 个答案:

答案 0 :(得分:5)

密文不太可能是真正的UTF-16编码文本。假设加密方面有类似的内容:

string encryptedText = Encoding.Unicode.GetString(encryptedBytes);
你基本上丢失了数据。加密的结果是文本 - 它是任意二进制数据。如果由于某些传输原因要将其转换为文本,则应使用Base64,例如

string base64EncryptedText = Convert.ToBase64String(encryptedBytes);

然后使用Convert.FromBase64String恢复准备解密的原始加密二进制数据。

答案 1 :(得分:0)

以下是您使用base-64字符串的RsaLibrary类,如Jon建议的那样:

    class RsaLibrary
    {
        //initializing the RSA object taking the option of a 1024 key size
        readonly RSACryptoServiceProvider _rsa = new RSACryptoServiceProvider(1024);
        readonly string _privateKey;
        readonly string _publicKey;

        public RsaLibrary()
        {
            _privateKey = _rsa.ToXmlString(true);
            _publicKey = _rsa.ToXmlString(false);
        }

        public string Decrypt(string ciphertext, string privateKey_ = null)
        {
            if (ciphertext.Length <= 0) throw new ArgumentNullException("ciphertext");

            string key = String.IsNullOrEmpty(privateKey_) ? _privateKey : privateKey_;
            return DecryptToBytes(ciphertext, key);
        }
        private string DecryptToBytes(string ciphertext, string privateKey)
        {
            if (String.IsNullOrEmpty(privateKey)) throw new ArgumentNullException("privateKey");

            byte[] ciphertext_Bytes = Convert.FromBase64String(ciphertext);
            _rsa.FromXmlString(privateKey);

            byte[] plaintext = _rsa.Decrypt(ciphertext_Bytes, false);
            return Encoding.Unicode.GetString(plaintext);
        }

        public string Encrypt(string plaintext, string publicKey_ = null)
        {
            if (plaintext.Length <= 0) throw new ArgumentNullException("plaintext");

            string key = String.IsNullOrEmpty(publicKey_) ? _publicKey : publicKey_;
            return EncryptToBytes(plaintext, key);
        }
        private string EncryptToBytes(string plaintext, string publicKey)
        {
            if (String.IsNullOrEmpty(publicKey)) throw new ArgumentNullException("publicKey");

            byte[] plaintext_Bytes = Encoding.Unicode.GetBytes(plaintext);
            _rsa.FromXmlString(publicKey);

            byte[] ciphertext = _rsa.Encrypt(plaintext_Bytes, false);
            return Convert.ToBase64String(ciphertext);
        }
    }

你真的应该使用SecureString作为你的明文。

class RsaLibrary2
{
    //initializing the RSA object taking the option of a 1024 key size
    readonly RSACryptoServiceProvider _rsa = new RSACryptoServiceProvider(1024);
    readonly string _privateKey;
    readonly string _publicKey;

    public RsaLibrary2()
    {
        _privateKey = _rsa.ToXmlString(true);
        _publicKey = _rsa.ToXmlString(false);
    }

    public SecureString Decrypt(string ciphertext, string privateKey_ = null)
    {
        if (ciphertext.Length <= 0) throw new ArgumentNullException("ciphertext");

        string key = String.IsNullOrEmpty(privateKey_) ? _privateKey : privateKey_;
        return DecryptToBytes(ciphertext, key);
    }
    private SecureString DecryptToBytes(string ciphertext, string privateKey)
    {
        if (String.IsNullOrEmpty(privateKey)) throw new ArgumentNullException("privateKey");

        byte[] ciphertext_Bytes = Convert.FromBase64String(ciphertext);
        _rsa.FromXmlString(privateKey);

        byte[] plainbytes = _rsa.Decrypt(ciphertext_Bytes, false);
        char[] plain = Encoding.Unicode.GetChars(plainbytes);
        var retval = new SecureString();
        FromArray(retval, ref plain);
        return retval;
    }

    public string Encrypt(SecureString plaintext, string publicKey_ = null)
    {
        if (plaintext == null) throw new ArgumentNullException("plaintext");
        if (plaintext.Length <= 0) throw new ArgumentOutOfRangeException("plaintext");

        string key = String.IsNullOrEmpty(publicKey_) ? _publicKey : publicKey_;
        return EncryptToBytes(plaintext, key);
    }
    private string EncryptToBytes(SecureString plaintext, string publicKey)
    {
        if (String.IsNullOrEmpty(publicKey)) throw new ArgumentNullException("publicKey");

        byte[] plaintext_Bytes = SecureStringToByteArray(plaintext);
        _rsa.FromXmlString(publicKey);

        byte[] ciphertext = _rsa.Encrypt(plaintext_Bytes, false);
        return Convert.ToBase64String(ciphertext);
    }

    // YIKES! Copies the SecureString to a byte[] array; use with caution!
    static byte[] SecureStringToByteArray(SecureString secureString)
    {
        if (secureString == null) throw new ArgumentNullException(/*MSG0*/"secureString");

        // copy plaintext from unmanaged memory into managed byte[]s
        int stringSize = secureString.Length * sizeof(char); // http://blogs.msdn.com/shawnfa/archive/2005/02/25/380592.aspx
        byte[] bytes = new byte[stringSize];
        IntPtr pString = Marshal.SecureStringToGlobalAllocUnicode(secureString); // do this last to minimize the availability of "pString"
        try // free "pString" even if Copy() throws
        {
            Marshal.Copy(pString, bytes, 0, stringSize);
        }
        finally
        {
            Marshal.ZeroFreeGlobalAllocUnicode(pString); // clear plaintext from unmanaged memory ASAP
        }

        return bytes;
    }

    static void ArrayZero<T>(ref T[] array)
    {
        Array.Clear(array, 0, array.Length); // clear from managed memory
        Array.Resize(ref array, 0); // set Length=0 ASAP; even the length can be valuable
        array = null; // just to "help" callers know there's nothing in the array anymore
    }

    static void FromArray(SecureString secureString, ref char[] array)
    {
        try // clear "array" even if AppendChar() throws
        {
            for (int i = 0; i < array.Length; i++)
            {
                secureString.AppendChar(array[i]);
                array[i] = default(char); // clear plaintext ASAP
            }
        }
        finally
        {
            ArrayZero(ref array); // clear plaintext from managed memory
        }
    }
}