I'm attempting to write C# implementation for AES CBC encryption of messages. The goal is to "properly" encrypt a message in C# so that the C implementation could properly decrypt it.
The C decryption implementation looks like the following (using openssl):
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new())) {
handleErrors();
}
if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, (unsigned char*)key, (unsigned char*)iv)) {
handleErrors();
}
if(1 != EVP_DecryptUpdate(ctx, (unsigned char*)plaintext, &len, (unsigned char*)encrypted_text, encrypted_text_len)) {
handleErrors();
}
plaintext_len = len;
if(1 != EVP_DecryptFinal_ex(ctx, (unsigned char*)plaintext + len, &len)) {
//Error happens here...
}
I get the following error:
error: digital envelope routines:EVP_DecryptFinal_ex:wrong final block length:evp_enc.c:518:
C# code:
static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV)
{
byte[] encrypted;
// Create an Aes object
// with the specified key and IV.
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = Key;
aesAlg.IV = IV;
aesAlg.Mode = CipherMode.CBC;
// 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;
}
I have tried all of the padding modes, no luck. Any ideas of what the issue could be?
The error indicates that encrypted_text_len % 16 != 0.
You should double check that you aren't getting an accidental newline into your buffer if you're reading from a file.
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.
We have implemented AES encryption in our project. And it works fine.
But, if the user tampers the byte[] then the Decrypt function returns a wrong plain text with different symbols like � in it.
We want to handle this case by determining that the data is tampered.
Please find below the code of Decrypt function:
public static string Decrypt(string encryptedText)
{
try
{
// First convert the base64 string to byte[].
var cipherText = Convert.FromBase64String(encryptedText);
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
string plaintext = null;
// Create an Aes object
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = Encoding.ASCII.GetBytes("abc");
aesAlg.IV = Encoding.ASCII.GetBytes("xyz");
// Create a decryptor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
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
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
return plaintext;
}
catch (Exception ex)
{
return null;
}
}
Please help me to solve my issue.
Thanks!
I have a program which stores encrypted text data. Whenever new data is added, the encrypted data is loaded from file, decrypted, the new string data is appended, and finally the data is re-encrypted and saved to disk. This used to work until recently, now however I get a CryptographicException: Padding is invalid and cannot be removed when decrypting the loaded data. This is the code I use to encrypt/decrypt the data:
public static byte[] Encrypt(string text, byte[] key) {
byte[] encrypted;
byte[] IV;
using (var aes = Aes.Create()) {
aes.Key = key;
aes.GenerateIV();
IV = aes.IV;
aes.Mode = CipherMode.CBC;
var encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
using (var msEncrypt = new MemoryStream())
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) {
using (var swEncrypt = new StreamWriter(csEncrypt)) {
swEncrypt.Write(text);
}
encrypted = msEncrypt.ToArray();
}
}
// return plaintext IV and encrypted text payload concatenated
return IV.Concat(encrypted).ToArray();
} // Encrypt()
public static string Decrypt(byte[] bytes, byte[] key) {
string plaintext = null;
using (var aes = Aes.Create()) {
aes.Key = key;
// split iv and encryped cyphertext
byte[] IV = new byte[aes.BlockSize / 8];
byte[] cipherText = new byte[bytes.Length - IV.Length];
Array.Copy(bytes, IV, IV.Length);
Array.Copy(bytes, IV.Length, cipherText, 0, cipherText.Length);
aes.IV = IV;
aes.Mode = CipherMode.CBC;
var decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
using (var msDecrypt = new MemoryStream(cipherText))
using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
using (var srDecrypt = new StreamReader(csDecrypt)) {
plaintext = srDecrypt.ReadToEnd();
// !!! EXCEPTION HAPPENS HERE !!!
}
}
return plaintext;
}
The encrypted byte[] array is read/written using plain File.ReadAllBytes / File.WriteAllBytes.
I tried to change the the code to read byte by byte until an exception occurs, which gave me the decrypted text minus 16 bytes. However, only the first third contained valid text, the rest was a few garbled bytes, followed by a (equally garbled) 16 byte sequence, repeated over and over. This makes me suspect that some kind of corruption occurred during a previous save operation.
Any help would be greatly appreciated, regarding to recovering the data (if possible) and pointing out problems/bugs in the encryption/decryption code (if any).
I have been tasked with creating an internal document management system at my place of work. A requirement of the task is to encrypt documents imported into the system and only decrypt them when request by the end user. Also, the end user wont know the password/key for decryption, the system must fully handle the encryption and decryption on its own.
I wanted to use AES (no real reason, just seemed like a good option) so I started looking into how I could generate and store secure keys for AES. I couldn't find much in the way of implementation methods, just a lot of what not to do. The only decent way I found was using .NET Key Containers (https://learn.microsoft.com/en-us/dotnet/standard/security/how-to-store-asymmetric-keys-in-a-key-container) but its intended for asymmetric keys.
So I started playing with it and below is a working sample of using RSA in combination with AES:
public static byte[] Encrypt(byte[] data, byte[] salt)
{
byte[] encrypted;
Rfc2898DeriveBytes deriveBytes;
// Sanity
if (data == null || data.Length <= 0)
throw new ArgumentNullException("data");
if (salt == null || salt.Length <= 0)
throw new ArgumentNullException("salt");
// Create AES object
using (Aes aes = Aes.Create())
{
deriveBytes = new Rfc2898DeriveBytes(GetKeyFromContainer(), salt, MAX_ITERATIONS);
aes.Key = deriveBytes.GetBytes(32);
aes.IV = salt;
ICryptoTransform cryptoTransform = aes.CreateEncryptor(aes.Key, aes.IV);
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Write))
{
cryptoStream.Write(data, 0, data.Length);
}
encrypted = memoryStream.ToArray();
}
}
return encrypted;
}
public static byte[] Decrypt(byte[] data, byte[] salt)
{
byte[] decrypted;
Rfc2898DeriveBytes deriveBytes;
// Sanity
if (data == null || data.Length <= 0)
throw new ArgumentNullException("data");
if (salt == null || salt.Length <= 0)
throw new ArgumentNullException("salt");
// Create AES object
using (Aes aes = Aes.Create())
{
deriveBytes = new Rfc2898DeriveBytes(GetKeyFromContainer(), salt, MAX_ITERATIONS);
aes.Key = deriveBytes.GetBytes(32);
aes.IV = salt;
ICryptoTransform cryptoTransform = aes.CreateDecryptor(aes.Key, aes.IV);
using (MemoryStream memoryStream = new MemoryStream(data))
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Read))
{
using (StreamReader streamReader = new StreamReader(cryptoStream))
{
decrypted = Encoding.Default.GetBytes(streamReader.ReadToEnd());
}
}
}
}
return decrypted;
}
private static byte[] GetKeyFromContainer()
{
CspParameters parameters;
RSACryptoServiceProvider rsaServiceProvider;
parameters = new CspParameters();
parameters.KeyContainerName = KEY_CONTAINER_NAME;
rsaServiceProvider = new RSACryptoServiceProvider(parameters);
return Encoding.Default.GetBytes(rsaServiceProvider.ToXmlString(true));
}
So on to the questions:
How bad is it to use RSA to generate an asymmetric key to then be used by AES? What are the weaknesses, if any, to this strategy?
Is there a better method/algorithm for encrypting/decrypting the imported documents (not AES)?
I am somewhat inexperienced when it comes to cryptography, so any assistance or educational material is very much appreciated.
I use ECDiffieHellmanCng for exchange of public keys and then AES for encrypting/decrypting.
Sometimes the decryption works, other times I get the following error in decryption method: Padding is invalid and cannot be removed.
Where is the cause of this?
Here is the code:
private void Encryption(byte[] key, byte[] unencryptedMessage,out byte[] encryptedMessage, out byte[] iv) // encryption funkcija
{
using (Aes aes = new AesManaged())
{
aes.Key = key;
//aes.GenerateIV();
iv = aes.IV;
aes.Padding = PaddingMode.PKCS7;
// Encrypt the message
using (MemoryStream ciphertext = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ciphertext, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(unencryptedMessage, 0, unencryptedMessage.Length);
cs.Close();
}
encryptedMessage = ciphertext.ToArray();
}
}
}
private void Decryption(byte[] encryptedMessage, byte[] iv, out byte[] decryptedMessage)
{
using (Aes aes = new AesManaged())
{
aes.Key = receiversKey;
aes.IV = iv;
aes.Padding = PaddingMode.PKCS7;
// Decrypt the message
using (MemoryStream decryptedBytes = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(decryptedBytes, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(encryptedMessage, 0, encryptedMessage.Length);
cs.Close();
}
decryptedMessage = decryptedBytes.ToArray();
}
}
}
Since you're already using the same padding mode for both encryption and decryption, the most likely causes of invalid padding error are:
Different keys that are used for encryption and decryption.
Invalid encrypted message passed to Decryption() method. You could mistakenly pass an empty string or non-encrypted data.
If this does not help, please provide the code that calls Encryption() and Decryption() methods and handles the key used in both cases. It's required because those methods itself looks ok, the most likely problem is in passed arguments.