I'm using C# .Net 4.0. I generate the key and IV(initialization vector) using the rijindael class. I then write both of them to a file. The IV is always correct when I read the file, but the last byte of the key is always zero. I look at the key before writing to the file and it is fine, reading it back in the last byte is always zero.
I have tried setting the padding mode to the various choices and they don't make a difference.
using (Rijndael myRijndael = Rijndael.Create())
{
//Create keys
try
{
byte[] key;
byte[] iv;
key = new byte[32];
iv = new byte[16];
theKeys.Key = myRijndael.Key;
theKeys.IV = myRijndael.IV;
FileStream fs = File.Create("yyy.txt");
fs.Write(theKeys.Key, 0, theKeys.Key.Length);
fs.Flush();
fs.Close();
FileStream ts = File.Open("yyy.txt", FileMode.Append);
ts.Write(theKeys.IV, 0, theKeys.IV.Length);
ts.Flush();
ts.Close();
FileStream ms = File.Open("yyy.txt", FileMode.Open);
ms.Read(key, 0, 31);
ms.Seek(32, 0);
ms.Read(iv, 0, 16);
ms.Flush();
ms.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
// Save key and IV
using (var rijndael = new RijndaelManaged())
using (var writer = new BinaryWriter(File.Create("yyy.dat")))
{
writer.Write(rijndael.Key, 0, 32);
writer.Write(rijndael.IV, 0, 16);
}
// Restore key and IV
using (var rijndael = new RijndaelManaged())
using (var reader = new BinaryReader(File.OpenRead("yyy.dat")))
{
rijndael.Key = reader.ReadBytes(32);
rijndael.IV = reader.ReadBytes(16);
}
The problem is that you are only asking to read in 31 bytes:
ms.Read(key, 0, 31);
This should be changed to:
ms.Read(key, 0, 32);
Also, this can be much more efficient (leaving out use of theKeys in this example and just using the local vars):
using (Rijndael myRijndael = Rijndael.Create())
{
//Create keys
try
{
byte[] key;
byte[] iv;
key = new byte[32];
iv = new byte[16];
key = myRijndael.Key;
iv = myRijndael.IV;
using (FileStream fs = File.Create("yyy.txt"))
{
fs.Write(key, 0, key.Length);
fs.Write(iv, 0, iv.Length);
}
using (FileStream ms = File.Open("yyy.txt", FileMode.Open))
{
key = new byte[32];
iv = new byte[16];
ms.Read(key, 0, 32);
ms.Read(iv, 0, 16);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Related
I want to encrypt/ decrypt my access token using Aes. Encryption part is successful working. But my problem is when decrypting the encrypted access token following error is occurred
Padding is invalid and cannot be removed.
Following line is throwing an exception:
using (var srDecrypt = new StreamReader(csDecrypt))
{
result = srDecrypt.ReadToEnd();
}
Can anyone tell me what I can do to solve this issue? (as a console application)
class Program
{
private static string keyString = "E546C8DF278CD5931069B522E695D4F2";
static void Main(string[] args)
{
var text = "a16df7367e9eca23ac5e071dc4449a7a";
Console.WriteLine(EncryptString(text)); ;
Console.WriteLine(DecryptString(EncryptString(text)));
Console.ReadLine();
}
public static string EncryptString(string text)
{
var key = Encoding.UTF8.GetBytes(keyString);
using (var aesAlg = Aes.Create())
{
using (var encryptor = aesAlg.CreateEncryptor(key, aesAlg.IV))
{
using (var msEncrypt = new MemoryStream())
{
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
using (var swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(text);
}
var iv = aesAlg.IV;
var decryptedContent = msEncrypt.ToArray();
var result = new byte[iv.Length + decryptedContent.Length];
Buffer.BlockCopy(iv, 0, result, 0, iv.Length);
Buffer.BlockCopy(decryptedContent, 0, result, iv.Length, decryptedContent.Length);
return Convert.ToBase64String(result);
}
}
}
}
public static string DecryptString(string cipherText)
{
var fullCipher = Convert.FromBase64String(cipherText);
var iv = new byte[16];
var cipher = new byte[16];
Buffer.BlockCopy(fullCipher, 0, iv, 0, iv.Length);
Buffer.BlockCopy(fullCipher, iv.Length, cipher, 0, iv.Length);
var key = Encoding.UTF8.GetBytes(keyString);
using (var aesAlg = Aes.Create())
{
using (var decryptor = aesAlg.CreateDecryptor(key, iv))
{
string result;
using (var msDecrypt = new MemoryStream(cipher))
{
using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (var srDecrypt = new StreamReader(csDecrypt))
{
result = srDecrypt.ReadToEnd();
}
}
}
return result;
}
}
}
}
You should change it
var iv = new byte[16];
var cipher = new byte[16];
Buffer.BlockCopy(fullCipher, 0, iv, 0, iv.Length);
Buffer.BlockCopy(fullCipher, iv.Length, cipher, 0, iv.Length);
to
var iv = new byte[16];
var cipher = new byte[fullCipher.Length - 16]; //Calculate correct byte size
Buffer.BlockCopy(fullCipher, 0, iv, 0, iv.Length);
Buffer.BlockCopy(fullCipher, iv.Length, cipher, 0, cipher.Length); //Change destination count of copied bytes
Cipher array size can't be 16 bytes by default you should calculate it.
I am using AES - Standard SymmetricAlgorithm, for Encrypting and Decrypting string. String is encrypting successfully but when it comes to decrypt the compiler gives me the exception i.e
“Padding is invalid and cannot be removed”.
I have created a demo console application for testing, please have a look on below code.
The Main Method:
static void Main(string[] args)
{
var content = "5466160057107706";
var key = "E546C8DF278CD5931069B522E695D4F2";
var encrypted = EncryptString(content, key);
Console.WriteLine(encrypted);
var decrypted = DecryptString(encrypted, key);
Console.WriteLine(decrypted);
Console.ReadLine();
}
Method added for Encryption:
public static string EncryptString(string text, string keyString)
{
var key = Encoding.UTF8.GetBytes(keyString);
using (var aesAlg = Aes.Create())
{
using (var encryptor = aesAlg.CreateEncryptor(key, aesAlg.IV))
{
using (var msEncrypt = new MemoryStream())
{
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
using (var swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(text);
}
var iv = aesAlg.IV;
var decryptedContent = msEncrypt.ToArray();
var result = new byte[iv.Length + decryptedContent.Length];
Buffer.BlockCopy(iv, 0, result, 0, iv.Length);
Buffer.BlockCopy(decryptedContent, 0, result, iv.Length, decryptedContent.Length);
return Convert.ToBase64String(result);
}
}
}
}
Method added for Decryption:
public static string DecryptString(string cipherText, string keyString)
{
var fullCipher = Convert.FromBase64String(cipherText);
var iv = new byte[16];
var cipher = new byte[16];
Buffer.BlockCopy(fullCipher, 0, iv, 0, iv.Length);
Buffer.BlockCopy(fullCipher, iv.Length, cipher, 0, iv.Length);
var key = Encoding.UTF8.GetBytes(keyString);
using (var aesAlg = Aes.Create())
{
using (var decryptor = aesAlg.CreateDecryptor(key, iv))
{
string result;
using (var msDecrypt = new MemoryStream(cipher))
{
using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (var srDecrypt = new StreamReader(csDecrypt))
{
result = srDecrypt.ReadToEnd();
}
}
}
return result;
}
}
}
Here is the Error Snap which occurs in the DecryptString() method:
Any advice, how to solve this issue?
Clue:
var cipher = new byte[16];
Why are you assuming your cipher would be ONLY 16 bytes ? What if it is more than this ?
In fact, if I run this program and debug, I see that your cipher is 32 bytes.
So, the following 2 line changes makes it work:
var cipher = new byte[32];
Buffer.BlockCopy(fullCipher, iv.Length, cipher, 0, cipher.Length);
In any case, you would need to dynamically determine your size of cipher.
I wrote two programs in C#. One does the encryption, and the other one does the decryption. The decryption program throws exception of "The input data is not a complete block" with data from the encryption program. However the decryption program works fine with the encrypted data from a Unix encryption program, using PKCS5_PBKDF2_HMAC_SHA1().
Encrypted data is base 64 encoded, and saved in a text file. The first 8 bytes is a salt, the next 16 bytes is an IV, and the rest is the application text.
I would appreciate very much if anyone could help.
public static string DecryptText(string cipherData)
{
if (string.IsNullOrEmpty(_passwd))
return null;
var decodedBytes = Convert.FromBase64String(cipherData);
// First 8 bytes contain the salt used for key derivation. Use the password from the passwd.dat
// file and the salt to derive the key used to encode the credential.
//
var salt = new byte[8];
Buffer.BlockCopy(decodedBytes, 0, salt, 0, 8);
var derivedBytes = new Rfc2898DeriveBytes(_passwd, salt, 1000);
var key = derivedBytes.GetBytes(32);
// Next 16 bytes contain the initialization vector used to encrypt
//
var ivBytes = new byte[16];
Buffer.BlockCopy(decodedBytes, 8, ivBytes, 0, ivBytes.Length);
// Remaining bytes contain the credential cipher text
//
var cipherBytes = new byte[decodedBytes.Length - 8 - 16];
Buffer.BlockCopy(decodedBytes, 8 + 16, cipherBytes, 0, cipherBytes.Length);
string decryptedData = null;
try
{
using (var aes = new AesCryptoServiceProvider())
{
aes.Key = key;
aes.IV = ivBytes;
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(cipherBytes, 0, cipherBytes.Length);
cs.Close();
}
decryptedData = Encoding.UTF8.GetString(ms.ToArray());
}
}
}
catch (Exception ex)
{
Console.Write("Caught exception while decryption: {0}: ", ex.Message);
}
return decryptedData;
}
public static string EncryptText(string plainData)
{
if (string.IsNullOrEmpty(_passwd))
return null;
var rfc2898db = new Rfc2898DeriveBytes(_passwd, 8, 1000);
byte[] salt = new byte[8];
Buffer.BlockCopy(rfc2898db.Salt, 0, salt, 0, 8);
byte[] key = new byte[32];
Buffer.BlockCopy(rfc2898db.GetBytes(32), 0, key, 0, 32);
string cipherData;
try
{
var aes = new AesCryptoServiceProvider
{
Key = key,
KeySize = 256,
BlockSize = 128,
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7
};
aes.GenerateIV();
byte[] encrypted;
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
ms.Write(aes.IV, 0, aes.IV.Length);
ms.Write(salt, 0, 8);
cs.Write(Encoding.UTF8.GetBytes(plainData), 0, plainData.Length);
cs.Close();
}
encrypted = ms.ToArray();
}
byte[] encryptedBytes = new byte[SaltLength + IvLength + encrypted.Length];
Buffer.BlockCopy(salt, 0, encryptedBytes, 0, SaltLength);
Buffer.BlockCopy(aes.IV, 0, encryptedBytes, SaltLength, IvLength);
Buffer.BlockCopy(encrypted, 0, encryptedBytes, SaltLength + IvLength, encrypted.Length);
cipherData = Convert.ToBase64String(encryptedBytes);
}
catch (Exception ex)
{
Console.Write("Caught exception while encryption: {0}", ex.Message);
return null;
}
return cipherData;
}
I am performing independent encrypt-decrypt (1st app performs enc 2nd decrypts)
While decryption I either get "Padding invalid" or "Length of data to decrypt is invalid" error.Any help is appreciated thanks
My encryption code:
static void EncryptFile(string file, string password)
{
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
byte[] salt = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
passwordBytes = SHA256.Create().ComputeHash(passwordBytes);
RijndaelManaged AES = new RijndaelManaged();
AES.KeySize = AES.LegalKeySizes[0].MaxSize;
AES.BlockSize = AES.LegalBlockSizes[0].MaxSize;
AES.Padding = PaddingMode.Zeros;
using (var key = new Rfc2898DeriveBytes(passwordBytes, salt, 1000))
{
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CFB;
}
using (FileStream fsCrypt = new FileStream(file + ".ecc", FileMode.Create))
{
fsCrypt.Write(salt, 0, salt.Length);
}
int bytesToRead = 128 * 1024 * 1024; // 128MB
byte[] buffer = new byte[bytesToRead]; // create the array that will be used encrypted
long fileOffset = 0;
int read = 0;
bool allRead = false;
while (!allRead)
{
using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read))
{
fs.Seek(fileOffset, SeekOrigin.Begin); // continue reading from where we were...
read = fs.Read(buffer, 0, bytesToRead); // read the next chunk
}
if (read == 0)
allRead = true;
else
fileOffset += read;
using (FileStream fsCrypt = new FileStream(file + ".ecc", FileMode.Open)) // automatically dispose fsCrypt
{
using (CryptoStream cs = new CryptoStream(fsCrypt, AES.CreateEncryptor(), CryptoStreamMode.Write))
{
fsCrypt.Seek(fileOffset, SeekOrigin.End);
cs.FlushFinalBlock();
cs.Write(buffer, 0, read);
}
}
}
}
and My decryption code:
public void DecryptFile(string file, string password)
{
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
byte[] salt = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
passwordBytes = SHA256.Create().ComputeHash(passwordBytes);
RijndaelManaged AES = new RijndaelManaged();
AES.KeySize = AES.LegalKeySizes[0].MaxSize;
AES.BlockSize = AES.LegalBlockSizes[0].MaxSize;
AES.Padding = PaddingMode.Zeros;
using (var key = new Rfc2898DeriveBytes(passwordBytes, salt, 1000))
{
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CFB;
}
string extension = System.IO.Path.GetExtension(file);
string result = file.Substring(0, file.Length - extension.Length);
using (FileStream destination = new FileStream(result, FileMode.CreateNew, FileAccess.Write, FileShare.None))
{
using (CryptoStream cryptoStream = new CryptoStream(destination, AES.CreateDecryptor(), CryptoStreamMode.Write))
{
try
{
using (FileStream source = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
source.CopyTo(cryptoStream);
}
}
catch (CryptographicException exception)
{
if (exception.Message == "Padding is invalid and cannot be removed.")
throw new ApplicationException("Universal Microsoft Cryptographic Exception (Not to be believed!)", exception);
else
throw;
}
}
}
}
The following calls are executed in the wrong order:
cs.FlushFinalBlock();
and
cs.Write(buffer, 0, read);
FlushFinalBlock should always come last (it will be automatically called when the stream is closed though, so it should be OK if you don't close the underlying stream first). FlushFinalBlock should certainly never be called in a (while) loop.
The buffer handling is not correct: the streams should not be closed and opened all the time. Instead a block of bytes should be read, then written to the crypto stream. The using statements should be outside the while loop.
For CFB mode PaddingMode.PKCS7 should be set. Padding is not required at all for CFB. Unfortunately .NET seems to have a buggy implementation that does require padding to be used in combination to the streams.
I need to encrypt an image, return the string of the encrypted data, then decrypt it
Here's my encryption code :
string plainText = ASCIIEncoding.ASCII.GetString(Imagebytes);
byte[] encrypted;
byte[] key = Encoding.UTF8.GetBytes("M02cnQ51Ji97vwT4");;
// Create an AesCryptoServiceProvider object
using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
{
aesAlg.Key = key;
aesAlg.BlockSize = 128;
// 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();
}
}
}
using (var aesAlg = new AesManaged())
{
aesAlg.Key = new UTF8Encoding().GetBytes("M02cnQ51Ji97vwT4");
aesAlg.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
return UTF8Encoding.UTF8.GetString(encryptor.TransformFinalBlock(Imagebytes, 0, Imagebytes.Length)).Length;
}
My decryption work fine ( because i can receive image / video perfectly )
here's the code:
const string BLOB_KEY = "TTAyY25RNTFKaTk3dndUNA==";
using (RijndaelManaged rm = new RijndaelManaged())
{
rm.Mode = CipherMode.ECB;
rm.Key = Convert.FromBase64String(BLOB_KEY);
rm.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
rm.Padding = PaddingMode.Zeros;
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, rm.CreateDecryptor(),
CryptoStreamMode.Write))
{
cs.Write(image, 0, image.Length);
return ms.ToArray();
}
}
}
What's wrong with my encryption code ?
Your very initial line of code is already wrong:
string plainText = ASCIIEncoding.ASCII.GetString(Imagebytes);
An image is not a string, and plaintext is not necessarily a string either. Both consist of bytes. So you should not be using a StreamWriter either, just a normal stream.
It is likely that data is lost during conversion.
Furthermore, you are writing to a decryption stream and you are using ECB mode at one side and CBC mode at the other.
I would strongly advice you to read into the material and start over.
Thank you, i've changed my code to :
var aesAlg = new AesManaged
{
KeySize = 128,
Key = key,
BlockSize = 128,
Mode = CipherMode.ECB,
Padding = PaddingMode.Zeros,
IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
return encryptor.TransformFinalBlock(Imagebytes, 0, Imagebytes.Length);
And it works fine !