Invalid padding error when using AesCryptoServiceProvider in C# - c#

I've written a simple encryp/decrypt method in c# which uses the AES alg. When I try to encrypt and then decrypt a string with certain lengths like 4 or 7 characters, it works fine, with other lengths however It says that the padding is invalid and cannot be removed.
public static string Decrypt(string text)
{
Aes a = System.Security.Cryptography.AesCryptoServiceProvider.Create();
a.Padding = PaddingMode.PKCS7;
a.Key = Convert.FromBase64String("UDlArN63HCk15fHBski/zvaWiMZJi+jR1BADvVgenCU=");
a.IV = Convert.FromBase64String("xZG/eLY8eq0mQhUXvKbUDQ==");
var dc = a.CreateDecryptor();
byte[] encryptedBytes = Encoding.Unicode.GetBytes(text);
byte[] decryptedBytes = dc.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
return Encoding.Unicode.GetString(decryptedBytes);
}
public static string Encrypt(string text)
{
Aes a = System.Security.Cryptography.AesCryptoServiceProvider.Create();
a.Padding = PaddingMode.PKCS7;
a.Key = Convert.FromBase64String("UDlArN63HCk15fHBski/zvaWiMZJi+jR1BADvVgenCU=");
a.IV = Convert.FromBase64String("xZG/eLY8eq0mQhUXvKbUDQ==");
var dc = a.CreateEncryptor();
byte[] decryptedBytes = Encoding.Unicode.GetBytes(text);
byte[] encryptedBytes = dc.TransformFinalBlock(decryptedBytes, 0, decryptedBytes.Length);
return Encoding.Unicode.GetString(encryptedBytes);
}

Ciphertexts are binary data which might contain bytes that are not printable. If try to encode the byte array as a Unicode string, you will lose some bytes. It will be impossible to recover them during decryption.
If you actually want to handle the ciphertext as a string, you need to convert it into a textual representation like Base 64 or Hex.
// encryption
return Convert.ToBase64String(decryptedBytes);
// decryption
byte[] decryptedBytes = Convert.FromBase64String(text);

Related

PHP encryption not compatible with .NET/C# decryption (AES-256/CBC)

