blah blah blah is here! blah blah » Close

up1down
link

Hi friends.

The headline kinda says what needs to be said. it is all working fine exept that the decrypted file is containing rubbish. and wierdly enough it is smaller than the plaintext and cipher?

Thanks for your help :)

EDIT: I got some more information... now it has the correct length. now the decrypted file is 1 block short of the encrypted file, and it says: "padding is invalid and cannot be removed". I guess that this is maybe caused since the decryption fails and the padding then can't be recognized? I don't know.

Unfortunatly all the other decrypted blocks are wrong (rubbish)..

very frustrated. :(

private void encryptFile(byte[] key, byte[] iv, int keySize, CipherMode CM, FileStream fileInput, FileStream fileOutput)
{
try
{
RijndaelManaged AES = new RijndaelManaged();

AES.IV = iv;
AES.Mode = CM;
AES.Key = key;
AES.KeySize = keySize;

int blockSize = 16;
byte[] byteArrayInput = new byte[blockSize];
long numBlocks = fileInput.Length / blockSize;
long numBlocksDone = 0;

ICryptoTransform aesEncrypt = AES.CreateEncryptor();
CryptoStream cryptoStream = new CryptoStream(fileOutput, aesEncrypt, CryptoStreamMode.Write);

for (long l = 0; l < numBlocks; l++)
{
fileInput.Read(byteArrayInput, 0, byteArrayInput.Length);
cryptoStream.Write(byteArrayInput, 0, byteArrayInput.Length);

numBlocksDone++;
reportWhileEncrypting(numBlocksDone, numBlocks);
}

if (fileInput.Length % blockSize > 0L)
{
byteArrayInput = new byte[fileInput.Length % blockSize];
fileInput.Read(byteArrayInput, 0, byteArrayInput.Length);
cryptoStream.Write(byteArrayInput, 0, byteArrayInput.Length);
}

cryptoStream.Close();
fileInput.Close();
fileOutput.Close();
}
catch (Exception e)
{
statusHandler.addStatus("AES encryption...", statusReport.status.Error, "Error: " + e.Message);
}
}

private void decryptFile(byte[] key, byte[] iv, int keySize, CipherMode CM, FileStream fileInput, FileStream fileOutput)
{
try
{
RijndaelManaged AES = new RijndaelManaged();

AES.IV = iv;
AES.Mode = CM;
AES.Key = key;
AES.KeySize = keySize;

int blockSize = 16;
byte[] byteArrayInput = new byte[blockSize];
long numBlocks = fileInput.Length / blockSize;
long numBlocksDone = 0;

ICryptoTransform aesDecrypt = AES.CreateDecryptor();
CryptoStream cryptoStream = new CryptoStream(fileInput, aesDecrypt, CryptoStreamMode.Read);

for (long l = 0; l < numBlocks; l++)
{
cryptoStream.Read(byteArrayInput, 0, byteArrayInput.Length);
fileOutput.Write(byteArrayInput, 0, byteArrayInput.Length);

numBlocksDone++;
reportWhileEncrypting(numBlocksDone, numBlocks);
}

cryptoStream.Close();
fileInput.Close();
fileOutput.Close();
}
catch (Exception e)
{
statusHandler.addStatus("AES Decryption...", statusReport.status.Error, "Error: " + e.Message);
}
}

last answered one year ago

2 answers

link

Just to show that it definitely is possible to use RijndaelManaged to encrypt/decrypt one block at a time, I've adjusted the MS Support article code used in previous threads to allow for this. It works fine on the (small) files I've tested it on.

using System;
using System.IO;
using System.Security;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
using System.Text;

namespace CSEncryptDecrypt
{
class Class1
{
// Call this function to remove the key from memory after use for security
[System.Runtime.InteropServices.DllImport("KERNEL32.DLL", EntryPoint="RtlZeroMemory")]
public static extern bool ZeroMemory(IntPtr Destination, int Length);

// Function to Generate a 128 bits Key.
static string GenerateKey()
{
// Create an instance of Symetric Algorithm. Key and IV is generated automatically.
RijndaelManaged aesCrypto = new RijndaelManaged();
aesCrypto.KeySize = 128;
// Use the Automatically generated key for Encryption.
return ASCIIEncoding.ASCII.GetString(aesCrypto.Key);
}

static void EncryptFile(string sInputFilename,
string sOutputFilename,
string sKey)
{

FileStream fsInput = new FileStream(sInputFilename,
FileMode.Open,
FileAccess.Read);

FileStream fsEncrypted = new FileStream(sOutputFilename,
FileMode.Create,
FileAccess.Write);
RijndaelManaged AES = new RijndaelManaged();
int blockSize = AES.BlockSize/8; // in bytes
byte[] bytearrayinput = new byte[blockSize];
long numBlocks = fsInput.Length / blockSize;
AES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
AES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
AES.Mode = CipherMode.CBC;
ICryptoTransform aesencrypt = AES.CreateEncryptor();
CryptoStream cryptostream = new CryptoStream(fsEncrypted,
aesencrypt,
CryptoStreamMode.Write);
for(long l = 0; l < numBlocks; l++)
{
fsInput.Read(bytearrayinput, 0, bytearrayinput.Length);
cryptostream.Write(bytearrayinput, 0, bytearrayinput.Length);
}
// process last incomplete block if there is one
if (fsInput.Length % blockSize > 0L)
{
bytearrayinput = new byte[fsInput.Length % blockSize];
fsInput.Read(bytearrayinput, 0, bytearrayinput.Length);
cryptostream.Write(bytearrayinput, 0, bytearrayinput.Length);
}

cryptostream.Close();
fsInput.Close();
fsEncrypted.Close();
}

static void DecryptFile(string sInputFilename,
string sOutputFilename,
string sKey)
{

//Create a file stream to read the encrypted file back.
FileStream fsInput = new FileStream(sInputFilename,
FileMode.Open,
FileAccess.Read);

//Create a file stream to write the decrypted file to disk
FileStream fsDecrypted = new FileStream(sOutputFilename,
FileMode.Create,
FileAccess.Write);

RijndaelManaged AES = new RijndaelManaged();
//A 128 bit key and IV is required for this provider.

int blockSize = AES.BlockSize/8; // in bytes
byte[] bytearrayinput = new byte[blockSize];
long numBlocks = fsInput.Length / blockSize;
//Set secret key For DES algorithm.
AES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
//Set initialization vector.
AES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
AES.Mode = CipherMode.CBC;

//Create a DES decryptor from the DES instance.
ICryptoTransform aesdecrypt = AES.CreateDecryptor();
//Create crypto stream set to read and do a
//AES decryption transform on incoming bytes.
CryptoStream cryptostreamDecr = new CryptoStream(fsInput,
aesdecrypt,
CryptoStreamMode.Read);
for(long l = 0; l < numBlocks - 1; l++)
{
cryptostreamDecr.Read(bytearrayinput, 0, bytearrayinput.Length);
fsDecrypted.Write(bytearrayinput, 0, bytearrayinput.Length);
}

// process last block
bytearrayinput = new byte[blockSize]; // make sure all bytes are initially zero
cryptostreamDecr.Read(bytearrayinput, 0, bytearrayinput.Length);
int len = blockSize;
for (int i = blockSize - 1; i >= 1; i--)
{
if (bytearrayinput[i] != 0) break;
len = i;
}

fsDecrypted.Write(bytearrayinput, 0, len);

cryptostreamDecr.Close();
fsInput.Close();
fsDecrypted.Close();
}

static void Main()
{
// Must be 128 bits, 16 bytes.
// Distribute this key to the user who will decrypt this file.
string sSecretKey;

// Get the Key for the file to Encrypt.
sSecretKey = GenerateKey();

// For additional security Pin the key.
GCHandle gch = GCHandle.Alloc( sSecretKey,GCHandleType.Pinned );

// Encrypt the file.
EncryptFile(@"C:\MyData.txt",
@"C:\Encrypted.txt",
sSecretKey);

// Decrypt the file.
DecryptFile(@"C:\Encrypted.txt",
@"C:\Decrypted.txt",
sSecretKey);

// Remove the Key from memory.
ZeroMemory(gch.AddrOfPinnedObject(), sSecretKey.Length * 2);
gch.Free();
}
}
}

I got it working finally... Thx for all your help :)

