4

I am attempting to use System.Security.Cryptography.AesManaged to encrypt a file in my .net application. It needs to be decrypted in an embedded Linux enviroment, so the .net libraries will not be available to me.

The code I have at the moment looks something like this:

string encPassword = "ABCDABCDABCDABCDABCDABCDABCDABCD";
string sourceFile = "myFile.txt";
string targetFile = "myFile.encrypted.txt";
FileStream fsInput = = new FileStream(sourceFile, FileMode.Open, FileAccess.Read);
FileStream fsOutput = new FileStream(targetFile, FileMode.OpenOrCreate, FileAccess.Write);

CryptoStream cryptoStream = null;

try
{
    byte[] key = Encoding.ASCII.GetBytes(encPasswd);
    byte[] IV = new byte[16];
    Array.Copy(key, 0, IV, 0, 16);

    AesManaged aes = new AesManaged();
    aes.Key = key;
    aes.IV = IV;
    aes.BlockSize = 128;
    aes.KeySize = 256;
    aes.Mode = CipherMode.CBC;

    ICryptoTransform encryptor = aes.CreateEncryptor();

    cryptoStream = new CryptoStream(fsOutput, encryptor, CryptoStreamMode.Write);

    byte[] buffer = new byte[BUFFER_LENGTH];
    long bytesProcessed = 0;
    long fileLength = fsInput.Length;
    int bytesInCurrentBlock;

    do
    {
        bytesInCurrentBlock = fsInput.Read(buffer, 0, BUFFER_LENGTH);
        cryptoStream.Write(buffer, 0, bytesInCurrentBlock);
        bytesProcessed = bytesProcessed + bytesInCurrentBlock;
    }
    while (bytesProcessed < fileLength);

    return true;
}
// ...

This encrypts the file okay. Now I am trying to decrypt the file using a 3rd-party utility on Windows that is also supported in Linux, to give me confidence that the Linux developer will be able to decrypt it.

A quick search on SourceForge let me to Enqrypt. However, if I use Enqrypt on the encrypted file like this:

enqrypt.exe -d -aes -256 -cbc -k ABCDABCDABCDABCDABCDABCDABCDABCD myFile.encrypted.txt

where -d indicates decrypt, -256 indicates the key size, -cbc the mode, and -k preceding the key.

it doesn't give me the original file.

I have tried this with a few 3rd party utilities but I can't seem to decrypt it.

Are there any obvious errors with how I am attempting to encrypt and decrypt this file?

Update

In response to recommendations from @Paŭlo, I now have the following test code (don't worry, I plan to change the key and IV to be different):

byte[] key = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 };
byte[] IV =  { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 };

The block size is still 128 and the key size is still 256 in code.

I now try to decrypt the file using openssl like so:

openssl enc -d -aes-256-cbc -in c:\encrypted.txt -out c:\decrypted.txt -K 11223344556677881122334455667788 -iv 11223344556677881122334455667788

This results in the following error:

bad decrypt 11452:error:06065064:digital envelope routines:EVP_DecryptFinal:bad decrypt:evp_enc.c:450:

Any idea what I am doing wrong?

