Length of the data to decrypt is invalid when decrypting - c#

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 !

Related

Unity C# AES - Can't send IV

I am having a problem with my code and cannot figure out the problem.
With fullMsg set to false it works.
If I change fullMsg to true it no longer works even if I set it back to false.
I have no idea what is going on as the byte[] array remains the same in all the cases.
private void sendIndividualMsg(string msg){
//Debug.Log (msg);
byte[] toSend = PackageMsg (msg);
byte[] decoded = UnPackageMsg (toSend);
Debug.Log( System.Text.Encoding.ASCII.GetString(decoded) );
}
private byte[] UnPackageMsg(byte[] msg){
var toDecrypt = msg;
if (fullMsg) {
toDecrypt = new byte[msg.Length - 16];
var decryptIV = new byte[16];
System.Buffer.BlockCopy (msg, 0, decryptIV, 0, 16);
System.Buffer.BlockCopy (msg, 16, toDecrypt, 0, (msg.Length - 16));
//myAes.IV = decryptIV;
}
PrintByteArray (toDecrypt, "ToDecrypt");
byte[] plaintext;
// Create the streams used for decryption.
{
ICryptoTransform decryptor = myAes.CreateDecryptor (myAes.Key, myAes.IV);
MemoryStream msDecrypt = new MemoryStream ();
CryptoStream csDecrypt = new CryptoStream (msDecrypt, decryptor, CryptoStreamMode.Write);
csDecrypt.Write(msg, 0, msg.Length);
csDecrypt.FlushFinalBlock();
csDecrypt.Close();
plaintext = msDecrypt.ToArray();
msDecrypt.Close ();
decryptor.Dispose();
}
if (plaintext.Length > 16) {
byte[] hash = new byte[16];
byte[] hashCalc = new byte[16];
byte[] payload = new byte[plaintext.Length - 16 ];
System.Buffer.BlockCopy (plaintext, 0, hash, 0, 16);
System.Buffer.BlockCopy (plaintext, 16, payload, 0, plaintext.Length - 16);
hashCalc = md5.ComputeHash(payload);
if(ByteArrayCompare(hash, hashCalc)){
return payload;
}else{
return new byte[0];
}
} else {
return new byte[0];
}
}
private byte[] PackageMsg(string msg){
System.Text.ASCIIEncoding ue = new System.Text.ASCIIEncoding();
byte[] bytes = ue.GetBytes(msg);
byte[] hashBytes = md5.ComputeHash(bytes);
byte[] toEncrypt = new byte[bytes.Length + hashBytes.Length];
System.Buffer.BlockCopy(hashBytes, 0, toEncrypt, 0, hashBytes.Length);
System.Buffer.BlockCopy(bytes, 0, toEncrypt, hashBytes.Length, bytes.Length);
//myAes.GenerateIV();
byte[] encrypted;
{
ICryptoTransform encryptor = myAes.CreateEncryptor (myAes.Key, myAes.IV);
MemoryStream msEncrypt = new MemoryStream ();
CryptoStream csEncrypt = new CryptoStream (msEncrypt, encryptor, CryptoStreamMode.Write);
csEncrypt.Write(toEncrypt, 0, toEncrypt.Length);
csEncrypt.FlushFinalBlock();
csEncrypt.Close();
encrypted = msEncrypt.ToArray();
msEncrypt.Close ();
encryptor.Dispose();
}
PrintByteArray (encrypted, "Encrypted");
//SessionBytes + IV + ENCRYPTED( hash + msg)
byte[] finalMsg = new byte[myAes.IV.Length + encrypted.Length ];
System.Buffer.BlockCopy(myAes.IV, 0, finalMsg, 0 , myAes.IV.Length);
System.Buffer.BlockCopy(encrypted, 0, finalMsg, myAes.IV.Length , encrypted.Length);
if (!fullMsg) {
finalMsg = encrypted;
}
return finalMsg;
}
(I want to send the IV through each message, but until I get this working their is no point.)
Basic explanation of the algorithm for encrypting:
If fullMsg is set the encryption is [session][iv][encryptedmsg]
If fullMsg is not set the encryption is [encryptedmsg]
For Decryption the first part of the code is too extract just the encryptedmsg part.
As show by the screenshot of the logs, in both modes the bytes are the same.
--

Cannot AES decrypt data in C# that was enccrypted in Objective-C