MadHatter
2309

I've always hated managed aes implementation. rijndael doesn't use an iv. that base class is pretty much a des/triple des base but doesn't make sense with others.

Why you hate it? :) and it's not the algorithms that uses the IV, it's the cipherMode, which just ensures different cipher for same plaintext, and it has nothing to do with the cipher algorithm itself.

MadHatter
2309

aes doesn't use a cipher mode or iv. it has it's own substitution box and works way different than des/3des (which uses the iv to xor the initial block, and uses the cipher mode to determine whether it xor's the previous block, or whatever). both these are useless to aes, and therefore the algorithm base class is a very bad interface for all symmetric encryption algorithms.

up0down
link

I don't know whether it's the only problem but there certainly is a problem with the way you're decrypting the final block.

Any trailing zero bytes need to be trimmed off before writing it to the decrypted file as these will reflect padding added during the encryption process due to the plaintext file size not being an exact multiple of the block size.

I've adjusted your decryptFile method below to allow for this:

private void decryptFile(byte[] key, byte[] iv, int keySize, CipherMode CM, FileStream fileInput, FileStream fileOutput)
{
try
{
RijndaelManaged AES = new RijndaelManaged();

AES.IV = iv;
AES.Mode = CM;
AES.Key = key;
AES.KeySize = keySize;

int blockSize = 16;
byte[] byteArrayInput = new byte[blockSize];
long numBlocks = fileInput.Length / blockSize;
long numBlocksDone = 0;

ICryptoTransform aesDecrypt = AES.CreateDecryptor();
CryptoStream cryptoStream = new CryptoStream(fileInput, aesDecrypt, CryptoStreamMode.Read);

for (long l = 0; l < numBlocks - 1; l++) // now numBlocks - 1
{
cryptoStream.Read(byteArrayInput, 0, byteArrayInput.Length);
fileOutput.Write(byteArrayInput, 0, byteArrayInput.Length);

numBlocksDone++;
reportWhileEncrypting(numBlocksDone, numBlocks);
}

// process last block
byteArrayInput = new byte[blockSize]; // make sure all bytes are initially zero
cryptoStream.Read(byteArrayInput, 0, byteArrayInput.Length);
int len = blockSize;
for (int i = blockSize - 1; i >= 1; i--)
{
if (byteArrayInput[i] != 0) break;
len = i;
}

fileOutput.Write(bytearrayinput, 0, len);
reportWhileEncrypting(numBlocks, numBlocks);

cryptoStream.Close();
fileInput.Close();
fileOutput.Close();
}
catch (Exception e)
{
statusHandler.addStatus("AES Decryption...", statusReport.status.Error, "Error: " + e.Message);
}
}

DIdn't change anything... and i guess that the paddig would be added beforehand the encryption (since it's neede to encrypt) and then the zero bytes would be ebcrypted, hence we can't really remove them before decrypting? anyway, all the decrypted blocks are rubbish unfortunatly :(

vulpes
17279

The extra code is removing the extra bytes after decryption so that the decrypted text file length will be the same as the original file length. I don't know what else could be wrong unless there's some mismatch in the key, IV or mode being passed to the encrypt and decrypt methods but see my additional answer below.

Feedback