/* Copyright (c) (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 #include #include #include "ccmode_internal.h" #include "crypto_test_modes.h" #include "testbyteBuffer.h" #include "testmore.h" static int verbose = 0; typedef struct ccgcm_test_t { char *keyStr; //key char *aDataStr; //additional data char *init_ivStr; //initialization vector char *ptStr; //plain text char *ctStr; //cipher text char *tagStr; //tag } ccgcm_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 gcm_vectors only contains test for AES // and there is no way to specify another block cipher. // crypto_test_modes is really generic. ccgcm_test_vector gcm_vectors[] = { #include "../test_vectors/aes_gcm_test_vectors_ossl.inc" #include "../test_vectors/aes_gcm_test_vectors.inc" }; size_t nvectors = sizeof(gcm_vectors) / sizeof(ccgcm_test_vector); static int ccgcm_discrete(const struct ccmode_gcm *mode, size_t key_len, const void *key, size_t iv_len, const void *iv, size_t adata_len, const void *adata, size_t nbytes, const void *in, void *out, 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; ccgcm_ctx_decl(mode->size, ctx); mode->init(mode, ctx, key_len, key); if(iv_len > 0 && iv != NULL) { rc |= mode->set_iv(ctx, iv_len, iv); } if(adata_len > 0 && adata != NULL) { if (adata_len>max_block_len) { size_t d1 = adata_len-max_block_len; rc |= mode->gmac(ctx, max_block_len, adata); rc |= mode->gmac(ctx, d1, adata+max_block_len); } else { rc |= mode->gmac(ctx, adata_len, adata); } } else { if(verbose) printf("Skipping added AAD\n"); } if(nbytes > 0) { rc |= mode->gcm(ctx, nbytes, in, out); } else { if(verbose) printf("Skipping data\n"); } rc |= mode->finalize(ctx, tag_len, tag); ccgcm_ctx_clear(mode->size, ctx); return rc; } typedef int (*ccgcm_test_func_t)(const struct ccmode_gcm *mode, size_t key_len, const void *key, size_t iv_len, const void *iv, size_t adata_len, const void *adata, size_t nbytes, const void *in, void *out, size_t tag_len, void *tag); static int gcm_test_a_function(const struct ccmode_gcm *em, const struct ccmode_gcm *dm, size_t key_len, const void *key, size_t iv_len, const void *iv, size_t adata_len, const void *adata, size_t nbytes, const void *plaintext, void *ciphertext, size_t tag_len, void *tag, ccgcm_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, adata_len, adata, nbytes, plaintext, cipher_result, tag_len, cipher_tag); ok_or_fail(rc==0, "gcm encryption failed"); memcpy(plain_tag, tag, tag_len); //set the expected tag for decryption rc = func(dm, key_len, key, iv_len, iv, adata_len, adata, nbytes, cipher_result, plain_result, tag_len, plain_tag ); ok_or_fail(rc==0, "gcm 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"); plain_tag[0] ^= 1; rc = func(dm, key_len, key, iv_len, iv, adata_len, adata, nbytes, cipher_result, plain_result, tag_len, plain_tag ); ok_or_fail(rc != 0, "gcm authentication failed"); return 1; } static int gcm_testcase(const struct ccmode_gcm *encrypt_ciphermode, const struct ccmode_gcm *decrypt_ciphermode, size_t casenum) { size_t i=casenum; byteBuffer key = hexStringToBytes(gcm_vectors[i].keyStr); byteBuffer iv = hexStringToBytes(gcm_vectors[i].init_ivStr); byteBuffer adata = hexStringToBytes(gcm_vectors[i].aDataStr); byteBuffer plaintext = hexStringToBytes(gcm_vectors[i].ptStr); byteBuffer ciphertext = hexStringToBytes(gcm_vectors[i].ctStr); byteBuffer tag = hexStringToBytes(gcm_vectors[i].tagStr); if(verbose) printf("GCM Case %zu\n", casenum); gcm_test_a_function(encrypt_ciphermode, decrypt_ciphermode, key->len, key->bytes, iv->len, iv->bytes, adata->len, adata->bytes, plaintext->len, plaintext->bytes, ciphertext->bytes, tag->len, tag->bytes, ccgcm_discrete); gcm_test_a_function(encrypt_ciphermode, decrypt_ciphermode, key->len, key->bytes, iv->len, iv->bytes, adata->len, adata->bytes, plaintext->len, plaintext->bytes, ciphertext->bytes, tag->len, tag->bytes, ccgcm_one_shot); gcm_test_a_function(encrypt_ciphermode, decrypt_ciphermode, key->len, key->bytes, iv->len, iv->bytes, adata->len, adata->bytes, plaintext->len, plaintext->bytes, ciphertext->bytes, tag->len, tag->bytes, ccgcm_one_shot_legacy); free(key); free(iv); free(adata); free(plaintext); free(ciphertext); free(tag); return 1; } static int gcm_test_zerolen_iv(const struct ccmode_gcm *encrypt_ciphermode, const struct ccmode_gcm *decrypt_ciphermode) { int rc; byteBuffer key = hexStringToBytes("59454c4c4f57205355424d4152494e45"); byteBuffer ad = hexStringToBytes("0000005a"); byteBuffer ptext = hexStringToBytes("506f69736f6e6f7573207061726167726170687320736d61736820796f75722070686f6e6f677261706820696e2068616c660a49742062652074686520496e73706563746168204465636b206f6e207468652077617270617468"); byteBuffer ctext = hexStringToBytes("3a8fbd9d5e5d53663664c8a67ca82c22d09b932a18fb18a37814330955bf55b73aef15a678182f42b9b0f7d8137b7c30dc09123ab9b150b8e04d65532e223e6a4eacc98275f75e113e9daf8598b7445fe04ec754bfe914bd65e8"); byteBuffer tag = hexStringToBytes("226a3338b54f22819e933c242746f303"); uint8_t textout[ptext->len]; uint8_t tagout[tag->len]; rc = ccgcm_one_shot(encrypt_ciphermode, key->len, key->bytes, 0, NULL, ad->len, ad->bytes, ptext->len, ptext->bytes, textout, sizeof (tagout), tagout); ok_or_fail(rc != 0, "gcm one-shot encryption accepted zero-length iv"); rc = ccgcm_discrete(encrypt_ciphermode, key->len, key->bytes, 0, NULL, ad->len, ad->bytes, ptext->len, ptext->bytes, textout, sizeof (tagout), tagout); ok_or_fail(rc != 0, "gcm discrete encryption accepted zero-length iv"); rc = ccgcm_one_shot_legacy(encrypt_ciphermode, key->len, key->bytes, 0, NULL, ad->len, ad->bytes, ptext->len, ptext->bytes, textout, sizeof (tagout), tagout); ok_or_fail(rc == 0, "gcm one-shot legacy encryption failed"); ok_memcmp_or_fail(ctext->bytes, textout, ctext->len, "gcm one-shot legacy encryption text mismatch"); ok_memcmp_or_fail(tag->bytes, tagout, tag->len, "gcm one-shot legacy encryption tag mismatch"); rc = ccgcm_one_shot(decrypt_ciphermode, key->len, key->bytes, 0, NULL, ad->len, ad->bytes, ctext->len, ctext->bytes, textout, sizeof (tagout), tagout); ok_or_fail(rc != 0, "gcm one-shot decryption accepted zero-length iv"); rc = ccgcm_discrete(decrypt_ciphermode, key->len, key->bytes, 0, NULL, ad->len, ad->bytes, ctext->len, ctext->bytes, textout, sizeof (tagout), tagout); ok_or_fail(rc != 0, "gcm discrete decryption accepted zero-length iv"); rc = ccgcm_one_shot_legacy(decrypt_ciphermode, key->len, key->bytes, 0, NULL, ad->len, ad->bytes, ctext->len, ctext->bytes, textout, sizeof (tagout), tagout); ok_or_fail(rc == 0, "gcm legacy decryption failed"); ok_memcmp_or_fail(ptext->bytes, textout, ptext->len, "gcm one-shot legacy decryption text mismatch"); ok_memcmp_or_fail(tag->bytes, tagout, tag->len, "gcm one-shot legacy decryption tag mismatch"); free(key); free(tag); free(ad); free(ptext); free(ctext); return 1; } static int gcm_test_init_with_iv(const struct ccmode_gcm *encrypt_ciphermode, const struct ccmode_gcm *decrypt_ciphermode) { // int rc; byteBuffer key = hexStringToBytes("e792232af1917965d75fc9b65a87f656"); byteBuffer iv1 = hexStringToBytes("c7ccdafe0000000000000000"); byteBuffer iv2 = hexStringToBytes("c7ccdafe0000000000000001"); byteBuffer ad = hexStringToBytes("04d7e6bd00cca0947da2"); byteBuffer ptext = hexStringToBytes("576f772c20746865205368616f6c696e207374796c6520697320616c6c20696e206d650a4368696c642c207468652077686f6c652064616d6e2069736c652069732063616c6c696e206d650a"); byteBuffer ctext1 = hexStringToBytes("f90a4f9c1250849af5289066aad8c10f67ffc2ca5799e58d8b49cc6f22c495f56f46adb18c3b21b4710306dffc88ce9a7252ba92b74b35db08221d8dca7aed27105b0d1a812bd10e49af2345"); byteBuffer tag1 = hexStringToBytes("73d833e2d55d741743b09e0e07c6d610"); byteBuffer ctext2 = hexStringToBytes("d075317f57fc20ff37832f507e90c84fd311a0a160b59084217b642829028dcef56ffa73db659bf250ab97eda2df50635d1fc29f6e2dbbc651acd4e747ed7577805a61708bec9ad8e272cce4"); byteBuffer tag2 = hexStringToBytes("298184a805bede8490c0da2cf19e7b0e"); uint8_t ivout[iv1->len]; uint8_t textout[ptext->len]; uint8_t tagout[tag1->len]; ccgcm_ctx_decl(ccgcm_context_size(encrypt_ciphermode), encrypt_ctx); ccgcm_ctx_decl(ccgcm_context_size(decrypt_ciphermode), decrypt_ctx); ok_or_fail(ccgcm_init_with_iv(encrypt_ciphermode, encrypt_ctx, key->len, key->bytes, iv1->bytes) == 0, "ccgcm_init_with_iv encrypt1"); ok_or_fail(ccgcm_aad(encrypt_ciphermode, encrypt_ctx, ad->len, ad->bytes) == 0, "ccgcm_aad encrypt1"); ok_or_fail(ccgcm_update(encrypt_ciphermode, encrypt_ctx, ptext->len, ptext->bytes, textout) == 0, "ccgcm_update encrypt1"); ok_or_fail(ccgcm_finalize(encrypt_ciphermode, encrypt_ctx, tag1->len, tagout) == 0, "ccgcm_finalize encrypt1"); ok_memcmp(ctext1->bytes, textout, ctext1->len, "ctext1 encrypt1"); ok_memcmp(tag1->bytes, tagout, tag1->len, "tag1 encrypt1"); ok_or_fail(ccgcm_init_with_iv(decrypt_ciphermode, decrypt_ctx, key->len, key->bytes, iv1->bytes) == 0, "ccgcm_init_with_iv decrypt1"); ok_or_fail(ccgcm_aad(decrypt_ciphermode, decrypt_ctx, ad->len, ad->bytes) == 0, "ccgcm_aad decrypt1"); ok_or_fail(ccgcm_update(decrypt_ciphermode, decrypt_ctx, ctext1->len, ctext1->bytes, textout) == 0, "ccgcm_update decrypt1"); ok_or_fail(ccgcm_finalize(decrypt_ciphermode, decrypt_ctx, tag1->len, tagout) == 0, "ccgcm_finalize decrypt1"); ok_memcmp(ptext->bytes, textout, ptext->len, "ptext decrypt1"); ok_memcmp(tag1->bytes, tagout, tag1->len, "tag1 decrypt1"); ok_or_fail(ccgcm_reset(encrypt_ciphermode, encrypt_ctx) == 0, "ccgcm_reset encrypt2"); ok_or_fail(ccgcm_inc_iv(encrypt_ciphermode, encrypt_ctx, ivout) == 0, "ccgcm_inc_iv encrypt2"); ok_or_fail(ccgcm_aad(encrypt_ciphermode, encrypt_ctx, ad->len, ad->bytes) == 0, "ccgcm_aad encrypt2"); ok_or_fail(ccgcm_update(encrypt_ciphermode, encrypt_ctx, ptext->len, ptext->bytes, textout) == 0, "ccgcm_update encrypt2"); ok_or_fail(ccgcm_finalize(encrypt_ciphermode, encrypt_ctx, tag2->len, tagout) == 0, "ccgcm_finalize encrypt2"); ok_memcmp(iv2->bytes, ivout, iv2->len, "iv2 encrypt2"); ok_memcmp(ctext2->bytes, textout, ctext2->len, "ctext2 encrypt2"); ok_memcmp(tag2->bytes, tagout, tag2->len, "tag2 encrypt2"); ok_or_fail(ccgcm_reset(decrypt_ciphermode, decrypt_ctx) == 0, "ccgcm_reset decrypt2"); ok_or_fail(ccgcm_inc_iv(decrypt_ciphermode, decrypt_ctx, ivout) == 0, "ccgcm_inc_iv decrypt2"); ok_or_fail(ccgcm_aad(decrypt_ciphermode, decrypt_ctx, ad->len, ad->bytes) == 0, "ccgcm_aad decrypt2"); ok_or_fail(ccgcm_update(decrypt_ciphermode, decrypt_ctx, ctext2->len, ctext2->bytes, textout) == 0, "ccgcm_update decrypt2"); ok_or_fail(ccgcm_finalize(decrypt_ciphermode, decrypt_ctx, tag2->len, tagout) == 0, "ccgcm_finalize decrypt2"); ok_memcmp(iv2->bytes, ivout, iv2->len, "iv2 decrypt2"); ok_memcmp(ptext->bytes, textout, ptext->len, "ptext decrypt2"); ok_memcmp(tag2->bytes, tagout, tag2->len, "tag2 decrypt2"); ok_or_fail(ccgcm_init_with_iv(encrypt_ciphermode, encrypt_ctx, key->len, key->bytes, iv1->bytes) == 0, "ccgcm_init_with_iv encrypt no-set-iv"); ok_or_fail(ccgcm_reset(encrypt_ciphermode, encrypt_ctx) == 0, "ccgcm_reset encrypt no-set-iv"); ok_or_fail(ccgcm_set_iv(encrypt_ciphermode, encrypt_ctx, iv2->len, iv2->bytes) != 0, "ccgcm_set_iv encrypt no-set-iv"); ok_or_fail(ccgcm_init_with_iv(decrypt_ciphermode, decrypt_ctx, key->len, key->bytes, iv1->bytes) == 0, "ccgcm_init_with_iv decrypt no-set-iv"); ok_or_fail(ccgcm_reset(decrypt_ciphermode, decrypt_ctx) == 0, "ccgcm_reset decrypt no-set-iv"); ok_or_fail(ccgcm_set_iv(decrypt_ciphermode, decrypt_ctx, iv2->len, iv2->bytes) != 0, "ccgcm_set_iv decrypt no-set-iv"); ok_or_fail(ccgcm_init(encrypt_ciphermode, encrypt_ctx, key->len, key->bytes) == 0, "ccgcm_init_with_iv encrypt no-inc-iv"); ok_or_fail(ccgcm_set_iv(encrypt_ciphermode, encrypt_ctx, iv1->len, iv1->bytes) == 0, "ccgcm_set_iv encrypt no-inc-iv"); ok_or_fail(ccgcm_reset(encrypt_ciphermode, encrypt_ctx) == 0, "ccgcm_reset encrypt no-inc-iv"); ok_or_fail(ccgcm_inc_iv(encrypt_ciphermode, encrypt_ctx, ivout) != 0, "ccgcm_set_iv encrypt no-inc-iv"); ok_or_fail(ccgcm_init(decrypt_ciphermode, decrypt_ctx, key->len, key->bytes) == 0, "ccgcm_init_with_iv decrypt no-inc-iv"); ok_or_fail(ccgcm_set_iv(decrypt_ciphermode, decrypt_ctx, iv1->len, iv1->bytes) == 0, "ccgcm_set_iv decrypt no-inc-iv"); ok_or_fail(ccgcm_reset(decrypt_ciphermode, decrypt_ctx) == 0, "ccgcm_reset decrypt no-inc-iv"); ok_or_fail(ccgcm_inc_iv(decrypt_ciphermode, decrypt_ctx, ivout) != 0, "ccgcm_set_iv decrypt no-inc-iv"); free(key); free(iv1); free(iv2); free(ad); free(ptext); free(ctext1); free(tag1); free(ctext2); free(tag2); return 1; } /* In this test we reach into the internal state to trigger the validation error on long messages. */ static int gcm_test_counter_wrap(const struct ccmode_gcm *encrypt_ciphermode, const struct ccmode_gcm *decrypt_ciphermode) { uint8_t buf[CCGCM_BLOCK_NBYTES] = { 0 }; ccgcm_ctx_decl(ccgcm_context_size(encrypt_ciphermode), encrypt_ctx); ccgcm_ctx_decl(ccgcm_context_size(decrypt_ciphermode), decrypt_ctx); ok_or_fail(ccgcm_init(encrypt_ciphermode, encrypt_ctx, CCAES_KEY_SIZE_128, buf) == 0, "ccgcm_init encrypt counter wrap"); ok_or_fail(ccgcm_set_iv(encrypt_ciphermode, encrypt_ctx, CCGCM_IV_NBYTES, buf) == 0, "ccgcm_set encrypt counter wrap"); ok_or_fail(ccgcm_update(encrypt_ciphermode, encrypt_ctx, sizeof (buf), buf, buf) == 0, "ccgcm_update (begin) encrypt counter wrap"); ((struct _ccmode_gcm_key *)encrypt_ctx)->text_nbytes = CCGCM_TEXT_MAX_NBYTES - CCGCM_BLOCK_NBYTES; ok_or_fail(ccgcm_update(encrypt_ciphermode, encrypt_ctx, sizeof (buf), buf, buf) == 0, "ccgcm_update (end) encrypt counter wrap"); ok_or_fail(ccgcm_update(encrypt_ciphermode, encrypt_ctx, 1, buf, buf) == CCMODE_INVALID_INPUT, "ccgcm_update (overflow) encrypt counter wrap"); ok_or_fail(ccgcm_init(decrypt_ciphermode, decrypt_ctx, CCAES_KEY_SIZE_128, buf) == 0, "ccgcm_init decrypt counter wrap"); ok_or_fail(ccgcm_set_iv(decrypt_ciphermode, decrypt_ctx, CCGCM_IV_NBYTES, buf) == 0, "ccgcm_set decrypt counter wrap"); ok_or_fail(ccgcm_update(decrypt_ciphermode, decrypt_ctx, sizeof (buf), buf, buf) == 0, "ccgcm_update (begin) decrypt counter wrap"); ((struct _ccmode_gcm_key *)decrypt_ctx)->text_nbytes = CCGCM_TEXT_MAX_NBYTES - CCGCM_BLOCK_NBYTES; ok_or_fail(ccgcm_update(decrypt_ciphermode, decrypt_ctx, sizeof (buf), buf, buf) == 0, "ccgcm_update (end) decrypt counter wrap"); ok_or_fail(ccgcm_update(decrypt_ciphermode, decrypt_ctx, 1, buf, buf) == CCMODE_INVALID_INPUT, "ccgcm_update (overflow) decrypt counter wrap"); return 1; } static int gcm_test_gf_mult(void) { uint8_t keyA[16]; uint8_t stateA[16]; uint8_t outA[16]; uint8_t keyB[16]; uint8_t stateB[16]; uint8_t outB[16]; for (size_t i = 0; i < sizeof(keyA); i++) { keyA[i] = 0xDE; keyB[i] = 0xDE; stateA[i] = 0xED; stateB[i] = 0xED; } ccmode_gcm_gf_mult_table(keyA, stateA, outA); ccmode_gcm_gf_mult_compute(keyA, stateB, outB); ok_memcmp_or_fail(outA, outB, sizeof(outA), "ccmode_gcm_gf_mult_table and ccmode_gcm_gf_mult_compute computed different results"); return 1; } int test_gcm(const struct ccmode_gcm *encrypt_ciphermode, const struct ccmode_gcm *decrypt_ciphermode) { for (size_t i = 0; i < nvectors; i++) { gcm_testcase(encrypt_ciphermode, decrypt_ciphermode, i); } gcm_test_zerolen_iv(encrypt_ciphermode, decrypt_ciphermode); gcm_test_init_with_iv(encrypt_ciphermode, decrypt_ciphermode); gcm_test_counter_wrap(encrypt_ciphermode, decrypt_ciphermode); return gcm_test_gf_mult(); }