问题
I am trying to encrypt/decrypt a string using eith Rijndael or Aes and the code below.
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);
}
}
//Edits: I have changed over the Unicode calls to Convert.ToBase64String per Xint0's answer below.
On the cs.Write in Decrypt method, I am getting the error that "Padding is invalid and cannot be removed."
I have tried setting the padding to PaddingMode.None but I get "Length of the data to encrypt is invalid." on the cs.Write in the Encrypt method.
I've looked at these and nothing they've said seems to work.
Padding is invalid and cannot be removed
Padding is invalid and cannot be removed?
Stack trace shows System.Security.CryptographicException is coming from RijndaelManagedTransform.DecryptData(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount, Byte[]& outputBuffer, Int32 outputOffset, PaddingMode paddingMode, Boolean fLast).
回答1:
I see two problems:
You are not flushing and closing the streams before calling
ms.ToArray()
. Change it to:... 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(); ...
In
Encrypt
the resulting byte arrayencryptedData
is NOT a Unicode string, yet you are using a Unicode encoder to get a string from the byte array. Instead of that useSystem.Convert.ToBase64String()
inEncrypt
andSystem.Convert.FromBase64String()
inDecrypt
.
In Encrypt
do:
return System.Convert.ToBase64String(encryptedData);
In Decrypt
do:
byte[] encryptedData = System.Convert.FromBase64String(cipherText);
EDIT
The biggest problem is the return value of Encrypt
. The result of encrypting the byte representation of a Unicode string is NOT a byte representation of a Unicode string. You should not use the value of encryptedData
with Encoding.Unicode.GetString()
to get a string representation of the encrypted data. Use System.Convert.ToBase64String()
to get a string representation of the encrypted data. Please see the Remarks section in the Encoding Class MSDN Documentation.
EDIT 2
Note that Rijndael is not exactly AES, if you are interoperating with AES the block size should always be 128-bits, independent of the key size. For details you can read about it here.
回答2:
I have spend a lot of my time for finding what was causing CryptographicException and I was googling too including Stackoverflow.
It was a stupid mistake (as often when programming with copy-paste) as follow:
It was throwing on method FlushFinalBlock() from instance of CryptoStream.
Look at WRONG code:
CryptoStream cs = new CryptoStream(ms, rj.CreateDecryptor(rj.Key, rj.IV), CryptoStreamMode.Write);
I used it to encrypt so you can see CryptoStreamMode.Write but in the same instruction I was creating decryptor instead of encryptor (see second parameter in the constructor).
Be careful and check it to avoid wasting your precious time ;)
Regards
Bronek
回答3:
I had a similar problem, the issue in decrypt method was initializing an empty memory stream. when it worked when I initialized it with the cipher text byte array like this:
MemoryStream ms = new MemoryStream(cipherText);
来源:https://stackoverflow.com/questions/9574850/rijndael-padding-or-length-is-invalid