1

I'm trying to encrypt text block with AES128 (ECB mode), to test resulted encryption/decryption functionality I'm using using ECB-AES123 test vectors from "Recommendation for Block Cipher Modes of Operation: Methods and Techniques, NIST Special Publication 800-38A, 2001 Edition;".

For example:

Key: 2b7e151628aed2a6abf7158809cf4f3c  (16 bytes)      
Input Plaintext: 6bc1bee22e409f96e93d7e117393172a  (16 bytes) 
Resulted Ciphertext: 3ad77bb40d7a3660a89ecaf32466ef97  (16 bytes)

For OpenSSL following code works perfectly:

AES_KEY aes_key; 
//key vector of bytes 2b7e151628aed2a6abf7158809cf4f3c (16 bytes)
//input_vector also vector of bytes 6bc1bee22e409f96e93d7e117393172a  (16 bytes) 
if ( AES_set_encrypt_key( &key[0], 128, &aes_key ) != 0 )
{
    return false;
}
AES_ecb_encrypt( &input_vector[ 0 ], &encrypted_vector[ 0 ], &aes_key, AES_ENCRYPT );
//encrypted_vector will have expected value 3ad77bb40d7a3660a89ecaf32466ef97 (16 bytes)

But at the same time I need implement same functionality with Microsoft's Crypto API. Following is code which should do it:

HCRYPTPROV crypto_provider_handle;
HCRYPTHASH crypto_hash_handle;
HCRYPTKEY crypto_key_handle;

CryptAcquireContext( &crypto_provider_handle, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES,
                     CRYPT_VERIFYCONTEXT | CRYPT_NEWKEYSET );
CryptCreateHash( crypto_provider_handle, CALG_SHA1, 0, 0, &crypto_hash_handle ); 
CryptHashData( crypto_hash_handle, &key[ 0 ], key.size( ), 0 );
CryptDeriveKey( crypto_provider_handle, CALG_AES_128, crypto_hash_handle,
                0x00800000 | CRYPT_NO_SALT, crypto_key_handle );

// Set ECB mode
DWORD mode = CRYPT_MODE_ECB;
CryptSetKeyParam( crypto_key_handle, KP_MODE, (BYTE*)&mode, 0 );

// input_data is buffer of 16 bytes with additional space, total size 16*2
// input_size equals 16
CryptEncrypt( crypto_key_handle, NULL, TRUE, 0, input_data, &input_size, 16*2 );

But this code will produce different result.

  1. If "Final" will be TRUE (as was shown above) input_data will have size 32 bytes, which doesn't match expected value at all. According to MSDN it's OK, since in this case one additional block of padding is appended to the data.
  2. If "Final" will be FALSE input_data will have expected size (16 bytes) but also wrong result.

I have stuck with this case and I don't understand what I have missed. Is it possible to produce same result as OpenSSL (which is expected according specs)? Why AES128 in ECB mode changes size of result (In ECB mode it shouldn't do it)?

jww
  • 97,681
  • 90
  • 411
  • 885
  • Setting `NoPadding` (or its equivalent) will get rid of the second block. Best to check that your keys and IVs are **byte-for-byte** the same. OpenSSL and MS are likely to have different defaults, so if you rely on system defaults you will get a mismatch. Wherever possible, explicitly specify everything, so you know they are the same in both systems. – rossum May 02 '15 at 10:55
  • Yep, I agree. I have thought about padding disabling. But the problem is that typically padding should be added when the last plain text block is short Sample from MSDN: "if the block length is 64 bits and the last block contains only 40 bits, then 24 bits of padding must be added to the last block". But in our case all blocks have same size - 16 bytes. Also don't found any possibility to disable padding for incoming data. Looks like it's default behavior. – Alex Zeydel May 02 '15 at 11:40
  • @AlexZeydel 1) I don't get your point. If you use PKCS#7 padding, a 16 byte plaintext will map to a 32 byte ciphertext since it adds between 1 and 16 bytes of padding. It will automatically be removed when decrypting if you use PKCS#7 padding during decryption as well. If you don't want padding, you need to disable it. 2) Why are you using an IV? ECB doesn't support IVs. – CodesInChaos May 02 '15 at 11:45
  • 1
    Also it's a little bit tricky to set the same default behavior for both OpenSSL and MS Crypto API libraries, since we don't know what is default MS behavior. OpenSSL can be easily checked, since all src are available. As for me, the problem looks like I have missed something in configuration steps before call CryptoEnctypt – Alex Zeydel May 02 '15 at 11:49
  • @CodesInChaos 1) yep, looks like pkcs#7 is default behavior for MS CryptoApi, but at the same time we cannot disable it there. Also as far as I know AES cannot use for example pkcs#5. 2) Why you have made such decision about IV. In ECB mode we don't need it at all.In my case I have just the key (password) 16 bytes, plain data (also 16 bytes) and result which should be also 16 bytes – Alex Zeydel May 02 '15 at 12:00
  • PKCS#5 padding is just a subset of PKCS#7 padding since it's restricted to 64 bit blocks. But some APIs simply tread PKCS#5 as a synonym of PKCS#7 padding. – CodesInChaos May 02 '15 at 12:18
  • Regarding Microsoft's docs, there is possibility to set zero padding mode . But it doesn't supports by Microsoft's CSP: " The padding uses zeros. This padding method is not supported by the Microsoft supplied CSPs." So we can just set PKCS#5, but looks like it doesn't lead us to correct results – Alex Zeydel May 02 '15 at 13:09
  • @Alex - Just bikeshedding, but ECB mode is probably insecure for your needs. You should use an authenticated encryption mode, like EAX or GCM. In the absence of those modes, you should use AES/CBC with an HMAC. Apply the HMAC to the `{IV || Ciphertext}`. OpenSSL and CAPI has both primitives. – jww May 02 '15 at 19:57

0 Answers0