I have an iOS app that sends encrypted data that is later decrypted in C#. I have checked that the hex key and data received is same, but I still get Bad PKCS7 padding. Invalid length 0.
my Objective-C call is
+(NSData*) encryptData: (NSData*) data
key: (NSString*) key
{
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
// fetch key data
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
NSUInteger dataLength = [data length];
//See the doc: For block ciphers, the output size will always be less than or
//equal to the input size plus the size of one block.
//That's why we need to add the size of one block here
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES256,
NULL /* initialization vector (optional) */,
[data bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
//the returned NSData takes ownership of the buffer and will free it on deallocation
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
free(buffer); //free the buffer;
return nil;
}
my keysize is 256, blocksize is 128, padding is pkcs7, IV is null, mode is CBC (default).
My C# code to decrypt is
using (MemoryStream memoryStream = new MemoryStream(outputBytes))
{
AesManaged algo = GetCryptoAlgorithm(GetRawBrokerKey());
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, algo.CreateDecryptor(), CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(cryptoStream))
{
plaintext = srDecrypt.ReadToEnd();
}
}
}
private static AesManaged GetCryptoAlgorithm()
{
return GetCryptoAlgorithm(null);
}
private static AesManaged GetCryptoAlgorithm(byte[] key)
{
AesManaged algorithm = new AesManaged();
//set the mode, padding and block size
algorithm.Padding = PaddingMode.PKCS7;
algorithm.Mode = CipherMode.CBC;
algorithm.KeySize = 256;
algorithm.BlockSize = 128;
if (key != null)
{
algorithm.Key = key;
}
algorithm.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
return algorithm;
}
I tried encryption using C# and see a different hex output using the same key.
c# encryption - 42AC7494606333309287768F47DFB35B
static byte[] EncryptStringToBytes_Aes(string plainText, byte[] key)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
byte[] encrypted;
AesManaged algorithm = new AesManaged();
//set the mode, padding and block size
algorithm.Padding = PaddingMode.PKCS7;
algorithm.Mode = CipherMode.CBC;
algorithm.KeySize = 256;
algorithm.BlockSize = 128;
if (key != null)
{
algorithm.Key = key;
}
algorithm.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
// Create a decrytor to perform the stream transform.
ICryptoTransform encryptor = algorithm.CreateEncryptor();
// 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();
}
}
string hex = BitConverter.ToString(encrypted);
Console.WriteLine("c# encryption - " + hex.Replace("-", ""));
// Return the encrypted bytes from the memory stream.
return encrypted;
}
Any ideas what could be going wrong? I seem to be following all the online advice around defaults for mode and IV, I think.
in GetCryptoAlgorithm, you need to pass the private key to GetCryptoAlgorithm.

C# method to decrypt in PHP

