I am trying to encrypt a text in C# and then trying to decrypt the data in Python but I am unable to decrypt the C# encrypted data in python. I think maybe I am unable to get the same IV as I am using in C#. I don't know where I am getting wrong.
class AesEncryption
{
public static void Main()
{
var original = "Here is some data to encrypt!";
using (var myAes = Aes.Create())
{
var key = "My private key";
myAes.Key = Encoding.ASCII.GetBytes(key);
myAes.Mode = CipherMode.CBC;
myAes.IV = new byte[16];
// Encrypt the string to an array of bytes.
var encrypted = EncryptStringToBytes_Aes(original, myAes.Key, myAes.IV);
Console.WriteLine("Encrypted: {0}", encrypted);
// Decrypt the bytes to a string.
var roundtrip =
DecryptStringFromBytes_Aes(System.Convert.FromBase64String(encrypted), myAes.Key, myAes.IV);
//Display the original data and the decrypted data.
Console.WriteLine("Original: {0}", original);
Console.WriteLine("Round Trip: {0}", roundtrip);
}
}
private static string EncryptStringToBytes_Aes(string plainText, byte[] key, byte[] iv)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException(nameof(plainText));
if (key == null || key.Length <= 0)
throw new ArgumentNullException(nameof(key));
if (iv == null || iv.Length <= 0)
throw new ArgumentNullException(nameof(iv));
// Create an Aes object
// with the specified key and IV.
using var aesAlg = Aes.Create();
aesAlg.Key = key;
aesAlg.IV = iv;
// Create an encryptor to perform the stream transform.
var encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption.
using var msEncrypt = new MemoryStream();
using var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
using (var swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
var encrypted = msEncrypt.ToArray();
// Return the encrypted bytes from the memory stream.
return Convert.ToBase64String(encrypted);
}
private static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] key, byte[] iv)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException(nameof(cipherText));
if (key == null || key.Length <= 0)
throw new ArgumentNullException(nameof(key));
if (iv == null || iv.Length <= 0)
throw new ArgumentNullException(nameof(iv));
// Declare the string used to hold
// the decrypted text.
string plaintext;
// Create an Aes object
// with the specified key and IV.
using (var aesAlg = Aes.Create())
{
aesAlg.Key = key;
aesAlg.IV = iv;
// Create a decryptor to perform the stream transform.
var decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for decryption.
using (var msDecrypt = new MemoryStream(cipherText))
{
using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (var srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
return plaintext;
}
}
I am using IV
iv = as new byte[16];
In the above code, I am checking what is the Encrypted text being generated during the process of encryption and decryption and trying to match that in my python encryption.
import base64
import binascii
import hashlib
from Crypto.Cipher import AES
def r_pad(payload, block_size=16):
length = block_size - (len(payload) % block_size)
return payload chr(length) * length
key = "My private key"
body = "Here is some data to encrypt!"
iv = binascii.unhexlify(16 * "00")
length = len(body)
encoded_key = hashlib.sha256(key.encode()).digest()
data_from_encryption = r_pad(body).encode('utf-8')
encrypted_data = AES.new(encoded_key, AES.MODE_CBC, iv).encrypt(data_from_encryption)
encrypted_data_to_base64_str = base64.b64encode(encrypted_data).decode('utf-8')
print("Encrypted data: ", encrypted_data_to_base64_str)
bytes_to_decrypt = base64.decodebytes(encrypted_data_to_base64_str.encode())
decrypted_data = AES.new(encoded_key, AES.MODE_CBC, iv).decrypt(bytes_to_decrypt)[:length]
decode_str = decrypted_data.decode('utf-8')
print(decode_str)
I tried to user different value of IV
iv = binascii.unhexlify(16 * "00")
but can't get the same encrypted text in both the codes. I also know what r_pad function doing in python but if I don't user it Python raises Exception about my data not being padded according to 16 bit
Can anybody help and tell me where I am getting wrong?
CodePudding user response:
In the C# code, the key is the ASCII encoding of key
, but in the Python code it is the SHA-256 hash of key
.
So that the Python code produces the same ciphertext, simply replace:
encoded_key = key.encode('ascii')
Note the following issues:
- A static IV is insecure. Usually, a random IV is generated for each encryption and passed along with the ciphertext (usually concatenated).
- If the key is to be derived from a password, then a reliable key derivation function such as Argon2 or PBKDF2 should be used instead of a digest.
- PyCryptodome supports padding in a dedicated module: Crypto.Util.Padding