Crypto.AES.CCM produces incorrect results
Hi there,
While performing some unit tests with Pike's Crypto.AES.CCM, I've run into an issue of the digest function producing "incorrect" results.
During my tests, I'm using two unit tests. The first test is:
key: 1a44f3550688fddbc1e5041dc98952c0
iv: 5d2904298f668ba95eaa1797
aad: d55908958b70abee81054cdf3d3df5
msg:
expected digest: 5c71b4f069cfa13b7634db4b13e7be7d
And the second test is:
key: 439fd5c3b76587d5a601ba6ef8fad214
iv: ed1d316d0834d174c1b5b438
aad: eae252f42d2c71
msg:
expected digest: e8530426cbabf63633ff373159247e38
The second test results in the the digest value of "e8530426cbabf63633ff373159247e38". This is the same value as seen in openssl using the following C source code (gcc test.c -lcrypto
):
#include <stdio.h>
#include <string.h>
#include <openssl/evp.h>
void str2hex(char *, char*, int);
void printBytes(unsigned char *, size_t );
int main() {
unsigned char *aad, *pt, *key, *nonce;
int Klen, Alen, Nlen, Plen, Tlen, Clen;
int outl = 0;
key = "439fd5c3b76587d5a601ba6ef8fad214";
aad = "eae252f42d2c71";
nonce = "ed1d316d0834d174c1b5b438";
pt = "";
Klen = strlen(key) / 2;
Alen = strlen(aad) / 2;
Nlen = strlen(nonce) / 2;
Plen = strlen(pt) / 2;
Tlen = 16;
Clen = Plen + Tlen;
unsigned char keyy[Klen], aadd[Alen], noncee[Nlen], ptt[Plen];
unsigned char ct[Clen], dt[Plen];
str2hex(key, keyy, Klen);
str2hex(pt, ptt, Plen);
str2hex(aad, aadd, Alen);
str2hex(nonce, noncee, Nlen);
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX_init(ctx);
EVP_EncryptInit(ctx, EVP_aes_128_ccm(), 0, 0);
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, Nlen, 0);
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, Tlen, 0);
EVP_EncryptInit(ctx, 0, keyy, noncee);
EVP_EncryptUpdate(ctx, 0, &outl, 0, Plen);
EVP_EncryptUpdate(ctx, 0, &outl, aadd, Alen);
EVP_EncryptUpdate(ctx, ct, &outl, ptt, Plen);
EVP_EncryptFinal(ctx, &ct[outl], &outl);
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_GET_TAG, Tlen, ct + Plen);
printf("plaintext' = %s", pt);
printf("\n");
printf("\nciphertext : ");
printBytes(ct, Clen);
EVP_DecryptInit(ctx, EVP_aes_128_ccm(), 0, 0);
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, Nlen, 0);
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, Tlen, ct + Plen);
EVP_DecryptInit(ctx, 0, keyy, noncee);
EVP_DecryptUpdate(ctx, 0, &outl, 0, Plen);
EVP_DecryptUpdate(ctx, 0, &outl, aadd, Alen);
EVP_DecryptUpdate(ctx, dt, &outl, ct, Plen);
EVP_DecryptFinal(ctx, &dt[outl], &outl);
printf("plaintext : ");
printBytes(dt, Plen);
return 0;
}
void str2hex(char *str, char *hex, int len) {
int tt, ss;
unsigned char temp[4];
for (tt = 0, ss = 0; tt < len, ss < 2 * len; tt++, ss += 2) {
temp[0] = '0';
temp[1] = 'x';
temp[2] = str[ss];
temp[3] = str[ss + 1];
hex[tt] = (int) strtol(temp, NULL, 0);
}
}
void printBytes(unsigned char *buf, size_t len) {
int i;
for (i = 0; i < len; i++) {
printf("%02x", buf[i]);
}
printf("\n");
}
However, the first test does not succeed. Pike produces the digest "7a627cad3a11cb4192566a040d801fa8", while the C code (edited accordingly) produces the expected result, "5c71b4f069cfa13b7634db4b13e7be7d".
The following Pike code annotates my concerns:
int main() {
mixed state1 = Crypto.AES.CCM.State();
state1->set_encrypt_key(String.hex2string("1a44f3550688fddbc1e5041dc98952c0"));
state1->set_iv(String.hex2string("5d2904298f668ba95eaa1797"));
state1->update(String.hex2string("d55908958b70abee81054cdf3d3df5"));
string ct1 = state1->crypt(String.hex2string(""));
string dig1 = state1->digest();
if(String.string2hex(dig1) != "5c71b4f069cfa13b7634db4b13e7be7d")
write("First one did not match. Got %s, expected %s.\n", String.string2hex(dig1), "5c71b4f069cfa13b7634db4b13e7be7d");
mixed state2 = Crypto.AES.CCM.State();
state2->set_encrypt_key(String.hex2string("439fd5c3b76587d5a601ba6ef8fad214"));
state2->set_iv(String.hex2string("ed1d316d0834d174c1b5b438"));
state2->update(String.hex2string("eae252f42d2c71"));
string ct2 = state2->crypt(String.hex2string(""));
string dig2 = state2->digest();
if(String.string2hex(dig2) != "e8530426cbabf63633ff373159247e38")
write("Second one did not match. Got %s, expected %s.\n", String.string2hex(dig2), "e8530426cbabf63633ff373159247e38");
}
I have no explanation for the incorrect results, unfortunately.
Any support is welcome.
Thank you.