258 lines
9.5 KiB
C
258 lines
9.5 KiB
C
/* Copyright (c) (2012,2013,2015,2016,2018,2019) Apple Inc. All rights reserved.
|
||
*
|
||
* corecrypto is licensed under Apple Inc.’s Internal Use License Agreement (which
|
||
* is contained in the License.txt file distributed with corecrypto) and only to
|
||
* people who accept that license. IMPORTANT: Any license rights granted to you by
|
||
* Apple Inc. (if any) are limited to internal use within your organization only on
|
||
* devices and computers you own or control, for the sole purpose of verifying the
|
||
* security characteristics and correct functioning of the Apple Software. You may
|
||
* not, directly or indirectly, redistribute the Apple Software or any portions thereof.
|
||
*/
|
||
|
||
#include "testmore.h"
|
||
#include "testbyteBuffer.h"
|
||
#include "testccnBuffer.h"
|
||
#include "cc_priv.h"
|
||
|
||
static int verbose = 0;
|
||
|
||
#if (CCCMAC == 0)
|
||
entryPoint(cccmac_tests,"cccmac test")
|
||
#else
|
||
#include "crypto_test_cmac.h"
|
||
|
||
/* Currently, cccmac and friends won't work when length == 0 and the
|
||
* data pointer is NULL.
|
||
*/
|
||
|
||
int showBytesAreEqual(byteBuffer bb1, byteBuffer bb2, char *label) {
|
||
ok(bytesAreEqual(bb1, bb2), label);
|
||
if(bytesAreEqual(bb1, bb2) == 0) {
|
||
printByteBuffer(bb1, "Want");
|
||
printByteBuffer(bb2, "Got ");
|
||
return 0;
|
||
}
|
||
return 1;
|
||
}
|
||
|
||
int test_cmac_answer(char *mode_name, const test_vector *vector, void*answer, char *test_type) {
|
||
byteBuffer answer_bb;
|
||
byteBuffer correct_answer_bb;
|
||
int isEqual;
|
||
if(vector->Mac == NULL) {
|
||
answer_bb = bytesToBytes(answer, CMAC_BLOCKSIZE);
|
||
diag("/* CMAC-%d test %d */", vector->Key_len*8, vector->Count);
|
||
diag("\t\t\"%s\",\n", bytesToHexString(answer_bb));
|
||
return 1;
|
||
} else {
|
||
correct_answer_bb = hexStringToBytes((char *) vector->Mac);
|
||
answer_bb = bytesToBytes(answer, correct_answer_bb->len);
|
||
}
|
||
isEqual=bytesAreEqual(correct_answer_bb, answer_bb);
|
||
ok((isEqual && vector->Result==0) || (!isEqual && vector->Result!=0), "compare memory of answer");
|
||
if(!isEqual && vector->Result==0) {
|
||
diag("Failed Test (%d) for CMAC-%d-%s %s", vector->Count, vector->Key_len*8, mode_name, test_type);
|
||
printByteBuffer(correct_answer_bb, "Correct Answer");
|
||
printByteBuffer(answer_bb, "Provided Answer");
|
||
}
|
||
free(correct_answer_bb);
|
||
free(answer_bb);
|
||
return 1;
|
||
}
|
||
|
||
/* =============================================================================
|
||
|
||
Test for new CMAC
|
||
|
||
==============================================================================*/
|
||
|
||
static int test_oneshot(const struct ccmode_cbc *cbc, char *mode_name, const test_vector *vector) {
|
||
uint8_t answer[CMAC_BLOCKSIZE];
|
||
byteBuffer key = hexStringToBytes(vector->Key);
|
||
byteBuffer in = hexStringToBytes(vector->Msg);
|
||
byteBuffer expected_answer = hexStringToBytes(vector->Mac);
|
||
if (vector->Result==0) {
|
||
is(cccmac_one_shot_generate(cbc, key->len, key->bytes,
|
||
in->len, in->bytes,
|
||
expected_answer->len, answer),0,"generate cmac");
|
||
ok(test_cmac_answer(mode_name, vector, answer, "one-shot"), "check answer");
|
||
is(cccmac_one_shot_verify(cbc, key->len, key->bytes,
|
||
in->len, in->bytes,
|
||
expected_answer->len, expected_answer->bytes),0,"valid cmac");
|
||
} else {
|
||
isnt(cccmac_one_shot_verify(cbc, key->len, key->bytes,
|
||
in->len, in->bytes,
|
||
expected_answer->len, expected_answer->bytes),0,"detect invalid cmac");
|
||
ok(test_cmac_answer(mode_name, vector, answer, "one-shot"), "check answer");
|
||
}
|
||
free(key);
|
||
free(in);
|
||
free(expected_answer);
|
||
return 1;
|
||
}
|
||
|
||
|
||
static int test_discrete(const struct ccmode_cbc *cbc, char *mode_name, const test_vector *vector) {
|
||
|
||
uint8_t answer[CMAC_BLOCKSIZE];
|
||
cccmac_mode_decl(cbc, cmac);
|
||
|
||
byteBuffer key = hexStringToBytes(vector->Key);
|
||
byteBuffer in = hexStringToBytes(vector->Msg);
|
||
size_t nbytes = in->len;
|
||
uint8_t *data = in->bytes;
|
||
|
||
is(cccmac_init(cbc, cmac, key->len, key->bytes),0,"init");
|
||
|
||
byteBuffer correct_answer_k1 = hexStringToBytes(vector->SubKey1);
|
||
byteBuffer correct_answer_k2 = hexStringToBytes(vector->SubKey2);
|
||
byteBuffer answer_k1 = bytesToBytes(cccmac_k1(cmac), 16);
|
||
byteBuffer answer_k2 = bytesToBytes(cccmac_k2(cmac), 16);
|
||
byteBuffer expected_answer = hexStringToBytes(vector->Mac);
|
||
if (correct_answer_k1->len) {
|
||
showBytesAreEqual(correct_answer_k1, answer_k1, "Subkey K1 is correct");
|
||
}
|
||
if (correct_answer_k2->len) {
|
||
showBytesAreEqual(correct_answer_k2, answer_k2, "Subkey K2 is correct");
|
||
}
|
||
|
||
// Process some bytes
|
||
size_t rbytes=cc_rand(32);
|
||
size_t i;
|
||
for(i=0; (i<rbytes) && nbytes; i++) {
|
||
is(cccmac_update(cmac, 1, data), 0, "update one byte");
|
||
data+=1;
|
||
nbytes-=1;
|
||
}
|
||
for(; i<32; i++) pass("update one byte");
|
||
|
||
// Process 2 blocks
|
||
size_t blockchunck=2;
|
||
if (nbytes >= blockchunck*CMAC_BLOCKSIZE) {
|
||
is(cccmac_update(cmac, blockchunck*CMAC_BLOCKSIZE, data), 0, "update 2 blocks");
|
||
data += blockchunck*CMAC_BLOCKSIZE;
|
||
nbytes -= blockchunck*CMAC_BLOCKSIZE;
|
||
} else pass("update 2 blocks");
|
||
|
||
// Process the rest
|
||
is(cccmac_update(cmac, nbytes, data),0,"update");
|
||
|
||
if (vector->Result==0) {
|
||
cccmac_mode_decl(cbc, cmac2);
|
||
memcpy(cmac2, cmac, cccmac_ctx_size(cccmac_cbc(cmac)));
|
||
|
||
// Test generate
|
||
is(cccmac_final_generate(cmac, expected_answer->len, answer),0,"final_generate");
|
||
ok(test_cmac_answer(mode_name, vector, answer, "one-shot"), "check answer");
|
||
|
||
// Test verify
|
||
is(cccmac_final_verify(cmac2, expected_answer->len, expected_answer->bytes),0,"final_generate");
|
||
} else {
|
||
isnt(cccmac_final_verify(cmac, expected_answer->len, expected_answer->bytes),0,"detect invalid cmac");
|
||
}
|
||
free(key);
|
||
free(in);
|
||
free(correct_answer_k1);
|
||
free(correct_answer_k2);
|
||
free(answer_k1);
|
||
free(answer_k2);
|
||
free(expected_answer);
|
||
return 1;
|
||
}
|
||
|
||
|
||
static int test_negative(const struct ccmode_cbc *cbc) {
|
||
uint8_t key[32];
|
||
cccmac_mode_decl(cbc, cmac);
|
||
isnt(cccmac_init(cbc, cmac, 15,key),0,"init");
|
||
return 0;
|
||
}
|
||
|
||
|
||
static int test_cmac(const struct ccmode_cbc *cbc, char *mode_name) {
|
||
|
||
static const test_vector vector[] = {
|
||
#define keystr128 "000102030405060708090a0b0c0d0e0f"
|
||
#include "../test_vectors/CMACGenAES128.inc"
|
||
#include "../test_vectors/CMACVerAES128.inc"
|
||
#include "../test_vectors/CMACGenAES192.inc"
|
||
#include "../test_vectors/CMACVerAES192.inc"
|
||
#include "../test_vectors/CMACGenAES256.inc"
|
||
#include "../test_vectors/CMACVerAES256.inc"
|
||
{
|
||
.Count = 1, // cnt
|
||
.Key_len = 16,
|
||
.Key = "2b7e151628aed2a6abf7158809cf4f3c", // keyStr
|
||
.SubKey1 = "fbeed618357133667c85e08f7236a8de", // k1Str
|
||
.SubKey2 = "f7ddac306ae266ccf90bc11ee46d513b", // k2Str
|
||
.Msg = "", // in
|
||
.Mac = "bb1d6929e95937287fa37d129b756746", // out
|
||
.Result = 0
|
||
},
|
||
{
|
||
.Count = 2, // cnt
|
||
.Key_len = 16,
|
||
.Key = "2b7e151628aed2a6abf7158809cf4f3c", // keyStr
|
||
.SubKey1 = "fbeed618357133667c85e08f7236a8de", // k1Str
|
||
.SubKey2 = "f7ddac306ae266ccf90bc11ee46d513b", // k2Str
|
||
.Msg = "6bc1bee22e409f96e93d7e117393172a", // in
|
||
.Mac = "070a16b46b4d4144f79bdd9dd04a287c", // out
|
||
.Result = 0
|
||
},
|
||
{
|
||
.Count = 3, // cnt
|
||
.Key_len = 16,
|
||
.Key = "2b7e151628aed2a6abf7158809cf4f3c", // keyStr
|
||
.SubKey1 = "fbeed618357133667c85e08f7236a8de", // k1Str
|
||
.SubKey2 = "f7ddac306ae266ccf90bc11ee46d513b", // k2Str
|
||
.Msg = "6bc1bee22e409f96e93d7e117393172a"\
|
||
"ae2d8a571e03ac9c9eb76fac45af8e51"\
|
||
"30c81c46a35ce411", // in
|
||
.Mac = "dfa66747de9ae63030ca32611497c827", // out
|
||
.Result = 0
|
||
},
|
||
{
|
||
.Count = 4, // cnt
|
||
.Key_len = 16,
|
||
.Key = "2b7e151628aed2a6abf7158809cf4f3c", // keyStr
|
||
.SubKey1 = "fbeed618357133667c85e08f7236a8de", // k1Str
|
||
.SubKey2 = "f7ddac306ae266ccf90bc11ee46d513b", // k2Str
|
||
.Msg = "6bc1bee22e409f96e93d7e117393172a"\
|
||
"ae2d8a571e03ac9c9eb76fac45af8e51"\
|
||
"30c81c46a35ce411e5fbc1191a0a52ef"\
|
||
"f69f2445df4f9b17ad2b417be66c3710", // in
|
||
.Mac = "51f0bebf7e3b9d92fc49741779363cfe", // out
|
||
.Result = 0
|
||
},
|
||
{
|
||
.Count = 5, // cnt
|
||
.Key_len = 16,
|
||
.Key = "2b7e151628aed2a6abf7158809cf4f3c", // keyStr
|
||
.SubKey1 = "fbeed618357133667c85e08f7236a8de", // k1Str
|
||
.SubKey2 = "f7ddac306ae266ccf90bc11ee46d513b", // k2Str
|
||
.Msg = "00000000000000000000000000000001", // in
|
||
.Mac = "d9fa25e90d2fa42543939a85b543e233", // out
|
||
.Result = 0
|
||
},
|
||
};
|
||
|
||
size_t vector_size = sizeof (vector) / sizeof (test_vector);
|
||
|
||
for(size_t i = 0; i < vector_size; i++) {
|
||
ok(test_oneshot(cbc, mode_name, &vector[i]), "test one-shot AES%d_CMAC",vector[i].Key_len*8);
|
||
ok(test_discrete(cbc, mode_name, &vector[i]), "test discrete AES%d_CMAC",vector[i].Key_len*8);
|
||
}
|
||
test_negative(cbc);
|
||
return 1;
|
||
}
|
||
|
||
|
||
int cccmac_tests(TM_UNUSED int argc, TM_UNUSED char *const *argv)
|
||
{
|
||
plan_tests(50469);
|
||
if(verbose) diag("Starting cmac tests");
|
||
ok(test_cmac(ccaes_cbc_encrypt_mode(), "system cbc di"), "CMAC Tests");
|
||
return 0;
|
||
}
|
||
#endif
|