I have a C# code to decrypt data, now I'm trying to make the same in PHP but I can't get the same result. I know that I missing something but I don't know how to transfer this to PHP. Any ideas? Thanks.
This is the C# code:
public static string Decrypt(string cipherData, string key)
{
byte[] salt = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
byte[] IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
PasswordDeriveBytes cdk = new PasswordDeriveBytes(key, salt);
byte[] kex = cdk.CryptDeriveKey("RC2", "SHA1", 128, salt);
RijndaelManaged rijKey = new RijndaelManaged();
rijKey.Mode = CipherMode.CBC;
byte[] textBytes = Convert.FromBase64String(cipherData);
ICryptoTransform decryptor = rijKey.CreateDecryptor(kex, IV);
MemoryStream memoryStream = new MemoryStream(textBytes);
CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
byte[] pTextBytes = new byte[(textBytes.Length - 1) + 1];
int decryptedByteCount = cryptoStream.Read(pTextBytes, 0, pTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
return Encoding.UTF8.GetString(pTextBytes, 0, decryptedByteCount);
}
This is the PHP code trying to make the same (I know that it is incomplete):
function Decrypt($data, $key) {
$method = 'rc2-cbc';
$iv = '0000000000000000';
return utf8_encode(openssl_decrypt($data, $method, sha1($key), OPENSSL_ZERO_PADDING, $iv));
}

AES encryption error: The input data is not a complete block?

Here's the encryption method:
public static byte[] Encrypt(byte[] plaintext, byte[] key)
{
using (var aes = Aes.Create())
{
aes.BlockSize = 128;
aes.Mode = CipherMode.ECB;
aes.Padding = PaddingMode.None;
var iv = new byte[16];
for (int i = 0; i < iv.Length; i++)
iv[i] = 0;
aes.IV = iv;
var encryptor = aes.CreateEncryptor(key, aes.IV);
using(var target = new MemoryStream())
using (var cs = new CryptoStream(target, encryptor, CryptoStreamMode.Write))
{
using (var source = new StreamWriter(cs))
source.Write(plaintext);
return target.ToArray();
}
}
}
And how I'm calling it:
var key = new byte[16] { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
var plaintext = new byte[16] { 128, 0, 112, 0, 96, 0, 80, 0, 64, 0, 48, 0, 32, 0, 16, 0 };
But it keeps throwing an exception at source.Write(plaintext) that says it's not a complete block? I'm using a 16 byte/ 128 bit array with the block size set to 128. I don't understand what's wrong?
Also, just to head off any suggestions that ECB is bad etc, this is not for production, I'm just playing around.
StreamWriter writes UTF8 text characters to a stream.
You're writing plaintext.ToString() as text for the ciphertext.
This returns "System.Byte[]", which does not translate into 16 bytes of UTF8.
I believe the problem to be padding mode. Unless your text to be encrypted is for sure divisible by BlockSize (in bits, or BlockSize / 8 in bytes), you should specify a PaddingMode other than None.
see the post here for example code
I changed the function to this:
public static byte[] Encrypt(byte[] plaintext, byte[] key)
{
using (var aes = Aes.Create())
{
aes.BlockSize = 128;
aes.Mode = CipherMode.ECB;
aes.Padding = PaddingMode.None;
var encryptor = aes.CreateEncryptor(key, new byte[16]);
using(var target = new MemoryStream())
using (var cs = new CryptoStream(target, encryptor, CryptoStreamMode.Write))
{
cs.Write(plaintext, 0, plaintext.Length);
return target.ToArray();
}
}
}
From what I have experienced and fixed this issue, I missed to encrypt the field that it is complaining about, I was only decrypting it. It was saving a plain clear text and trying to decrypt it. So just make sure that the field that is complaining about is encrypted first. Thanks
This is valid for PowerShell:
This could happen if you encrypted the password without using -key option. To fix it encrypt it using -key option:
ConvertFrom-SecureString -key $key

AES Encryption getting incorrect result

I'm try to use AES encryption for some text, but the decrypted text is not identical to original one.
Original text: abcd
Decrypted text: ?9T?o??G???x;*
Here is my code:
public static void Main(string[] args)
{
byte[] original = { 97, 98, 99, 100 }; //"abcd"
byte[] key = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
byte[] encrypt = Encrypt(original, key, iv);
byte[] decrypt = Decrypt(encrypt, key, iv);
Console.WriteLine(Encoding.UTF8.GetString(original));
Console.WriteLine(Encoding.UTF8.GetString(decrypt));
Console.ReadKey();
}
public static byte[] Encrypt(byte[] original, byte[] key, byte[] iv)
{
using (var memoryStream = new MemoryStream())
{
using (var aes = new AesManaged { Key = key, IV = iv, Padding = PaddingMode.PKCS7, Mode = CipherMode.CBC })
{
using (var cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
cryptoStream.Write(original, 0, original.Length);
}
}
return memoryStream.ToArray();
}
}
public static byte[] Decrypt(byte[] encrypt, byte[] key, byte[] iv)
{
using (var memoryStream = new MemoryStream(encrypt))
{
using (var aes = new AesManaged { Key = key, IV = iv, Padding = PaddingMode.PKCS7, Mode = CipherMode.CBC })
{
using (var cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(), CryptoStreamMode.Read))
{
byte[] decrypt = new byte[encrypt.Length];
cryptoStream.Read(decrypt, 0, decrypt.Length);
return decrypt;
}
}
}
}
What's wrong? Thanks in advance.
You've got this in your decryption code:
using (var cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(),
CryptoStreamMode.Read))
Change it to call aes.CreateDecryptor() and it works fine.
There's something wrong with your decrypt method, use something like this :
public string Decrypt(byte[] EncryptedValue)
{
#region Write the encrypted value to the decryption stream
MemoryStream encryptedStream = new MemoryStream();
CryptoStream decryptStream = new CryptoStream(encryptedStream, DecryptorTransform, CryptoStreamMode.Write);
decryptStream.Write(EncryptedValue, 0, EncryptedValue.Length);
decryptStream.FlushFinalBlock();
#endregion
#region Read the decrypted value from the stream.
encryptedStream.Position = 0;
Byte[] decryptedBytes = new Byte[encryptedStream.Length];
encryptedStream.Read(decryptedBytes, 0, decryptedBytes.Length);
encryptedStream.Close();
#endregion
return UTFEncoder.GetString(decryptedBytes);
}

Categories