when I try to encrypt using openssl_encrypt PHP I get square spaces at the end decrypted data which is shown in attached image
My API response is getting failure due to getting extra characters during decryption done by .NET side..
How can i resolve this issue please help
C#
public static string Decrypt(String encryptedText, String VendorKey, String Token)
{
var encryptedBytes = Convert.FromBase64String(encryptedText);
return Encoding.UTF8.GetString(Decrypt(encryptedBytes, GetRijndaelManaged(VendorKey,Token)));
}
private static byte[] Decrypt(byte[] encryptedData, RijndaelManaged rijndaelManaged)
{
return rijndaelManaged.CreateDecryptor()
.TransformFinalBlock(encryptedData, 0, encryptedData.Length);
}
public static RijndaelManaged GetRijndaelManaged(String VendorKey, String Token)
{
var keyBytes = new byte[32];
var ivBytes = new byte[16];
var secretKeyBytes = Encoding.UTF8.GetBytes(VendorKey + Token);
Array.Copy(secretKeyBytes, keyBytes, Math.Min(keyBytes.Length, secretKeyBytes.Length));
var ivKeyBytes = Encoding.UTF8.GetBytes(VendorKey);
Array.Copy(ivKeyBytes, ivBytes, Math.Min(ivBytes.Length, ivKeyBytes.Length));
return new RijndaelManaged
{
Mode = CipherMode.CBC,
Padding = PaddingMode.Zeros,
KeySize = 256,
BlockSize = 128,
Key = keyBytes,
IV = ivKeyBytes
};
}
public static string Encrypt(String plainText, String VendorKey, String Token)
{
var plainBytes = Encoding.UTF8.GetBytes(plainText);
return Convert.ToBase64String(Encrypt(plainBytes, GetRijndaelManaged(VendorKey, Token)));
}
private static byte[] Encrypt(byte[] plainBytes, RijndaelManaged rijndaelManaged)
{
return rijndaelManaged.CreateEncryptor()
.TransformFinalBlock(plainBytes, 0, plainBytes.Length);
}
public static RijndaelManaged GetRijndaelManaged(String VendorKey, String Token)
{
var keyBytes = new byte[32];
var ivBytes = new byte[16];
var secretKeyBytes = Encoding.UTF8.GetBytes(VendorKey + Token);
Array.Copy(secretKeyBytes, keyBytes, Math.Min(keyBytes.Length, secretKeyBytes.Length));
var ivKeyBytes = Encoding.UTF8.GetBytes(VendorKey);
Array.Copy(ivKeyBytes, ivBytes, Math.Min(ivBytes.Length, ivKeyBytes.Length));
return new RijndaelManaged
{
Mode = CipherMode.CBC,
Padding = PaddingMode.Zeros,
KeySize = 256,
BlockSize = 128,
Key = keyBytes,
IV = ivKeyBytes
};
}
So can help me to resolve this issue
When using the sample data you provided, encryption with the .NET code:
string vendorKey = "0123456789012345";
string token = "012345";
string pt = #"{""prospectNo"":""SL1000000"",""paymentRequestDateFrom"":""2020-05-28"",""paymentRequestDateTo"":""2020-06-02"",""merchantTransactionId"":""7"",""callerReferenceNo"":""3""}";
string ct = Encrypt(pt, vendorKey, token);
Console.WriteLine(ct);
returns the following ciphertext:
g163a7jXmZKjH1J3RjC7xkPn5+PJWY6wTX9BgxiTY8hkYjsqImlCuvXOtZgUrrfLnwLy1QGUk6iylc/sInV/XJ9sypJ93tCvjRoj4s4RWGKTqUk3bY31JTM6QuYVclw4zNvyq2WUBCc+EMGGYtn5dBAvqiYdTqrJJTae67EZfgc4Fw5ormmf0rCYXQ2mn7mc1Jdg8v2r3LK9FYiwLEbhOA==
The PHP code below:
<?php
$cipher = "AES-256-CBC";
$array = json_encode(array(
"prospectNo"=> "SL1000000",
"paymentRequestDateFrom"=>"2020-05-28",
"paymentRequestDateTo"=>"2020-06-02",
"merchantTransactionId"=> "7",
"callerReferenceNo"=>"3"
)
);
$token = "012345";
$vendorKey = "0123456789012345";
$key = substr(str_pad($vendorKey . $token, 32, "\0"), 0, 32);
$iv = substr(str_pad($vendorKey, 16, "\0"), 0, 16);
$encrypted_data = openssl_encrypt(zeroPad($array, 16), $cipher, $key, OPENSSL_ZERO_PADDING, $iv);
print($encrypted_data . "\n");
function zeroPad($text, $bs) {
$pad = ($bs - strlen($text) % $bs) % $bs;
return ($pad > 0) ? $text . str_repeat("\0", $pad) : $text;
}
?>
gives the same ciphertext and is thus the PHP counterpart you are looking for, i.e. under the premise that the API can process the data encrypted by the .NET code, it must also process the data encrypted by the PHP code.
As expected, this ciphertext is decrypted into the correct plaintext by the .NET code. The hex encoded plaintext also reveals that the .NET code does not remove the padding bytes (note the 8 0x00 bytes at the end):
string vendorKey = "0123456789012345";
string token = "012345";
string ct = "g163a7jXmZKjH1J3RjC7xkPn5+PJWY6wTX9BgxiTY8hkYjsqImlCuvXOtZgUrrfLnwLy1QGUk6iylc/sInV/XJ9sypJ93tCvjRoj4s4RWGKTqUk3bY31JTM6QuYVclw4zNvyq2WUBCc+EMGGYtn5dBAvqiYdTqrJJTae67EZfgc4Fw5ormmf0rCYXQ2mn7mc1Jdg8v2r3LK9FYiwLEbhOA==";
string dt = Decrypt(ct, vendorKey, token);
Console.WriteLine("Plaintext: " + dt);
Console.WriteLine("Plaintext, hex: " + Convert.ToHexString(Encoding.UTF8.GetBytes(dt)));
with the output:
Plaintext: {"prospectNo":"SL1000000","paymentRequestDateFrom":"2020-05-28","paymentRequestDateTo":"2020-06-02","merchantTransactionId":"7","callerReferenceNo":"3"}
Plaintext, hex: 7B2270726F73706563744E6F223A22534C31303030303030222C227061796D656E74526571756573744461746546726F6D223A22323032302D30352D3238222C227061796D656E745265717565737444617465546F223A22323032302D30362D3032222C226D65726368616E745472616E73616374696F6E4964223A2237222C2263616C6C65725265666572656E63654E6F223A2233227D0000000000000000
The PHP code posted in this answer differs from your original PHP code essentially only in a more general derivation of $key and $iv (but this makes no difference for the vendorKey used here) and the padding. The original PHP code applied the default PKCS#7 padding used by openssl_encrypt(), while the current PHP code applies Zero padding.
Specifically, for the current plaintext, this means that the original PHP code padded with 0x0808080808080808, while the current PHP code pads with 0x0000000000000000. Since the .NET code does not remove the padding, the padding bytes are still present even when using the current PHP code (just with different values).

