I'm using Aes to encrypt and decrypt data. I have tested my Encrypt and Decrypt functions and they work, but when I try to decrypt stored in my database data it throws me
System.Security.Cryptography.CryptographicException: The input data is
not a complete block.
What I do before storing the bytes encryption is
string encryptedData = Encoding.UTF8.GetString(_securityService.AesEncryptToBytes(data));
// Proceed in adding the encryptedData to the database.
This is how I decrypt my encrypted data pulled from the database.
string data = _securityService.AesDecryptFromBytes(Encoding.UTF8.GetBytes(encryptedDataPulledFromMyDataBase));
My encryption method:
public byte[] AesEncryptToBytes(string plainText)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (key == null || key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("IV");
byte[] encrypted;
// Create an Aes object
// with the specified key and IV.
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = key;
aesAlg.IV = IV;
// Create an encryptor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
// Return the encrypted bytes from the memory stream.
return encrypted;
}
My Decryption method:
public string AesDecryptFromBytes(byte[] cipherText)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (key == null || key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("IV");
// Declare the string used to hold
// the decrypted text.
string plaintext = null;
// Create an Aes object
// with the specified key and IV.
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = key;
aesAlg.IV = IV;
// Create a decryptor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
return plaintext;
}
What I've done is basically copy pasting the code from Microsoft Docs. Both methods work when testing them, but when I try to Decrypt the Encrypted data which is the encryption bytes converted to string I get thrown the exception.
Related
I have a requirement where I need to convert some PHP code to C#.. following is the PHP Code that needs to be converted:
$data = "Hello World!";
$key = "RTc0MDkwMEEwMDYxQjc4Mg=="
$encRaw = openssl_encrypt($data, 'AES-128-ECB', $key, OPENSSL_RAW_DATA);
To convert this openssl encryption, I am using below C# code:
static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
byte[] encrypted;
// Create an Aes object
// with the specified key and IV.
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = Key;
//aesAlg.IV = IV;
// Create an encryptor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
// Return the encrypted bytes from the memory stream.
return encrypted;
}
But somehow this is not giving me same result that PHP function is returning.
Can someone please help me to identify the issue in my code? Or suggest me what other changes should I do in my code so that I get the similar result that PHP function is returning.
I am trying to encrypt my data using the AES algorith.I got the functions from the MSDN site encryption decryption. What i am doing is i'm encrypting the data and storing it as a string using the following method
byte[] encrypted = EncryptStringToBytes_Aes(response, myAes.Key, myAes.IV);
string saveresponse = Convert.ToBase64String(encrypted);
and then i save it in IsolatedStorageSettings
settings.Add(merchantId, saveresponse);
But the problem i am facing is when the user comes after sometime and hits my page i check first in the IsolatedStorageSettings object if the data is present i pass that data to decrypt and process further.The step i use to decrypt is as follows
byte[] temp = Convert.FromBase64String(response);
response = DecryptStringFromBytes_Aes(temp, myAes.Key, myAes.IV);
But the above line gives me error "Value can not be null.
Parameter name: inputBuffer"
I am unable to find where i am going wrong.Can u guys please let me know what steps should be taken to make it up and running.
Here is the Encryption Code
static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("Key");
byte[] encrypted;
// Create an AesManaged object
// with the specified key and IV.
using (AesManaged aesAlg = new AesManaged())
{
aesAlg.Key = Key;
aesAlg.IV = IV;
// Create a decrytor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
return encrypted;
}
and here is the decryption code
static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key, byte[] IV)
{
try
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("Key");
// Declare the string used to hold
// the decrypted text.
string plaintext = null;
// Create an AesManaged object
// with the specified key and IV.
using (AesManaged aesAlg = new AesManaged())
{
aesAlg.Key = Key;
aesAlg.IV = IV;
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
return plaintext;
}
catch (Exception ex) {
return "Error";
}
}
and on button1 click i call the encryption method
using (AesManaged myAes = new AesManaged())
{
byte[] encrypted = EncryptStringToBytes_Aes(response, myAes.Key, myAes.IV);
string saveresponse = Convert.ToBase64String(encrypted);
}
and on button 2 i call decryption method
using (AesManaged myAes = new AesManaged())
{
byte[] temp= Convert.FromBase64String(response)
response = DecryptStringFromBytes_Aes(temp, myAes.Key, myAes.IV);
}
The problem was the using (AesManaged myAes = new AesManaged()){} block what it does it generates the new key and IV for encryption and decryption.So while decryption the key and IV doesnt match hence the error generates.Just remove the using block and declare the Aesmanaged myAes object at global level and the problem is solved. So the final code would look like
AesManaged myAes = new AesManaged();
On button one click to encrypt;
byte[] encrypted = EncryptStringToBytes_Aes(response, myAes.Key, myAes.IV);
string saveresponse = Convert.ToBase64String(encrypted);
and button2 click to decrypt
byte[] temp = Convert.FromBase64String(response);
response = DecryptStringFromBytes_Aes(temp, myAes.Key, myAes.IV);
Thats it, happpy coding.
I have a C# WinForms app, with AES encryption/decryption. The encryption (decryption) itself works fine, but only once. If I try to encrypt another string, I get a CryptographyException saying the padding is invalid. Based on some research, it seems I forgot to close some stream, but I can't figure out what it is. Does anyone know how to fix this?
Here is the code I use (I believe I found it earlier somewher on SO):
static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key
, byte[] IV)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("Key");
// Declare the string used to hold
// the decrypted text.
string plaintext = null;
// Create an Aes object
// with the specified key and IV.
using (Aes aesAlg = Aes.Create())
{
aesAlg.Padding = PaddingMode.PKCS7;
aesAlg.Key = Key;
aesAlg.IV = IV;
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key
, aesAlg.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt
, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(
csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
//csDecrypt.FlushFinalBlock(); causes an exception
plaintext = srDecrypt.ReadToEnd();
//csDecrypt.Flush(); experimental solution, doesn't work either
srDecrypt.Close();
}
csDecrypt.Close();
}
msDecrypt.Close();
}
}
return plaintext;
}
static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key,
byte[] IV)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("Key");
byte[] encrypted;
// Create an Aes object
// with the specified key and IV.
using (Aes aesAlg = Aes.Create())
{
aesAlg.Padding = PaddingMode.PKCS7;
aesAlg.Key = Key;
aesAlg.IV = IV;
// Create a decrytor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key
, aesAlg.IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt
, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(
csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
swEncrypt.Close();
}
csEncrypt.Close();
msEncrypt.Close();
encrypted = msEncrypt.ToArray();
//csEncrypt.FlushFinalBlock(); causes an exception saying it was already called
}
}
}
Here is a sample of code I use to test the ecnryption. Performs correctly, but only once...
The key and IV are converted into Unicode string so that the user is able to save it and use it later for decryption.
private void button7_Click(object sender, EventArgs e)
{
string aesKey = "";
string aesIV = "";
string ciphered = "";
string deciphered = "";
using (Aes myAes = Aes.Create())
{
myAes.GenerateKey();
myAes.GenerateIV();
aesKey = Encoding.Unicode.GetString(myAes.Key);
aesIV = Encoding.Unicode.GetString(myAes.IV);
ciphered = Encoding.Unicode.GetString(EncryptStringToBytes_Aes(".ahoj.", myAes.Key, myAes.IV));
byte[] deKey = Encoding.Unicode.GetBytes(aesKey);
byte[] deIv = Encoding.Unicode.GetBytes(aesIV);
deciphered = DecryptStringFromBytes_Aes(Encoding.Unicode.GetBytes(ciphered), deKey, deIv);
MessageBox.Show("key: " + aesKey + "\niv: " + aesIV + "\ndekey: " + Encoding.Unicode.GetString(deKey) + "\ndeIv: " + Encoding.Unicode.GetString(deIv) + "\nDeciphered: " + deciphered);
}
}
Instead of using GetBytes and GetString from the unicode encoding, I would recommend base 64 encoding the bytes.
You can do base 64 encoding using Convert.ToBase64String() and Convert.FromBase64String.
One problem with just getting the unicode string from a generated byte array is that there is no guarantee that all of the characters are printable characters. For example, if you have a 0 in the byte array, that will be a null control character.
I recently ran into this myself. I am making use of the 'using' statements in your first code block but I never call .Close() and I am not running into the issue of only being able to run once.
To solve issues with padding on decrypt and issue of non-printable characters, I am explicitly setting the Padding as you did in the first code block but I am using Encoding.Default.GetBytes(cipherText); and the GetString method of the same encoding so it uses Window's default Extended ASCII encoding so it will recognize all the characters.
EDIT: Added my hash code to the bottom of this.
I am having some problems creating a message integrity key for a solution I am creating. In order for this to be correct I need to use the following settings.
Mode: ECB
KeySize: 256
BlockSize: 128
Padding: PKCS7
I am using a 32 byte key which is generated from a file and also a blank IV as I understand ECB does not require one.
My problem I am expecting a 48 byte output from this before the encoding however I am receiving a 64 byte output.
I have shown some code below about how am I am trying to achieve this but I am not having much success.
public static string Encrypt(string hash) {
// Create a new instance of the AesManaged
// class. This generates a new key and initialization
// vector (IV).
using (AesManaged myAes = new AesManaged()) {
myAes.Key = File.ReadAllBytes("keyfile");
myAes.Mode = CipherMode.ECB;
myAes.IV = new byte[16] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
myAes.KeySize = 256;
myAes.BlockSize = 128;
myAes.Padding = PaddingMode.PKCS7;
// Encrypt the string to an array of bytes.
byte[] encrypted = EncryptStringToBytes_Aes(hash, myAes.Key, myAes.IV);
// Decrypt the bytes to a string.
string roundtrip = DecryptStringFromBytes_Aes(encrypted, myAes.Key, myAes.IV);
//Display the original data and the decrypted data.
Console.WriteLine("Original: {0}", hash);
Console.WriteLine("Round Trip: {0}", roundtrip);
// Encode
string encoded = Convert.ToBase64String(encrypted);
Console.WriteLine("Encoded: {0}", encoded);
return encoded;
}
}
static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV) {
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("Key");
byte[] encrypted;
// Create an AesManaged object
// with the specified key and IV.
using (AesManaged aesAlg = new AesManaged()) {
aesAlg.Key = Key;
aesAlg.IV = IV;
// Create a decrytor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream()) {
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) {
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt)) {
//Write all data to the stream.
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
// Return the encrypted bytes from the memory stream.
return encrypted;
}
static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key, byte[] IV)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("Key");
// Declare the string used to hold
// the decrypted text.
string plaintext = null;
// Create an AesManaged object
// with the specified key and IV.
using (AesManaged aesAlg = new AesManaged())
{
aesAlg.Key = Key;
aesAlg.IV = IV;
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
return plaintext;
}
public static string getHashSha256(string text) {
byte[] bytes = Encoding.UTF8.GetBytes(text);
SHA256Managed hashstring = new SHA256Managed();
byte[] hash = hashstring.ComputeHash(bytes);
string hashString = string.Empty;
foreach (byte x in hash) {
hashString += String.Format("{0:x2}", x);
}
return hashString;
}
PKCS #7 padding is defined such that padding is added in all cases. When the plaintext is a multiple of the block size, a whole block of padding is added. This is why the ciphertext is 64 bytes long when the plaintext is 48 bytes long.
I have used this example as a base, to read and write an encrypted cookie. Problem is that the decrypted string that gets returned contains invalid characters. i.e. the cookie value is
'MyValue'
and what gets returned is
Z!������3z�^��
This is the code I use:
protected void Button1_Click(object sender, EventArgs e)
{
HttpCookie myCookie = new HttpCookie("MyCookie");
string valString = "MyValue";
string keyAsString = "BJF8hXsXce7dhCWjGICNrnq1Gc8mWyMlODbiYvXTXCo=";
byte[] myKey = Convert.FromBase64String(keyAsString);
// Create a new instance of the AesManaged
// class. This generates a new key and initialization
// vector (IV).
using (AesManaged myAes = new AesManaged())
{
//Set default values as padding mode and ciphermode not supported in Silverlight
byte[] encrypted = EncryptStringToBytes_Aes(valString, myKey, myAes.IV);
myCookie.Value = Convert.ToBase64String(encrypted, 0, (int)encrypted.Length);
string roundtrip = DecryptStringFromBytes_Aes(Convert.FromBase64String(myCookie.Value), myAes.Key, myAes.IV);
}
//
myCookie.Expires = DateTime.Now.AddDays(1d);
Response.Cookies.Add(myCookie);
}
And the encryption/decryption functions are:
static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("Key");
byte[] encrypted;
// Create an AesManaged object
// with the specified key and IV.
using (AesManaged aesAlg = new AesManaged())
{
aesAlg.Key = Key;
aesAlg.IV = IV;
aesAlg.Mode = CipherMode.ECB;
// Create a decryptor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
// Return the encrypted bytes from the memory stream.
return encrypted;
}
static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key, byte[] IV)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("Key");
// Declare the string used to hold
// the decrypted text.
string plaintext = null;
// Create an AesManaged object
// with the specified key and IV.
using (AesManaged aesAlg = new AesManaged())
{
aesAlg.Key = Key;
aesAlg.IV = IV;
aesAlg.Padding = PaddingMode.None;
aesAlg.Mode = CipherMode.ECB;
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
return plaintext;
}
Looks like some sort of encoding issue. At first I thought the problem was reading the cookie value itself. But even if I try to decrypt the value just encrypted i.e.
string roundtrip = DecryptStringFromBytes_Aes(encrypted, myAes.Key,
myAes.IV);
I still get the same issue.
Not sure if this will help but the main goal is to just READ the cookie. Initially, the cookie will get created from a 3rd party PHP app using a shared key (hence I used the ECB CipherMode). This code is just a sample to make sure that I can read encrypted cookies.