[pycrypto] AES128 Countermode in Cryptodome vs OpenSSL/BouncyCastle/Erlang
Dirk-Willem van Gulik
dirkx at webweaving.org
Tue Apr 14 20:05:53 UTC 2020
I've got a very simple bit of cryptography (part of the Covid-19 european DP3T standard for good privacy/anonymisation[1]).
The key bit of code is just a AES128 used in counter mode; starting at 0.
And I am having a hard time to understand why Cryptodome gives me a different answer than OpenSSL, a 'trivial' AES suite and various other languages.
I cannot get things to be interoperable.
The code is shown below. The output is:
python/Cryptodome erlang, java, openssl, tiny-AES, ruby-2.6.3p62
3b8ce20e3f4601b69aa203ba54873ce0 66e94bd4ef8a2c3b884cfa59ca342b2e
11587022bd9ee188eb39f367e84bf520 58e2fccefa7e3061367f1d57a4e7455a
21ea107085daaf10646369d06e1671af 0388dace60b6a392f328c2b971b2fe78
0a8408cef8f06c19f6a482a0c10f2151 f795aaab494b5923f7fd89ff948bc1e0
Does that ring a bell with anyone ?
Is there something special with Cryptodome AES ? Some key rounds ? Or am I misreading how the AES call in python works versus AES_init_ctx_iv().
Any and all help much appreciated !
With kind regards,
Dw.
1: https://github.com/DP-3T/documents
PYHTON CODE
#!/usr/bin/env python3
from Cryptodome.Util import Counter
from Cryptodome.Cipher import AES
key = b"0" * 32
prg = AES.new(key, AES.MODE_CTR, counter = Counter.new(128, initial_value=0))
plaintext = b"\0" * 16 * 4
cipher = prg.encrypt(plaintext)
for i in range(4):
print("{}".format(cipher[ i * 16: i * 16 + 16 ].hex()))
C code (openssl, tiny-AES)
#include <stdio.h>
#include <unistd.h>
#include <strings.h>
#include <openssl/sha.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <openssl/hmac.h>
#include <openssl/crypto.h>
#include <assert.h>
#include <strings.h>
#include <stdlib.h>
// https://github.com/kokke/tiny-AES-c.git - AES128 is de default
#include "tiny-AES-c/aes.h"
#else
#include <openssl/evp.h>
#endif
int main(int argc, const char * argv[]) {
unsigned char key[16];
unsigned char inoutbuf[16*4];
unsigned char iv[16];
bzero(key,16);
bzero(inoutbuf, 16*4);
bzero(iv,16);
#ifdef TINY
struct AES_ctx ctx;
AES_init_ctx_iv(&ctx, key, iv);
AES_CTR_xcrypt_buffer(&ctx, inoutbuf, 16*4);
for(int i = 0; i < 4; i++) {
for(int j = 0; j < 16; j++)
printf("%02x", inoutbuf[ i*16+j ]);
printf("\n");
};
#else
unsigned char * out = malloc(16*4);
assert(out);
const EVP_CIPHER * cipher = EVP_aes_128_ctr();
assert(EVP_CIPHER_key_length(cipher) == 128/8);
assert(EVP_CIPHER_iv_length(cipher) == 128/8);
EVP_CIPHER_CTX * ctx;
assert(ctx = EVP_CIPHER_CTX_new());
EVP_CIPHER_CTX_init(ctx);
assert(1 == EVP_EncryptInit(ctx, cipher, key, iv));
EVP_CIPHER_CTX_set_padding(ctx, 0);
int len = 0, len2 = 0;
assert(1 == EVP_EncryptUpdate(ctx, out, &len, inoutbuf, 16*4));
assert(len == 16*4);
assert(1 == EVP_EncryptFinal(ctx, out + len, &len2));
assert(len + len2 == 16*4);
for(int i = 0; i < 4; i++) {
for(int j = 0; j < 16; j++)
printf("%02x", out[ i*16+j ]);
printf("\n");
}
EVP_CIPHER_CTX_cleanup(ctx);
EVP_CIPHER_CTX_free(ctx);
#endif
return 0;
}
More information about the pycrypto
mailing list