LeopardSkinPillBoxHat
  • 28,915
  • 15
  • 75
  • 111
  • Your last error message looks like OpenSSL expects some padding scheme, which is not there (but this can also be caused by a wrong key/IV combination). Also, you only pass a 16 bytes key, while AES-256 needs a 32-bytes key. (I have no idea what OpenSSL and .NET are doing when you pass a too short key, but I can imagine that they are not doing the same thing.) – Paŭlo Ebermann Nov 14 '11 at 01:17
  • @Paŭlo - I changed key to be a 32-byte array but it didn't make a difference. What does the padding scheme apply to, the `key`, `IV` or both? Should the length of the `IV` be the same as the `key`? – LeopardSkinPillBoxHat Nov 14 '11 at 01:27
  • The length of the IV for CBC should be the same as the block size (which is 128 bits/16 bytes for AES), independent of key size. A padding scheme would be applied to the plain text before encrypting, to make sure the plaintext has a size which is a multiple of the block size. Though the [documentation](http://msdn.microsoft.com/en-us/library/system.security.cryptography.aesmanaged.padding.aspx) says that the default value is PKCS7, which is the same as what the openssl tool uses. I'm out of ideas here ... – Paŭlo Ebermann Nov 14 '11 at 01:44
  • @Paŭlo - thanks for all of your help. I finally found the solution - please see [my answer](http://stackoverflow.com/questions/8090081/unable-to-decrypt-file-encrypted-using-aesmanaged/8117192#8117192). – LeopardSkinPillBoxHat Nov 14 '11 at 04:15

3 Answers3

5

I found the solution to my problem with decrypting using openssl (in the Update section of the question).

Firstly, my key length was wrong (as suggested by @Paŭlo Ebermann) - it should have been 256 bits.

But the final problem was that I was setting the key size after the key:

AesManaged aes = new AesManaged();
aes.Key = key;
aes.IV = IV;
aes.BlockSize = 128;
aes.KeySize = 256;
aes.Mode = CipherMode.CBC;

If I changed the above code to the following, I could decrypt it using openssl:

AesManaged aes = new AesManaged();
aes.BlockSize = 128;
aes.KeySize = 256;
aes.Key = key;
aes.IV = IV;
aes.Mode = CipherMode.CBC;

Thanks to this answer which led me in the right direction, and thanks to everyone else for their answers!

Community
  • 1
  • 1
LeopardSkinPillBoxHat
  • 28,915
  • 15
  • 75
  • 111
4

This enqrypt tool seems to be quite silly:

  • It allows only direct input of the key, no base64 or hexadecimal encoding, which disallows any keys which are not representable (or not easily typeable as command line parameters) in the used encoding.
  • It uses a fixed initialization vector of DUMMY_DUMMY_DUMM.

For CBC, the initialization vector should be essentially random, and not predictable by any attacker, if you use the same key for multiple messages.

You can work around the issue of fixed IV: Simply prepend your plaintext with one block (128 bits=16 bytes) of random data, encrypt with the fixed initialization vector, and strip this first block off again after decryption. As each block's ciphertext is used like the initialization vector for the next block, this should give enough randomization for the real data.

But as enqrypt is only A simple demonstrative command line tool, I think you should instead use either the openssl command line tool, as recommended by sarnold, or use the OpenSSL library functions directly (if you are writing a program there).

Paŭlo Ebermann
  • 73,284
  • 20
  • 146
  • 210
  • Thanks - I tried to use `openssl` too but got an error "bad magic number" when attempting to decrypt. This was my command-line usage: `openssl enc -d -aes-256-cbc -in "c:\Encrypted.txt" -out "c:\Decrypted.txt" -pass pass:ABCDABCDABCDABCDABCDABCDABCDABCD`. Any suggestions? 31E15C9364939 bad magic number – LeopardSkinPillBoxHat Nov 13 '11 at 23:56
  • Use `-K` instead of `-pass`, as you are using a key directly. I think you also need to specify the initialization vector, if it is not included in the file. (And you shouldn't reuse your key as the initialization vector!) – Paŭlo Ebermann Nov 14 '11 at 00:22
  • So looking at my code above, my `IV` is simply the first 16 bytes of the key, right? – LeopardSkinPillBoxHat Nov 14 '11 at 00:28
  • Yes. And this by itself is a bad idea, but you could try this to see if it works here. – Paŭlo Ebermann Nov 14 '11 at 00:34
  • Thanks for your help - I have updated the question with the latest status. Can you please take a look and let me know what I may be doing wrong? – LeopardSkinPillBoxHat Nov 14 '11 at 01:03
3

enqrypt probably should have thrown an error of some sort for not initializing the IV -- you've probably used an IV of all zero bytes (assuming C# initializes memory to zeros for you) when encrypting, so you should try to use all zero bytes when decrypting too. (Be sure to set the IV for real use.)

Update

Thanks for including the exact usage statement -- it made me curious enough to look at the enqrypt source code, which has the solution:

// dummy data, can be used as iv/key
unsigned char *gDummy = (unsigned char*)"DUMMY_DUMMY_DUMMY_DUMMY_DUMMY_DUMMY_DUMMY";
/* ... */
    if (ALGO_AES == gAlgorithm) {
        unsigned char *iv = (unsigned char*)malloc(AES_BLOCK_SIZE);
        memcpy(iv, gDummy, AES_BLOCK_SIZE);
        int rc, num=0;

        if ((!gMem) && (gMode <= MODE_CBC)) {
            // insert padding info for ECB/CBC modes
            tblk[0] = gSize % AES_BLOCK_SIZE;
            fwrite(tblk, 1, 1, ftar);
        }

        while (0 != (rc = fread(sblk, 1, AES_BLOCK_SIZE, fsrc))) {
            switch (gMode) {
            default:
            case MODE_ECB:                           // AES ECB encrypt
                AES_ecb_encrypt(sblk, tblk, &gEncAesKey, AES_ENCRYPT);
                if (!gMem) fwrite(tblk, 1, AES_BLOCK_SIZE, ftar);
                break;
            case MODE_CBC:                            // AES CBC encrypt
                AES_cbc_encrypt(sblk, tblk, AES_BLOCK_SIZE, &gEncAesKey, iv, AES_ENCRYPT);
                if (!gMem) fwrite(tblk, 1, AES_BLOCK_SIZE, ftar);
                break;
/* ... */

You never stood a chance, because the author of enqrypt has hard-coded the IV (not a good idea) to DUMMY_DUMMY_DUMM.

sarnold
  • 102,305
  • 22
  • 181
  • 238
  • The usage of `enqrypt` is as follows: `enqrypt.exe [-e|-d|-b] [-aes|-des|-3des|-blowfish|-rc4] [-196|-256] [-ecb|-cbc|-cfb|-ofb] [-k key_data] [-mem] filename`. There doesn't seem to be any way of passing the `IV`, unless I'm mistaken? – LeopardSkinPillBoxHat Nov 11 '11 at 06:05
  • Based on that rationale, if I hardcode the IV in the encode-side to `DUMMY_DUMMY_DUMM` it should decode, right? When I changed the `IV` initialization in the code to `byte[] IV = Encoding.ASCII.GetBytes("DUMMY_DUMMY_DUMM");` it may no difference unfortunately. – LeopardSkinPillBoxHat Nov 11 '11 at 06:22
  • Am I passing the key correctly to `enqrypt`? In my code, the key is being generated from the ASCII values of a plain-text string. On the decrypt side, I'm passing the original plain-text string as the key. Is this right? – LeopardSkinPillBoxHat Nov 11 '11 at 06:24
  • 1
    I _think_ `enQrypt` is using your ASCII values directly as the key, but this is some pretty awkward code. Since this thing just calls into OpenSSL, can you use the significantly nicer `openssl(1)` command line tool instead? – sarnold Nov 11 '11 at 06:39
  • thanks for your help. I ended up getting it working with `openssl` directly after a lot of pain, when I finally discovered the problem in my code. See my accepted answer to this question. – LeopardSkinPillBoxHat Nov 14 '11 at 04:16
  • 1
    Superb! I'm sorry I missed the keysize problem -- that sounds like a _horrible_ problem to track down. Good work. :) – sarnold Nov 14 '11 at 05:27