2012-03-05 95 views
1

我想使用eith Rijndael或Aes和下面的代码来加密/解密字符串。Rijndael填充或长度无效

public class Crypto 
{ 
    private const string defaultVector = "asdfg123456789"; 
    private const CipherMode cipherMode = CipherMode.CBC; 
    //Have tried PaddingMode.ISO10126, PaddingMode.None, and PaddingMode.PKCS7 
    private const PaddingMode paddingMode = PaddingMode.ISO10126; 
    private const int iterations = 2; 
    private static Rijndael GetCrypto(string passphrase) 
    { 
     var crypt = Rijndael.Create(); 
     crypt.Mode = cipherMode; 
     crypt.Padding = paddingMode; 
     crypt.BlockSize = 256; 
     crypt.KeySize = 256; 
     crypt.Key = 
      new Rfc2898DeriveBytes(passphrase, Encoding.Unicode.GetBytes(defaultVector), iterations).GetBytes(32); 
     crypt.IV = new Rfc2898DeriveBytes(passphrase, Encoding.Unicode.GetBytes(defaultVector), iterations).GetBytes(32); 
     return crypt; 
    } 
    public static string Encrypt(string plainText, string passphrase) 
    { 
     byte[] clearData = Encoding.Unicode.GetBytes(plainText); 
     byte[] encryptedData; 
     var crypt = GetCrypto(passphrase); 
     using (var ms = new MemoryStream()) 
     { 
      using (var cs = new CryptoStream(ms, crypt.CreateEncryptor(), CryptoStreamMode.Write)) 
      { 
       cs.Write(clearData, 0, clearData.Length); 
       //cs.FlushFinalBlock(); //Have tried this active and commented with no change. 
      } 
      encryptedData = ms.ToArray(); 
     } 
     //Changed per Xint0's answer. 
     return Convert.ToBase64String(encryptedData); 
    } 
    public static string Decrypt(string cipherText, string passphrase) 
    { 
     //Changed per Xint0's answer. 
     byte[] encryptedData = Convert.FromBase64String(cipherText); 
     byte[] clearData; 
     var crypt = GetCrypto(passphrase); 
     using (var ms = new MemoryStream()) 
     { 
       using (var cs = new CryptoStream(ms, crypt.CreateDecryptor(), CryptoStreamMode.Write)) 
       { 
        cs.Write(encryptedData, 0, encryptedData.Length); 
        //I have tried adding a cs.FlushFinalBlock(); here as well. 
       } 
       clearData = ms.ToArray(); 
     } 
     return Encoding.Unicode.GetString(clearData); 
    } 
} 

//编辑:我已经改变了统一调用按照以下XINT0的回答Convert.ToBase64String。

在解密方法中的cs.Write,我得到错误,“填充无效,无法删除。”

我曾尝试将填充设置为PaddingMode.None,但我得到“要加密的数据长度无效”。在加密方法中的cs.Write上。

我看过这些,他们所说的没有什么似乎可以工作。

Padding is invalid and cannot be removed

Padding is invalid and cannot be removed?

栈跟踪显示System.Security.CryptographicException从RijndaelManagedTransform.DecryptData(字节[] INPUTBUFFER,的Int32 inputOffset,的Int32 inputCount,字节[] & OutputBuffer中,的Int32 outputOffset,PaddingMode未来paddingMode,Boolean fLast)。

回答

1

我看到两个问题:

  1. 你不冲水,并呼吁ms.ToArray()前关闭流。将其更改为:

    ... 
    using (var cs = new CryptoStream(ms, crypt.CreateEncryptor(), CryptoStreamMode.Write)) 
    { 
        cs.Write(clearData, 0, clearData.Length); 
        cs.FlushFinalBlock(); 
        cs.Close(); 
    } 
    
    ms.Close(); 
    encryptedData = ms.ToArray(); 
    ... 
    
  2. Encrypt生成的字节数组encryptedData不是 Unicode字符串,但使用的是一个Unicode编码器来获得从字节数组的字符串。代替代替EncryptSystem.Convert.FromBase64String()代替Decrypt

Encrypt做:

return System.Convert.ToBase64String(encryptedData); 

Decrypt做:

byte[] encryptedData = System.Convert.FromBase64String(cipherText); 

编辑

最大的问题是Encrypt返回值。加密Unicode字符串的字节表示的结果是不是 Unicode字符串的字节表示形式。您不应使用encryptedDataEncoding.Unicode.GetString()的值来获取加密数据的字符串表示形式。使用System.Convert.ToBase64String()可获取加密数据的字符串表示形式。请参阅Encoding Class MSDN文档中的注释部分。

EDIT 2

注意Rijndael算法是不完全的AES,如果您正在使用AES互操作的块大小应始终是128位的独立密钥大小的。详情请参阅here

+0

我曾尝试加入cs.Close()和cs.FlushFinalBlock()的每一个排列。堆栈跟踪显示来自CryptoStream调用的System.Security.Cryptography.RijndaelManagedTransform.DecryptData(Byte [] inputBuffer,Int32 inputOffset,Int32 inputCount,Byte []&outputBuffer,Int32 outputOffset,PaddingMode paddingMode,Boolean fLast)的错误。 FlushFinalBlock()。当CryptoStream被关闭/处置时FlushFinalBlock也被调用。所以我在这里亏本。 – PMontgomery 2012-03-06 15:24:45

+0

@PMontgomery你用'System.Convert.ToBase64String(encryptedData)'替换'Encoding.Unicode.GetString(encryptedBytes)'?这是你最大的问题。 – Xint0 2012-03-06 17:45:07

+0

是的,我已经做了这些修改并编辑了原始问题以反映。它没有改变错误。 – PMontgomery 2012-03-06 19:41:03

2

我花了很多的时间来找到造成的原因CryptographicException我也是googling,包括Stackoverflow。

它是从实例投掷方法FlushFinalBlock()的CryptoStream的:
它(用复制粘贴编程时经常)如下是一个愚蠢的错误。

WRONG代码:

CryptoStream cs = new CryptoStream(ms, rj.CreateDecryptor(rj.Key, rj.IV), CryptoStreamMode.Write); 

我用它来加密,所以你可以看到CryptoStreamMode。 但在相同的指令中,我创建了解密器而不是加密器(请参阅构造函数中的第二个参数)。

仔细的检查,以避免浪费您的宝贵时间;)

问候
布罗尼斯瓦夫

0

我也有类似的问题,在解密方法的问题是初始化一个空的内存流。当它工作时,我与密文字节数组像这样初始化它:

MemoryStream ms = new MemoryStream(cipherText);