How to convert CryptoJS decryption code into C#?

I have this code in CryptoJS, inside browser:
var decrypt = function (cipherText) {
var key = "a_long_key_goes_here";
var iv = "initial_vector_goes_here";
key = CryptoJS.enc.Hex.parse(key);
iv = CryptoJS.enc.Hex.parse(iv);
var decrypted = CryptoJS.TripleDES.decrypt({
ciphertext: CryptoJS.enc.Hex.parse(cipherText)
}, key, {
iv: iv,
mode: CryptoJS.mode.CBC
});
var clearText = decrypted.toString(CryptoJS.enc.Utf8);
return clearText;
};
This code is not written by me. Also the cipherText come from another server that I have no access to. However, I have access to key and to iv.
I can decrypt that cipherText inside a browser's console. But I want to use these keys to decrypt that cipherText inside C# code. Here's the code I've written:
public void Desrypt()
{
ICryptoTransform decryptor;
UTF8Encoding encoder;
string key = "a_long_key_goes_here";
string iv = "initial_vector_goes_here";
var cipherText = "cipher_text_goes_here";
string clearText = "";
byte[] cipherBytes = FromHexString(cipherText);
using (Aes aes = Aes.Create())
{
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(key, new byte[] { });
aes.Key = pdb.GetBytes(32);
aes.IV = pdb.GetBytes(16);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(cipherBytes, 0, cipherBytes.Length);
cs.Close();
}
clearText = Encoding.Unicode.GetString(ms.ToArray());
}
}
return clearText;
}
public static byte[] FromHexString(string hexString)
{
var bytes = new byte[hexString.Length / 2];
for (var i = 0; i < bytes.Length; i++)
{
bytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
}
return bytes;
}
I have some problems though. I don't understand if I'm correctly decoding the given cipherText from hexadecimal or not. Also I can't instantiate Rfc2898DeriveBytes, because I don't know what the second parameter (salt) should be.
Also I don't know where should I use that iv I've gotten from the CryptoJS code.
Could you please help?
So that both codes are compatible, the following changes of the C# code are necessary:
The return type of the Decrypt method must be changed from void to string.
Key and IV have to be decoded hexadecimal like the ciphertext with FromHexString.
Instead of AES, TripleDES must be used.
Rfc2898DeriveBytes implements PBKDF2 and must not be applied (since the JavaScript code does not use PBKDF2 either).
The decrypted data must not be decoded with Encoding.Unicode (which corresponds to UTF16LE in .NET), but with Encoding.UTF8.
The C# code can handle 24 bytes keys (to support 3TDEA) and 16 bytes keys (to support the less secure 2TDEA). The posted CryptoJS code also handles these key sizes plus additionally 8 bytes keys (to support the least secure, DES compatible variant 1TDEA).
The following C# code decrypts a ciphertext generated with CryptoJS and 3TDEA:
public string Decrypt()
{
byte[] key = FromHexString("000102030405060708090a0b0c0d0e0f1011121314151617"); // 24 bytes (3TDEA)
byte[] iv = FromHexString("0001020304050607"); // 8 bytes
byte[] ciphertext = FromHexString("2116057c372e0e95dbe91fbfd148371b8e9974187b71e7c018de89c757280ad342d4191d29472040ee70d19015b025e1");
string plaintext = "";
using (TripleDES tdes = TripleDES.Create())
{
tdes.Key = key;
tdes.IV = iv;
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, tdes.CreateDecryptor(tdes.Key, tdes.IV), CryptoStreamMode.Write))
{
cs.Write(ciphertext, 0, ciphertext.Length);
}
plaintext = Encoding.UTF8.GetString(ms.ToArray());
}
}
return plaintext;
}
The decryption is also possible with the posted JavaScript code, which shows the functional equivalence of both codes.
Note: Since AES is more performant than TripleDES, AES should be used if possible.

