/* 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 #include "testmore.h" #include "testbyteBuffer.h" #include #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; }