corecrypto/ccmode/crypto_test/crypto_test_modes.c

302 lines
13 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Copyright (c) (2012,2014-2020) 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 <stdlib.h>
#include "testmore.h"
#include "testbyteBuffer.h"
#include <corecrypto/ccmode.h>
#include "ccsymmetric.h"
#include "crypto_test_modes.h"
#include "crypto_test_modes_vectors.h" // raw data is here
#include "cc_debug.h"
static int verbose = 0;
static void report_cipher_mode(duplex_cryptor cryptor) {
char *cipherStr, *modeStr, *digestStr;
switch(cryptor->cipher) {
case cc_cipherAES: cipherStr = "AES-"; break;
case cc_cipherDES: cipherStr = "DES-"; break;
case cc_cipher3DES: cipherStr = "3DES-"; break;
case cc_cipherCAST: cipherStr = "CAST-"; break;
case cc_cipherRC2: cipherStr = "RC2-"; break;
case cc_cipherBlowfish: cipherStr = "Blowfish-"; break;
default: cipherStr = "UnknownCipher-"; break;
}
switch(cryptor->mode) {
case cc_ModeECB: modeStr = "ECB\n"; break;
case cc_ModeCBC: modeStr = "CBC\n"; break;
case cc_ModeCFB: modeStr = "CFB\n"; break;
case cc_ModeCTR: modeStr = "CTR\n"; break;
case cc_ModeOFB: modeStr = "OFB\n"; break;
case cc_ModeXTS: modeStr = "XTS\n"; break;
case cc_ModeCFB8: modeStr = "CFB8\n"; break;
case cc_ModeGCM: modeStr = "GCM\n"; break;
case cc_ModeCCM: modeStr = "CCM\n"; break;
case cc_ModeSIV: modeStr = "SIV\n"; break;
case cc_ModeSIV_HMAC: modeStr = "SIV_HMAC\n"; break;
default: modeStr = "UnknownMode\n"; break;
}
switch(cryptor->digest){
case cc_digestSHA256: digestStr = "SHA256\n"; break;
default: digestStr = "UnknownDigest --Correct if not an HMAC mode\n"; break;
}
diag("%s%s%s", cipherStr, modeStr, digestStr);
}
ccsymmetric_test_vector *vectors[cc_NCiphers][cc_NModes] = {
{ aes_ecb_vectors, aes_cbc_vectors, aes_cfb_vectors, NULL, aes_ofb_vectors, aes_xts_vectors, aes_cfb8_vectors, aes_gcm_vectors, aes_ccm_vectors,aes_siv_vectors, aes_siv_hmac_vectors}, // AES
{ des_ecb_vectors, des_cbc_vectors, des_cfb_vectors, des_ctr_vectors, des_ofb_vectors, NULL, des_cfb8_vectors, NULL, NULL }, // DES
{ des3_ecb_vectors, des3_cbc_vectors, des3_cfb_vectors, des3_ctr_vectors, des3_ofb_vectors, NULL, des3_cfb8_vectors, NULL, NULL }, // 3DES
{ cast_ecb_vectors, cast_cbc_vectors, cast_cfb_vectors, cast_ctr_vectors, cast_ofb_vectors, NULL, cast_cfb8_vectors, NULL, NULL }, // CAST
{ rc2_ecb_vectors, rc2_cbc_vectors, rc2_cfb_vectors, rc2_ctr_vectors, rc2_ofb_vectors, NULL, rc2_cfb8_vectors, NULL, NULL }, // RC2
{ blowfish_ecb_vectors, blowfish_cbc_vectors, blowfish_cfb_vectors, blowfish_ctr_vectors, blowfish_ofb_vectors, NULL, blowfish_cfb8_vectors, NULL, NULL }, // Blowfish
};
static cc_status
ccsymmetric_tests(duplex_cryptor cryptor, ccsymmetric_test_vector test) {
byteBuffer key = hexStringToBytes(test.keyStr);
byteBuffer twk = hexStringToBytes(test.twkStr);
byteBuffer init_iv = hexStringToBytes(test.init_ivStr);
byteBuffer block_iv = hexStringToBytes(test.block_ivStr);
byteBuffer adata = hexStringToBytes(test.aDataStr);
byteBuffer adata2 = hexStringToBytes(test.aData2Str);
byteBuffer pt = hexStringToBytes(test.ptStr);
byteBuffer ct = hexStringToBytes(test.ctStr);
byteBuffer tag = hexStringToBytes(test.tagStr);
size_t len_in = pt->len;
size_t len_out = ct->len;
cc_status status = 1;
cc_ciphermode_descriptor_s encrypt_desc;
cc_ciphermode_descriptor_s decrypt_desc;
encrypt_desc.cipher = decrypt_desc.cipher = cryptor->cipher;
encrypt_desc.mode = decrypt_desc.mode = cryptor->mode;
encrypt_desc.direction = cc_Encrypt;
decrypt_desc.direction = cc_Decrypt;
encrypt_desc.ciphermode = cryptor->encrypt_ciphermode;
decrypt_desc.ciphermode = cryptor->decrypt_ciphermode;
MAKE_GENERIC_MODE_CONTEXT(encrypt_ctx, &encrypt_desc);
MAKE_GENERIC_MODE_CONTEXT(decrypt_ctx, &decrypt_desc);
if(verbose) report_cipher_mode(cryptor);
//--------------------------------------------------------------------------
// Known answer test
//--------------------------------------------------------------------------
switch(cryptor->mode) {
case cc_ModeECB:
case cc_ModeCBC:
case cc_ModeCFB:
case cc_ModeCTR:
case cc_ModeOFB:
case cc_ModeCFB8:
ok_or_fail((cc_symmetric_setup(&encrypt_desc, key->bytes, key->len, init_iv->bytes, encrypt_ctx) == 0), "cipher-mode is initted");
ok_or_fail((cc_symmetric_setup(&decrypt_desc, key->bytes, key->len, init_iv->bytes, decrypt_ctx) == 0), "cipher-mode is initted");
break;
case cc_ModeXTS:
ok_or_fail((cc_symmetric_setup_tweaked(&encrypt_desc, key->bytes, key->len, twk->bytes, init_iv->bytes, encrypt_ctx) == 0), "cipher-mode is initted");
ok_or_fail((cc_symmetric_setup_tweaked(&decrypt_desc, key->bytes, key->len, twk->bytes, init_iv->bytes, decrypt_ctx) == 0), "cipher-mode is initted");
break;
case cc_ModeSIV_HMAC:
case cc_ModeCCM:
case cc_ModeGCM:
case cc_ModeSIV:
ok_or_fail((cc_symmetric_setup_authenticated(&encrypt_desc, key->bytes, key->len, init_iv->bytes, init_iv->len,
adata->bytes, adata->len, adata2->bytes, adata2->len,
len_in, tag->len, encrypt_ctx) == 0), "cipher-mode is initted");
ok_or_fail((cc_symmetric_setup_authenticated(&decrypt_desc, key->bytes, key->len, init_iv->bytes, init_iv->len,
adata->bytes, adata->len, adata2->bytes, adata2->len,
len_out, tag->len, decrypt_ctx) == 0), "cipher-mode is initted");
break;
default:
break;
}
uint8_t in[len_in], out[len_out];
ok_or_fail(cc_symmetric_crypt((cc_symmetric_context_p) encrypt_ctx, block_iv->bytes, pt->bytes, out, len_in) == 0,
"cc_symmetric_crypt encrypt");
if(test.ctStr) {
ok_memcmp_or_fail(out, ct->bytes, len_out, "ciphertext as expected");
} else if(verbose) {
byteBuffer result = bytesToBytes(out, len_out);
diag("Round Trip Results\n");
printByteBufferAsCharAssignment(pt, "pt");
printByteBufferAsCharAssignment(result, "ct");
free(result);
return 1;
}
ok_or_fail(cc_symmetric_crypt((cc_symmetric_context_p) decrypt_ctx, block_iv->bytes, out, in, len_out) == 0,
"cc_symmetric_crypt decrypt");
ok_memcmp_or_fail(in, pt->bytes, len_in, "plaintext as expected");
if ((cryptor->mode == cc_ModeGCM)
|| (cryptor->mode == cc_ModeCCM)){
size_t len = tag->len;
char returned_tag[len];
cc_clear(len, returned_tag);
ok_or_fail(cc_symmetric_authenticated_finalize((cc_symmetric_context_p) encrypt_ctx, returned_tag, len) == 0,
"cc_symmetric_authenticated_finalize encrypt");
ok_or_fail(cc_symmetric_authenticated_finalize((cc_symmetric_context_p) decrypt_ctx, returned_tag, len) == 0,
"cc_symmetric_authenticated_finalize decrypt");
if(test.tagStr) {
ok_memcmp_or_fail(returned_tag, tag->bytes, len, "computed and expected tags match");
} else {
byteBuffer result = bytesToBytes(returned_tag, len);
diag("Round Trip Tags\n");
printByteBufferAsCharAssignment(result, "tagStr");
free(result);
}
}
//--------------------------------------------------------------------------
// Usage test
//--------------------------------------------------------------------------
switch(cryptor->mode) {
case cc_ModeECB:
case cc_ModeCBC:
case cc_ModeCFB:
case cc_ModeCTR:
case cc_ModeOFB:
case cc_ModeCFB8:
case cc_ModeGCM:
case cc_ModeCCM:
break;
case cc_ModeSIV:
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
// Encrypt again => expect failure with SIV
ok_or_fail(cc_symmetric_crypt((cc_symmetric_context_p) encrypt_ctx, block_iv->bytes, pt->bytes, out, len_in) != 0,
"Negative test: cc_symmetric_crypt encrypt");
ok_or_fail(cc_symmetric_crypt((cc_symmetric_context_p) decrypt_ctx, block_iv->bytes, out, in, len_out) != 0,
"Negative test: cc_symmetric_crypt decrypt");
// Reset
ok_or_fail(cc_symmetric_reset((cc_symmetric_context_p) encrypt_ctx) == 0,
"cc_symmetric_reset reset");
ok_or_fail(cc_symmetric_reset((cc_symmetric_context_p) decrypt_ctx) == 0,
"cc_symmetric_reset reset");
// Success after reset
ok_or_fail(cc_symmetric_crypt((cc_symmetric_context_p) encrypt_ctx, block_iv->bytes, pt->bytes, out, len_in) == 0,
"After reset cc_symmetric_crypt encrypt");
ok_or_fail(cc_symmetric_crypt((cc_symmetric_context_p) decrypt_ctx, block_iv->bytes, out, in, len_out) == 0,
"After reset cc_symmetric_crypt decrypt");
if (adata->len==0 && adata2->len==0 && init_iv->len==0) {
ok_memcmp_or_fail(out, ct->bytes, len_out, "ciphertext as expected");
ok_memcmp_or_fail(in, pt->bytes, len_in, "plaintext as expected");
}
break;
default:
break;
}
//--------------------------------------------------------------------------
free(key);
free(twk);
free(init_iv);
free(block_iv);
free(adata);
free(adata2);
free(pt);
free(tag);
free(ct);
return status;
}
static int
run_symmetric_vectors(duplex_cryptor cryptor) {
ccsymmetric_test_vector *run_vector = vectors[cryptor->cipher][cryptor->mode];
for(int i=0; run_vector[i].keyStr != NULL; i++) {
ccsymmetric_test_vector test = run_vector[i];
ok_or_fail(ccsymmetric_tests(cryptor, test), "Test Vector %d",i);
}
return 1;
}
int test_mode(ciphermode_t encrypt_ciphermode, ciphermode_t decrypt_ciphermode, cc_cipher_select cipher, cc_mode_select mode) {
duplex_cryptor_s cryptor;
cryptor.cipher = cipher;
cryptor.mode = mode;
cryptor.encrypt_ciphermode = encrypt_ciphermode;
cryptor.decrypt_ciphermode = decrypt_ciphermode;
cryptor.digest = cc_NDigest;
ok_or_fail(run_symmetric_vectors(&cryptor), "Cipher-Mode Test");
// Switch to allow testing for properties that are specific to a given node
switch(mode) {
case cc_ModeSIV:
test_aes_siv_corner_cases(&cryptor);
break;
default:
break;
}
return 1;
}
int test_hmac_mode(ciphermode_t encrypt_ciphermode, ciphermode_t decrypt_ciphermode, cc_cipher_select cipher, cc_mode_select mode, cc_digest_select digest) {
duplex_cryptor_s cryptor;
cryptor.cipher = cipher;
cryptor.mode = mode;
cryptor.digest = digest;
cryptor.encrypt_ciphermode = encrypt_ciphermode;
cryptor.decrypt_ciphermode = decrypt_ciphermode;
ok_or_fail (test_siv_hmac_corner_cases(&cryptor), "siv_hmac corner case tests");
ok_or_fail(run_symmetric_vectors(&cryptor), "Cipher-Mode Test");
return 1;
}
int test_siv_hmac_corner_cases(duplex_cryptor cryptor)
{
cc_ciphermode_descriptor_s encrypt_desc;
cc_ciphermode_descriptor_s decrypt_desc;
encrypt_desc.cipher = decrypt_desc.cipher = cryptor->cipher;
encrypt_desc.mode = decrypt_desc.mode = cryptor->mode;
encrypt_desc.direction = cc_Encrypt;
encrypt_desc.ciphermode = cryptor->encrypt_ciphermode;
MAKE_GENERIC_MODE_CONTEXT(encrypt_ctx, &encrypt_desc);
ccmode_siv_hmac_state_tests(&encrypt_desc, encrypt_ctx);
return 1;
}
int test_aes_siv_corner_cases(duplex_cryptor cryptor)
{
cc_ciphermode_descriptor_s encrypt_desc;
cc_ciphermode_descriptor_s decrypt_desc;
encrypt_desc.cipher = decrypt_desc.cipher = cryptor->cipher;
encrypt_desc.mode = decrypt_desc.mode = cryptor->mode;
encrypt_desc.direction = cc_Encrypt;
decrypt_desc.direction = cc_Decrypt;
encrypt_desc.ciphermode = cryptor->encrypt_ciphermode;
decrypt_desc.ciphermode = cryptor->decrypt_ciphermode;
MAKE_GENERIC_MODE_CONTEXT(encrypt_ctx, &encrypt_desc);
MAKE_GENERIC_MODE_CONTEXT(decrypt_ctx, &decrypt_desc);
ccmode_aes_siv_encrypt_decrypt_in_place_tests(&encrypt_desc, encrypt_ctx, &decrypt_desc, decrypt_ctx);
return 1;
}