Decrypting byte array with Rijndael - lost Bytes

I am writing a encrypted (Rijndael) byte array in a .txt file.
When I read it out, I get a byte[48]. As soon as i decrypt it, I get a byte[32].
Why am I losing bytes here? If I write the result in the Console, it also cuts at a specific point.
static void ShowEntries()
{
string path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
path = path + #"\SafePass\";
byte[] file = File.ReadAllBytes(path + #"\crypt.txt");
using (MemoryStream memory = new MemoryStream(file))
{
using (BinaryReader binary = new BinaryReader(memory))
{
byte[] result = binary.ReadBytes(file.Length);
byte[] plainText = new byte[48];
plainText = Decrypt(result);
string SplainText = Converter(plainText);
Console.WriteLine(SplainText);
}
}
}
static string Converter(byte[] data)
{
string base64 = Convert.ToBase64String(data);
return base64;
}
static byte[] Decrypt(byte[] encryptedByte)
{
{
string password = #"mykey123"; // Your Key Here
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = UE.GetBytes(password);
MemoryStream mem = new MemoryStream();
RijndaelManaged RMCrypto = new RijndaelManaged();
CryptoStream cs = new CryptoStream(mem,
RMCrypto.CreateDecryptor(key, key),
CryptoStreamMode.Write);
cs.Write(encryptedByte, 0, encryptedByte.Length);
byte[] cipherText = null;
cipherText = mem.ToArray();
cs.Close();
return cipherText;
}
}
Assuming that your input data (i.e. what you're encrypting) is 32 bytes long, what's happening is that the encrypted data is being padded, which means that extra redundant information is added to the encrypted data.
In .NET, the default padding mode for symmetrical algorithms like Rijndael is PKCS #7.
I think that if you look at the extra data in the encrypted array all the extra values will be 16 (32 bytes input, next block is at 48, padding is the difference: 48-32=16).
Note that the padded bytes will be removed upon decryption, provided that the same padding mode is used for decryption as encryption. It's not going to affect your data.
But if you really want, you can set the padding mode to None, or one of the other values mentioned on MSDN.
Here's a similar answer to a similar question that you can also refer to.

Aes Encrypt and Decrypt null adds bytes

Hi there i'm using this encryption method to encrypt my json value in .net side
public static string Encrypt256(string text)
{
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
aes.BlockSize = 128;
aes.KeySize = 256;
aes.IV = Encoding.UTF8.GetBytes(AesIV256);
aes.Key = Encoding.UTF8.GetBytes(AesKey256);
aes.Mode = CipherMode.CBC;
byte[] src = Encoding.Unicode.GetBytes(text);
using (ICryptoTransform encrypt = aes.CreateEncryptor())
{
byte[] dest = encrypt.TransformFinalBlock(src, 0, src.Length);
Debug.WriteLine(Convert.ToBase64String(dest));
return Convert.ToBase64String(dest);
}
}
And im trying to decrypt it in Node Js side
var crypto = require('crypto'),
algorithm = process.env.tombalaCryptoAlgorithm,
password = process.env.tombalaHmacPass,
iv = '!QAZ2WSX#EDC4RFV'
function encrypt(text) {
var cipher = crypto.createCipheriv(algorithm, password, iv)
var encrypted = cipher.update(text, 'utf8', 'base64')
encrypted += cipher.final('base64');
return encrypted;
You are converting your text to be encrypted to Unicode which means UTF-16.
In UTF-16 every character consists of two bytes. If the second byte is not used it is null as you have observed.
I assume you want UTF-8 encoding. Therefore replace the line
byte[] src = Encoding.Unicode.GetBytes(text);
with
byte[] src = Encoding.UTF8.GetBytes(text);

Is there any difference between implementation of Triple DES in C# and Java? Java gives error wrong IV size

In our application we are using Triple DES to encrypt and decrypt the data. We have the enc/dec code in C# which uses 24 byte key and 12 byte IV which works fine. Now we want to implement same code in java but when I use 12 byte IV, I get an error in java saying wrong IV size. When I googled around, I came to know that java uses 8 byte IV. Now I am confused as how come there is implementation difference in C# and JAVA for triple DES. Or am I missing anything?
This is something similar to our encryption code
class cTripleDES
{
// define the triple des provider
private TripleDESCryptoServiceProvider m_des = new TripleDESCryptoServiceProvider();
// define the string handler
private UTF8Encoding m_utf8 = new UTF8Encoding();
// define the local property arrays
private byte[] m_key;
private byte[] m_iv;
public cTripleDES(byte[] key, byte[] iv)
{
this.m_key = key;
this.m_iv = iv;
}
public byte[] Encrypt(byte[] input)
{
return Transform(input,
m_des.CreateEncryptor(m_key, m_iv));
}
public byte[] Decrypt(byte[] input)
{
return Transform(input,
m_des.CreateDecryptor(m_key, m_iv));
}
public string Encrypt(string text)
{
byte[] input = m_utf8.GetBytes(text);
byte[] output = Transform(input,
m_des.CreateEncryptor(m_key, m_iv));
return Convert.ToBase64String(output);
}
public string Decrypt(string text)
{
byte[] input = Convert.FromBase64String(text);
byte[] output = Transform(input,
m_des.CreateDecryptor(m_key, m_iv));
return m_utf8.GetString(output);
}
private byte[] Transform(byte[] input,
ICryptoTransform CryptoTransform)
{
// create the necessary streams
MemoryStream memStream = new MemoryStream();
CryptoStream cryptStream = new CryptoStream(memStream,
CryptoTransform, CryptoStreamMode.Write);
// transform the bytes as requested
cryptStream.Write(input, 0, input.Length);
cryptStream.FlushFinalBlock();
// Read the memory stream and
// convert it back into byte array
memStream.Position = 0;
byte[] result = memStream.ToArray();
// close and release the streams
memStream.Close();
cryptStream.Close();
// hand back the encrypted buffer
return result;
}
}
This is how we are utilizing it:
string IVasAString = "AkdrIFjaQrRQ";
byte[] iv = Convert.FromBase64String(IVasAString);
byte[] key = ASCIIEncoding.UTF8.GetBytes(KEY);
// instantiate the class with the arrays
cTripleDES des = new cTripleDES(key, iv);
string output = des.Encrypt("DATA TO BE ENCRYPTED");
TripleDES has a 64-bit block size. You need to use an 8 byte IV in C#.
Got the answer.
decodeBase64 method from apache common framework (commons.codec.binary.Base64) does the necessary.
Thanks mfanto for the heads up.!

Categories