corecrypto/ccmode/crypto_test/crypto_test_ccm.c

181 lines
7.0 KiB
C
Raw 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) (2018-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 <corecrypto/ccaes.h>
#include <corecrypto/ccmode.h>
#include <corecrypto/ccmode_factory.h>
#include <corecrypto/ccmode_internal.h>
#include <corecrypto/ccn.h>
#include "xcunit/ccmode_test.h"
#include "crypto_test_modes.h"
#include "testbyteBuffer.h"
#include "testmore.h"
static int verbose = 0;
// to do: make sure this structure makes sense for CCM, as opposed to GCM
typedef struct ccccm_test_t {
char *keyStr;
char *aDataStr;
char *init_ivStr;
char *ptStr;
char *ctStr;
char *tagStr;
} ccccm_test_vector;
// Redundant tests, there are already run as part of crypto_test_modes.c
// however, this file does testing that crypto_test_modes does not support
// This file looks generic but ccm_vectors only contains test for AES
// and there is no way to specify another block cipher.
// crypto_test_modes is really generic.
// Function that is used to test ccm mode authenticated encryption with its most basic functionality
// with calls to set_iv, followed by calls to the cbcmac, and then the encryption followed by a call to finalize.
static int ccccm_discrete(const struct ccmode_ccm *mode,
size_t key_len, const void *key,
size_t nonce_len, const void *nonce,
size_t nbytes, const void *in, void *out,
size_t adata_len, const void *adata,
size_t tag_len, void *tag)
{
size_t max_block_len = cc_rand(19);
if(max_block_len == 0) {
max_block_len = 1;
}
if(verbose){
printf("\n------max_block_len=%zu\n", max_block_len);
}
int rc = 0;
ccccm_ctx_decl(mode->size, ctx);
ccccm_nonce_decl(mode->nonce_size, nonce_ctx);
rc |= mode->init(mode, ctx, key_len, key);
rc |= mode->set_iv(ctx, nonce_ctx, nonce_len, nonce, tag_len, adata_len, nbytes);
if(adata_len > 0 && adata != NULL) {
if (adata_len>max_block_len) {
size_t d1 = adata_len-max_block_len;
rc |= mode->cbcmac(ctx, nonce_ctx, max_block_len, adata);
rc |= mode->cbcmac(ctx, nonce_ctx, d1, adata+max_block_len);
} else {
rc |= mode->cbcmac(ctx, nonce_ctx, adata_len, adata);
}
} else {
if(verbose) printf("Skipping added AAD\n");
}
if(nbytes > 0) {
rc |= mode->ccm(ctx, nonce_ctx, nbytes, in, out);
} else {
if(verbose) printf("Skipping data\n");
}
rc |= mode->finalize(ctx,nonce_ctx, tag);
ccccm_ctx_clear(mode->size, ctx);
return rc;
}
typedef int (*ccccm_test_func_t)(const struct ccmode_ccm *mode,
size_t key_len, const void *key,
size_t iv_len, const void *iv,
size_t nbytes, const void *in, void *out,
size_t adata_len, const void *adata,
size_t tag_len, void *tag);
static int ccm_test_a_function(const struct ccmode_ccm *em, const struct ccmode_ccm *dm,
size_t key_len, const void *key,
size_t iv_len, const void *iv,
size_t nbytes, const void *plaintext, void *ciphertext,
size_t adata_len, const void *adata,
size_t tag_len, void *tag,
ccccm_test_func_t func)
{
uint8_t cipher_result[nbytes], plain_result[nbytes];
uint8_t cipher_tag[tag_len], plain_tag[tag_len];
int rc;
rc = func(em, key_len, key, iv_len, iv, nbytes, plaintext, cipher_result, adata_len, adata, tag_len, cipher_tag);
ok_or_fail(rc == 0, "ccm encryption failed");
memcpy(plain_tag, tag, tag_len); //set the expected tag for decryption
rc = func(dm, key_len, key, iv_len, iv, nbytes, cipher_result, plain_result, adata_len, adata, tag_len, plain_tag );
ok_or_fail(rc == 0, "ccm decryption failed");
ok_memcmp_or_fail(plaintext, plain_result, nbytes, "Round Trip Encrypt/Decrypt works");
ok_memcmp_or_fail(tag, cipher_tag, tag_len, "tags match on encrypt");
ok_memcmp_or_fail(tag, plain_tag, tag_len, "tags match on decrypt");
ok_memcmp_or_fail(ciphertext, cipher_result, nbytes, "Ciphertext matches known answer");
return 1;
}
static int ccm_testcase(const struct ccmode_ccm *enc, const struct ccmode_ccm *dec)
{
//Structure that contains test vectors that allow large adata by defining a repeat factor for adata
struct iterated_adata_ccm_test_vector large_adata_vec_array[] = {
#include "../test_vectors/ccm_aes_128_long_adata_test_vectors.inc"
};
// Testing for different sizes of adata in ccm mode using AES128.
unsigned int num_adata_vectors = sizeof(large_adata_vec_array) / sizeof(large_adata_vec_array[0]);
for (unsigned int i = 0; i < num_adata_vectors; i++) {
struct iterated_adata_ccm_test_vector *tmp_lvec=&(large_adata_vec_array[i]);
// Generate adata by concatenating string appropriate number of times.
size_t tmp_adata_n=tmp_lvec->aData_iterated_string_n * tmp_lvec->aData_num_of_iterations;
char *tmp_adata = malloc(tmp_adata_n);
for (size_t j = 0; j < tmp_lvec->aData_num_of_iterations; j++) {
memcpy(&tmp_adata[j*tmp_lvec->aData_iterated_string_n], tmp_lvec->iterated_string, tmp_lvec->aData_iterated_string_n);
}
ccm_test_a_function(enc, dec,
tmp_lvec->key_n, tmp_lvec->key,
tmp_lvec->nonce_n, tmp_lvec->nonce,
tmp_lvec-> pdata_n, tmp_lvec->pdata,
tmp_lvec->enc_data,
tmp_adata_n, tmp_adata,
tmp_lvec->tag_n, tmp_lvec->tag,
ccccm_discrete);
ccm_test_a_function(enc, dec,
tmp_lvec->key_n, tmp_lvec->key,
tmp_lvec->nonce_n, tmp_lvec->nonce,
tmp_lvec-> pdata_n,
tmp_lvec->pdata, tmp_lvec->enc_data,
tmp_adata_n, tmp_adata,
tmp_lvec->tag_n, tmp_lvec->tag,
ccccm_one_shot);
if(verbose){
printf("ccm_testcase %d\n", i);
}
free(tmp_adata);
}
return 1;
}
int test_ccm(const struct ccmode_ccm *encrypt_ciphermode, const struct ccmode_ccm *decrypt_ciphermode)
{
ccm_testcase(encrypt_ciphermode, decrypt_ciphermode);
return 1;
}