/* Copyright (c) (2010,2011,2012,2013,2014,2015,2016,2017,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 #include #include "cctest.h" #include #include "ccmode_test.h" //#define _INTERNAL_DEBUG_ 1 //#define USE_COMMONCRYPTO_GCM 1 #ifdef _INTERNAL_DEBUG_ #include #endif /* does one encryption or decryption in ECB mode and compare result */ int ccmode_ecb_test_one(const struct ccmode_ecb *ecb, size_t keylen, const void *keydata, size_t nblocks, const void *in, const void *out) { unsigned char temp[nblocks*ecb->block_size]; ccecb_ctx_decl(ecb->size, key); if (ecb->init(ecb, key, keylen, keydata)) { return -1; } if (ecb->ecb(key, nblocks, in, temp)) { return -1; } #ifdef _INTERNAL_DEBUG_ { char k[keylen*2+1]; char i[ecb->block_size*nblocks*2+1]; char o[ecb->block_size*nblocks*2+1]; char t[ecb->block_size*nblocks*2+1]; cc_bin2hex(keylen, k, keydata); cc_bin2hex(ecb->block_size*nblocks, i, in); cc_bin2hex(ecb->block_size*nblocks, o, out); cc_bin2hex(ecb->block_size*nblocks, t, temp); fprintf(stderr, "k: %s, i: %s, o:%s, t:%s\n", k, i, o, t); } #endif return memcmp(out, temp, ecb->block_size*nblocks); } /* Test one test vector - use dec=1 to reverse pt and ct */ int ccmode_ecb_test_one_vector(const struct ccmode_ecb *ecb, const struct ccmode_ecb_vector *v, int dec) { if (dec) { return ccmode_ecb_test_one(ecb, v->keylen, v->key, v->nblocks, v->ct, v->pt); } else { return ccmode_ecb_test_one(ecb, v->keylen, v->key, v->nblocks, v->pt, v->ct); } } /* Initialize a block of 'nblocks' of zeroes, Does 'loops' consecutive encryption (ECB) in place, then 'loops' decryption (ECB) in place, result should be zeroes. */ int ccmode_ecb_test_key_self(const struct ccmode_ecb *encrypt, const struct ccmode_ecb *decrypt, size_t nblocks, size_t keylen, const void *keydata, size_t loops) { unsigned char temp[nblocks*encrypt->block_size]; unsigned char zeroes[nblocks*encrypt->block_size]; ccecb_ctx_decl(decrypt->size, dkey); ccecb_ctx_decl(encrypt->size, ekey); cc_clear(nblocks*encrypt->block_size,temp); cc_clear(nblocks*encrypt->block_size,zeroes); if (encrypt->init(encrypt, ekey, keylen, keydata)) { return -1; } if (decrypt->init(decrypt, dkey, keylen, keydata)) { return -1; } for (size_t i=0; iecb(ekey, nblocks, temp, temp)) { return -1; } } for (size_t i=0; iecb(dkey, nblocks, temp, temp)) { return -1; } } return memcmp(zeroes, temp, encrypt->block_size*nblocks); } /* does one CBC encryption or decryption and compare result */ int ccmode_cbc_test_one(const struct ccmode_cbc *cbc, size_t keylen, const void *keydata, const void *iv, size_t nblocks, const void *in, const void *out) { unsigned char temp[nblocks*cbc->block_size]; if (cccbc_one_shot(cbc, keylen, keydata, iv, nblocks, in, temp)) { return -1; } return memcmp(out, temp, sizeof(temp)); } /* Test one test vector - use dec=1 to reverse pt and ct */ int ccmode_cbc_test_one_vector(const struct ccmode_cbc *cbc, const struct ccmode_cbc_vector *v, int dec) { if (dec) { return ccmode_cbc_test_one(cbc, v->keylen, v->key, v->iv, v->nblocks, v->ct, v->pt); } else { return ccmode_cbc_test_one(cbc, v->keylen, v->key, v->iv, v->nblocks, v->pt, v->ct); } } /* Test one test vector, with unaligned data */ int ccmode_cbc_test_one_vector_unaligned(const struct ccmode_cbc *cbc, const struct ccmode_cbc_vector *v, int dec) { uint8_t pt[v->nblocks*cbc->block_size+1]; uint8_t ct[v->nblocks*cbc->block_size+1]; memcpy(pt+1, v->pt, v->nblocks*cbc->block_size); memcpy(ct+1, v->ct, v->nblocks*cbc->block_size); if (dec) { return ccmode_cbc_test_one(cbc, v->keylen, v->key, v->iv, v->nblocks, ct+1, v->pt); } else { return ccmode_cbc_test_one(cbc, v->keylen, v->key, v->iv, v->nblocks, pt+1, v->ct); } } /* Test one test vector, 1 block at a time */ int ccmode_cbc_test_one_chained(const struct ccmode_cbc *cbc, size_t keylen, const void *keydata, const void *iv, size_t nblocks, const void *in, const void *out) { size_t i; const unsigned char *input=in; unsigned char temp[nblocks*cbc->block_size]; cccbc_ctx_decl(cbc->size, key); cccbc_iv_decl(cbc->block_size, iv_ctx); if (cccbc_init(cbc, key, keylen, keydata)) { return -1; } if (cccbc_set_iv(cbc, iv_ctx, iv)) { return -1; } for (i=0; iblock_size], &temp[i*cbc->block_size])) { return -1; } } return memcmp(out, temp, cbc->block_size*nblocks); } int ccmode_cbc_test_one_vector_chained(const struct ccmode_cbc *cbc, const struct ccmode_cbc_vector *v, int dec) { if (dec) { return ccmode_cbc_test_one_chained(cbc, v->keylen, v->key, v->iv, v->nblocks, v->ct, v->pt); } else { return ccmode_cbc_test_one_chained(cbc, v->keylen, v->key, v->iv, v->nblocks, v->pt, v->ct); } } /* Initialize a block of 'nblocks' of zeroes, Does 'loops' consecutive encryption (CBC) in place, then 'loops' decryption (CBC) in place, using 0 for iv in each loop, result should be zeroes. */ int ccmode_cbc_test_key_self(const struct ccmode_cbc *encrypt, const struct ccmode_cbc *decrypt, size_t nblocks, size_t keylen, const void *keydata, size_t loops) { unsigned char temp[nblocks*encrypt->block_size]; unsigned char zeroes[nblocks*encrypt->block_size]; cccbc_iv_decl(encrypt->block_size, iv); // we can use the same iv context for encrypt and decrypt // as long as we are not chaining concurrently for both. cccbc_ctx_decl(encrypt->size, ekey); cccbc_ctx_decl(decrypt->size, dkey); cc_clear(nblocks*encrypt->block_size,temp); cc_clear(nblocks*encrypt->block_size,zeroes); if (cccbc_init(encrypt, ekey, keylen, keydata)) { return -1; } for (size_t i=0; iblock_size*nblocks); } /* Encrypt and decrypt 'nblocks*loop' blocks of zeroes, 'nblocks' at a time. */ int ccmode_cbc_test_chaining_self(const struct ccmode_cbc *encrypt, const struct ccmode_cbc *decrypt, size_t nblocks, size_t keylen, const void *keydata, size_t loops) { unsigned char temp[nblocks*encrypt->block_size]; unsigned char zeroes[nblocks*encrypt->block_size]; cccbc_ctx_decl(encrypt->size, ekey); cccbc_ctx_decl(decrypt->size, dkey); /* here we have to use two iv contexts */ cccbc_iv_decl(encrypt->block_size, eiv); cccbc_iv_decl(decrypt->block_size, div); cc_clear(nblocks*encrypt->block_size,temp); cc_clear(nblocks*encrypt->block_size,zeroes); if (cccbc_init(encrypt, ekey, keylen, keydata)) { return -1; } if (cccbc_init(decrypt, dkey, keylen, keydata)) { return -1; } if (cccbc_set_iv(encrypt, eiv, NULL)) { return -1; } if (cccbc_set_iv(decrypt, div, NULL)) { return -1; } for (size_t i=0; isize, key); if (ofb->init(ofb, key, keylen, keydata, iv)) { return -1; } if (ofb->ofb(key, nbytes, in, temp)) { return -1; } return memcmp(out, temp, nbytes); } /* Test one test vector - use dec=1 to reverse pt and ct */ int ccmode_ofb_test_one_vector(const struct ccmode_ofb *ofb, const struct ccmode_ofb_vector *v, int dec) { if (dec) { return ccmode_ofb_test_one(ofb, v->keylen, v->key, v->iv, v->nbytes, v->ct, v->pt); } else { return ccmode_ofb_test_one(ofb, v->keylen, v->key, v->iv, v->nbytes, v->pt, v->ct); } } /* Test one test vector, 1 byte at a time */ int ccmode_ofb_test_one_chained(const struct ccmode_ofb *ofb, size_t keylen, const void *keydata, const void *iv, size_t nbytes, const void *in, const void *out) { size_t i; const unsigned char *input=in; unsigned char temp[nbytes]; ccofb_ctx_decl(ofb->size, key); if (ofb->init(ofb, key, keylen, keydata, iv)) { return -1; } for (i=0; iofb(key, 1, &input[i], &temp[i])) { return -1; } } return memcmp(out, temp, nbytes); } int ccmode_ofb_test_one_vector_chained(const struct ccmode_ofb *ofb, const struct ccmode_ofb_vector *v, int dec) { if (dec) { return ccmode_ofb_test_one_chained(ofb, v->keylen, v->key, v->iv, v->nbytes, v->ct, v->pt); } else { return ccmode_ofb_test_one_chained(ofb, v->keylen, v->key, v->iv, v->nbytes, v->pt, v->ct); } } /* does one CFB encryption or decryption and compare result */ int ccmode_cfb_test_one(const struct ccmode_cfb *cfb, size_t keylen, const void *keydata, const void *iv, size_t nbytes, const void *in, const void *out) { unsigned char temp[nbytes]; cccfb_ctx_decl(cfb->size, key); if (cfb->init(cfb, key, keylen, keydata, iv)) { return -1; } if (cfb->cfb(key, nbytes, in, temp)) { return -1; } return memcmp(out, temp, nbytes); } /* Test one test vector - use dec=1 to reverse pt and ct */ int ccmode_cfb_test_one_vector(const struct ccmode_cfb *cfb, const struct ccmode_cfb_vector *v, int dec) { if (dec) { return ccmode_cfb_test_one(cfb, v->keylen, v->key, v->iv, v->nbytes, v->ct, v->pt); } else { return ccmode_cfb_test_one(cfb, v->keylen, v->key, v->iv, v->nbytes, v->pt, v->ct); } } /* Test one test vector, 1 block at a time */ int ccmode_cfb_test_one_chained(const struct ccmode_cfb *cfb, size_t keylen, const void *keydata, const void *iv, size_t nbytes, const void *in, const void *out) { size_t i; const unsigned char *input=in; unsigned char temp[nbytes]; cccfb_ctx_decl(cfb->size, key); if (cfb->init(cfb, key, keylen, keydata, iv)) { return -1; } for (i=0; icfb(key, 1, &input[i], &temp[i])) { return -1; } } return memcmp(out, temp, nbytes); } int ccmode_cfb_test_one_vector_chained(const struct ccmode_cfb *cfb, const struct ccmode_cfb_vector *v, int dec) { if (dec) { return ccmode_cfb_test_one_chained(cfb, v->keylen, v->key, v->iv, v->nbytes, v->ct, v->pt); } else { return ccmode_cfb_test_one_chained(cfb, v->keylen, v->key, v->iv, v->nbytes, v->pt, v->ct); } } /* CFB8 */ /* does one CFB8 encryption or decryption and compare result */ int ccmode_cfb8_test_one(const struct ccmode_cfb8 *cfb8, size_t keylen, const void *keydata, const void *iv, size_t nbytes, const void *in, const void *out) { unsigned char temp[nbytes]; cccfb8_ctx_decl(cfb8->size, key); if (cfb8->init(cfb8, key, keylen, keydata, iv)) { return -1; } if (cfb8->cfb8(key, nbytes, in, temp)) { return -1; } return memcmp(out, temp, nbytes); } /* Test one test vector - use dec=1 to reverse pt and ct */ int ccmode_cfb8_test_one_vector(const struct ccmode_cfb8 *cfb8, const struct ccmode_cfb8_vector *v, int dec) { if (dec) { return ccmode_cfb8_test_one(cfb8, v->keylen, v->key, v->iv, v->nbytes, v->ct, v->pt); } else { return ccmode_cfb8_test_one(cfb8, v->keylen, v->key, v->iv, v->nbytes, v->pt, v->ct); } } /* Test one test vector, 1 byte at a time */ int ccmode_cfb8_test_one_chained(const struct ccmode_cfb8 *cfb8, size_t keylen, const void *keydata, const void *iv, size_t nbytes, const void *in, const void *out) { size_t i; const unsigned char *input=in; unsigned char temp[nbytes]; cccfb8_ctx_decl(cfb8->size, key); if (cfb8->init(cfb8, key, keylen, keydata, iv)) { return -1; } for (i=0; icfb8(key, 1, &input[i], &temp[i])) { return -1; } } return memcmp(out, temp, nbytes); } int ccmode_cfb8_test_one_vector_chained(const struct ccmode_cfb8 *cfb8, const struct ccmode_cfb8_vector *v, int dec) { if (dec) { return ccmode_cfb8_test_one_chained(cfb8, v->keylen, v->key, v->iv, v->nbytes, v->ct, v->pt); } else { return ccmode_cfb8_test_one_chained(cfb8, v->keylen, v->key, v->iv, v->nbytes, v->pt, v->ct); } } /* GCM */ int ccmode_gcm_test_one_chained(const struct ccmode_gcm *gcm, size_t keylen, const void *keydata, size_t ivlen, const void *iv, size_t adalen, const void *ada, size_t nbytes, const void *in, const void *out, size_t taglen, const void *tag) { /* mac and crypt one byte at a time */ size_t i; unsigned char temp[nbytes]; unsigned char temptag[taglen]; ccgcm_ctx_decl(gcm->size, key); if (gcm->init(gcm, key, keylen, keydata)) { return -1; } if (gcm->set_iv(key, ivlen, iv)) { return -1; } const unsigned char *p = ada; if (adalen) { for (i = 0; i < adalen; i++) { if (gcm->gmac(key, 1, &p[i])) { return -1; } } } else { if (gcm->gmac(key, 0, NULL)) { return -1; } } p = in; if (nbytes) { for (i = 0; i < nbytes; i++) { if (gcm->gcm(key, 1, &p[i], &temp[i])) { return -1; } } } else { if (gcm->gcm(key, 0, NULL, NULL)) { return -1; } } memcpy(temptag, tag, taglen); int rc=gcm->finalize(key, taglen, temptag); //for decryption should return zero because we passed the correct tag #ifdef _INTERNAL_DEBUG_ int r1, r2; r1 = memcmp(out, temp, nbytes); r2 = memcmp(tag, temptag, taglen); if (r1 || r2) cc_printf("ivlen: %lu adalen: %lu nbytes: %lu taglen: %lu crypt: %d tag: %d\n", ivlen, adalen, nbytes, taglen, r1, r2); return r1 != 0 ? r1 : r2; #else return rc || memcmp(out, temp, nbytes) || memcmp(tag, temptag, taglen); #endif } int ccmode_gcm_test_one_vector(const struct ccmode_gcm *gcm, const struct ccmode_gcm_vector *v, int dec) { if (v->ptlen != v->ctlen) { return -1; } char expected_tag[v->taglen]; int rc = 0; if (dec) { char pt_out[v->ptlen]; memcpy(expected_tag, v->tag, v->taglen); rc = ccgcm_one_shot(gcm, v->keylen, v->key, v->ivlen, v->iv, v->adalen, v->ada, v->ctlen, v->ct, pt_out, v->taglen, expected_tag); //this is not needed in practice, we do it because this is a test fucntion rc = rc | memcmp(pt_out, v->pt, v->ptlen) | memcmp(expected_tag, v->tag, v->taglen); }else{ char ct_out[v->ptlen]; rc = ccgcm_one_shot(gcm, v->keylen, v->key, v->ivlen, v->iv, v->adalen, v->ada, v->ptlen, v->pt, ct_out, v->taglen, expected_tag); rc = rc | memcmp(ct_out, v->ct, v->ctlen) | memcmp(expected_tag, v->tag, v->taglen); } return rc; } int ccmode_gcm_test_one_vector_chained(const struct ccmode_gcm *gcm, const struct ccmode_gcm_vector *v, int dec) { if (v->ptlen != v->ctlen) { return -1; } if (dec) { return ccmode_gcm_test_one_chained(gcm, v->keylen, v->key, v->ivlen, v->iv, v->adalen, v->ada, v->ptlen, v->ct, v->pt, v->taglen, v->tag); } else { return ccmode_gcm_test_one_chained(gcm, v->keylen, v->key, v->ivlen, v->iv, v->adalen, v->ada, v->ptlen, v->pt, v->ct, v->taglen, v->tag); } } /* does one XTS encryption or decryption and compare result */ int ccmode_xts_test_one(const struct ccmode_xts *xts, size_t keylen, const void *dkey, const void *tkey, const void *iv, size_t nbytes, const void *in, void *out, int dec) { ccxts_ctx_decl(xts->size, key); ccxts_tweak_decl(xts->tweak_size, tweak); if (xts->init(xts, key, keylen, dkey, tkey)) { return -1; } if (xts->set_tweak(key, tweak, iv)) { return -1; } /* Use raw xex mode when nbytes is a multiple of the blocksize. */ if ((nbytes & 15) == 0) { if (xts->xts(key, tweak, nbytes >> 4, in, out) == NULL) { return -1; } } else { if (dec) { if (ccpad_xts_decrypt(xts, key, tweak, nbytes, in, out) != nbytes) { return -1; } } else { ccpad_xts_encrypt(xts, key, tweak, nbytes, in, out); } } return 0; } /* Test one test vector - use dec=1 to reverse pt and ct */ int ccmode_xts_test_one_vector(const struct ccmode_xts *xts, const struct ccmode_xts_vector *v, void *out, int dec) { if (dec) { return ccmode_xts_test_one(xts, v->keylen, v->dkey, v->tkey, v->tweak, v->nbytes, v->ct, out, dec); } else { return ccmode_xts_test_one(xts, v->keylen, v->dkey, v->tkey, v->tweak, v->nbytes, v->pt, out, dec); } } /* Test one test vector, 1 block at a time */ int ccmode_xts_test_one_chained(const struct ccmode_xts *xts, size_t keylen, const void *dkey, const void *tkey, const void *iv, size_t nbytes, const void *in, void *out, int dec) { size_t i; const unsigned char *input=in; unsigned char *output=out; ccxts_ctx_decl(xts->size, key); ccxts_tweak_decl(xts->tweak_size, tweak); if (xts->init(xts, key, keylen, dkey, tkey) != 0) { return -1; } if (xts->set_tweak(key, tweak, iv)) { return -1; } size_t nblocks = nbytes >> 4; if (nbytes & 15) { nblocks -= 1; } for (i=0; i < nblocks; i++) { if (xts->xts(key, tweak, 1, &input[i*xts->block_size], &output[i*xts->block_size]) == NULL) { return -1; } } if (nbytes & 15) { nbytes -= nblocks * xts->block_size; if (dec) { if (ccpad_xts_decrypt(xts, key, tweak, nbytes, &input[nblocks*xts->block_size], &output[nblocks*xts->block_size]) != nbytes) { return -1; } } else { ccpad_xts_encrypt(xts, key, tweak, nbytes, &input[nblocks*xts->block_size], &output[nblocks*xts->block_size]); } } return 0; } int ccmode_xts_test_one_vector_chained(const struct ccmode_xts *xts, const struct ccmode_xts_vector *v, void *out, int dec) { if (dec) { return ccmode_xts_test_one_chained(xts, v->keylen, v->dkey, v->tkey, v->tweak, v->nbytes, v->ct, out, dec); } else { return ccmode_xts_test_one_chained(xts, v->keylen, v->dkey, v->tkey, v->tweak, v->nbytes, v->pt, out, dec); } } /* CCM */ int ccmode_ccm_test_one(const struct ccmode_ccm *ccm, size_t keylen, const void *keydata, size_t noncelen, const void *noncedata, size_t adalen, const void *ada, size_t nbytes, const void *in, const void *out, size_t mac_size, const void *mac, int chained) { unsigned char temp[nbytes]; unsigned char tempmac[mac_size]; ccccm_ctx_decl(ccm->size, key); ccccm_nonce_decl(ccm->nonce_size, nonce); /* mac and crypt one byte at a time */ if (chained) { if (ccm->init(ccm, key, keylen, keydata)) { return -1; } if (ccm->set_iv(key, nonce, noncelen, noncedata, mac_size, adalen, nbytes)) { return -1; } const unsigned char *p = ada; if (adalen) { for (unsigned i = 0; i < adalen; i++) { if (ccm->cbcmac(key, nonce, 1, &p[i])) { return -1; } } } else { if (ccm->cbcmac(key, nonce, 0, NULL)) { return -1; } } p = in; if (nbytes) { for (unsigned i = 0; i < nbytes; i++) { if (ccm->ccm(key, nonce, 1, &p[i], &temp[i])) { return -1; } } } else { if (ccm->ccm(key, nonce, 0, NULL, NULL)) { return -1; } } if (ccm->finalize(key, nonce, tempmac)) { return -1; } } else { if (ccccm_one_shot(ccm, keylen, keydata, noncelen, noncedata, nbytes, in, temp, adalen, ada, mac_size, tempmac)) { return -1; } } #ifdef _INTERNAL_DEBUG_ int r1, r2; r1 = memcmp(out, temp, nbytes); r2 = memcmp(mac, tempmac, mac_size); if (r1 || r2) printf("nonce_len: %u adalen: %lu nbytes: %lu taglen: %u crypt: %d tag: %d\n", nonce_len, adalen, nbytes, mac_size, r1, r2); return r1 != 0 ? r1 : r2; #else return memcmp(out, temp, nbytes) || memcmp(mac, tempmac, mac_size); #endif } /* Test one test vector - use dec=1 to reverse pt and ct */ int ccmode_ccm_test_one_vector(const struct ccmode_ccm *ccm, const struct ccmode_ccm_vector *v, int dec, int chained) { if (dec) { return ccmode_ccm_test_one(ccm, v->keylen, v->key, v->noncelen, v->nonce, v->adalen, v->ada, v->ptlen, v->ct, v->pt, (unsigned)(v->ctlen - v->ptlen), v->ct + v->ptlen, chained); } else { return ccmode_ccm_test_one(ccm, v->keylen, v->key, v->noncelen, v->nonce, v->adalen, v->ada, v->ptlen, v->pt, v->ct, (unsigned)(v->ctlen - v->ptlen), v->ct + v->ptlen, chained); } }