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).
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 array encryptedData
is NOT a Unicode string, yet you are using a Unicode encoder to get a string from the byte array. Instead of that use System.Convert.ToBase64String()
in Encrypt
and System.Convert.FromBase64String()
in Decrypt
.
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.