/* Copyright (c) (2012,2014,2015,2016,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 "testmore.h" #include "testbyteBuffer.h" #include "testccnBuffer.h" #include "crypto_test_digest.h" #include "cc_memory.h" static int verbose = 0; #if (CCDIGEST == 0) entryPoint(ccdigest,"ccdigest test") #else #include #include #include #include #include #include #include #include #include /* Currently, ccdigest and friends won't work when length == 0 and the * data pointer is NULL. */ #define DIGEST_DATA_POINTER_NULL_TOLERANT 0 typedef struct test_vector_t { uint8_t *input; size_t len; uint8_t *md2_answer; uint8_t *md4_answer; uint8_t *md5_answer; uint8_t *sha1_answer; uint8_t *sha224_answer; uint8_t *sha256_answer; uint8_t *sha384_answer; uint8_t *sha512_answer; uint8_t *rmd160_answer; uint8_t *sha512_256_answer; } test_vector; static int test_answer(const struct ccdigest_info *di, test_vector *vector, void*answer) { uint8_t *correct_answer = NULL; if(ccdigest_oid_equal(di, CC_DIGEST_OID_MD2)) correct_answer = vector->md2_answer; else if(ccdigest_oid_equal(di, CC_DIGEST_OID_MD4)) correct_answer = vector->md4_answer; else if(ccdigest_oid_equal(di, CC_DIGEST_OID_MD5)) correct_answer = vector->md5_answer; else if(ccdigest_oid_equal(di, CC_DIGEST_OID_SHA1)) correct_answer = vector->sha1_answer; else if(ccdigest_oid_equal(di, CC_DIGEST_OID_SHA224)) correct_answer = vector->sha224_answer; else if(ccdigest_oid_equal(di, CC_DIGEST_OID_SHA256)) correct_answer = vector->sha256_answer; else if(ccdigest_oid_equal(di, CC_DIGEST_OID_SHA384)) correct_answer = vector->sha384_answer; else if(ccdigest_oid_equal(di, CC_DIGEST_OID_SHA512)) correct_answer = vector->sha512_answer; else if(ccdigest_oid_equal(di, CC_DIGEST_OID_RMD160)) correct_answer = vector->rmd160_answer; else if(ccdigest_oid_equal(di, CC_DIGEST_OID_SHA512_256)) correct_answer = vector->sha512_256_answer; if(correct_answer == NULL) { return 1; } byteBuffer answer_bb = bytesToBytes(answer, di->output_size); byteBuffer correct_answer_bb = hexStringToBytes((char *) correct_answer); ok(bytesAreEqual(correct_answer_bb, answer_bb), "compare memory of answer"); if(bytesAreEqual(correct_answer_bb, answer_bb) == 0) { printByteBuffer(correct_answer_bb, "Correct Answer"); printByteBuffer(answer_bb, "Provided Answer"); } free(correct_answer_bb); free(answer_bb); return 1; } static int guard_ok(uint8_t *p, int chr, size_t len) { for(size_t i=0; ilen; size_t chunk = vector->len/2; uint8_t *p = vector->input; uint8_t ctxfrontguard[4096]; ccdigest_di_decl(di, ctx); uint8_t ctxrearguard[4096]; memset(ctxfrontguard, 0xee, 4096); memset(ctxrearguard, 0xee, 4096); // break it up into pieces. ccdigest_init(di, ctx); ok(guard_ok(ctxfrontguard, 0xee, 4096), "context is safe"); ok(guard_ok(ctxrearguard, 0xee, 4096), "context is safe"); do { ccdigest_update(di, ctx, chunk, p); total -= chunk; p += chunk; chunk /= 2; if(chunk == 0) chunk = total; } while(total); ok(guard_ok(ctxfrontguard, 0xee, 4096), "context is safe"); ok(guard_ok(ctxrearguard, 0xee, 4096), "context is safe"); ccdigest_final(di, ctx, answer); ok(guard_ok(ctxfrontguard, 0xee, 4096), "context is safe"); ok(guard_ok(ctxrearguard, 0xee, 4096), "context is safe"); ok(test_answer(di, vector, answer), "check answer"); return 1; } static int test_oneshot(const struct ccdigest_info *di, test_vector *vector) { uint8_t answer[128]; ccdigest(di, vector->len, vector->input, answer); ok(test_answer(di, vector, answer), "check answer"); return 1; } static int test_digest_many_blocks(const struct ccdigest_info *di) { static const size_t buffer_size = 16383; static uint8_t buffer[buffer_size]; static test_vector vector[] = { { buffer, buffer_size, (uint8_t *) "460825c272c70b141a24364117e1242e", //MD2 (uint8_t *) "45eb5470a0e700ef2f47e408652792dc", //MD4 (uint8_t *) "ef17d771a405e1effd7fb6a1f9950018", //MD5 (uint8_t *) "217edfa45f521c1232e4cc2cacac29bf8a9d1e66", //SHA1 (uint8_t *) "bfcef78f215b9682767c4ba7404379ef87012c4b7346631ccb965c2d", //SHA224 (uint8_t *) "fab82f1352405c22ca2953ff80a508e5567c51e1a9aeb57cf9a56447e40ba066", //SHA256 (uint8_t *) "220dfd6babc12b08f6f456133d52aa2975dfb50689de810ab0fa8cd9a7650218dc6afaf24f77f6b969f9ea7141f9aeb7", //SHA384 (uint8_t *) "a238834f3693080d7cce3c44c7600e8a09311ba8e6059002bc67d4158430148abd2d8255afdf3b2f944fa5e1025dd6c4646f5dd9f6858ee1222a67430a24d491", //SHA512 (uint8_t *) "d6cca8771842686d759d5778702c24bcc4d355e0", //RMD160 (uint8_t *) "05a1178de8564d8c6a814bf1c3a4df3d0dde4aa4d491e77aae3958d2f93b6bd4", //SHA512/256 }, }; int vector_size = sizeof (vector) / sizeof (test_vector); for(size_t n=0; noutput_size]; uint8_t chunk[128] = { 0 }; ccdigest_di_decl(di, ctx); ccdigest_init(di, ctx); // Corrupt the context. ccdigest_num(di, ctx) = 0xffffffff; ccdigest_update(di, ctx, sizeof(chunk), chunk); // Corrupt the context. ccdigest_num(di, ctx) = 0xffffffff; ccdigest_final(di, ctx, digest); // Sanity check the resulting digest. static test_vector vector = { NULL, 0, NULL, NULL, (uint8_t *) "f09f35a5637839458e462e6350ecbce4", //MD5 (uint8_t *) "0ae4f711ef5d6e9d26c611fd2c8c8ac45ecbf9e7", //SHA1 (uint8_t *) "2fbd823ebcd9909d265827e4bce793a4fc572e3f39c7c3dd67749f3e", //SHA224 (uint8_t *) "38723a2e5e8a17aa7950dc008209944e898f69a7bd10a23c839d341e935fd5ca", //SHA256 (uint8_t *) "f809b88323411f24a6f152e5e9d9d1b5466b77e0f3c7550f8b242c31b6e7b99bcb45bdecb6124bc23283db3b9fc4f5b3", //SHA384 (uint8_t *) "ab942f526272e456ed68a979f50202905ca903a141ed98443567b11ef0bf25a552d639051a01be58558122c58e3de07d749ee59ded36acf0c55cd91924d6ba11", //SHA512 NULL, (uint8_t *) "fe3d375e149b888e08e2521007764b422d2cd6f7b0606881b7fe1b1370d5fa88", //SHA512/256 }; ok(test_answer(di, &vector, digest), "Invalid digest"); return 1; } // CHUNK_SIZE will be either (1 << 31) or (1 << 32), depending on size of size_t. // // * In the former case, (1 << 31) * 8 == (1 << 34), which would let // ccdigest_nbits() overflow if we don't perform 64-bit multiplication. // // * In the latter case, we ensure that the custom division routine works on // 64-bit systems too. #define CHUNK_SIZE (sizeof(size_t) << 29) #define NUM_CHUNKS 8 // Check that nblocks was computed correctly. static void custom1_compress(CC_UNUSED ccdigest_state_t state, size_t nblocks, CC_UNUSED const void *in) { is(nblocks, CHUNK_SIZE / CCSHA1_BLOCK_SIZE, "nblocks is correct"); } // Check that nblocks was computed correctly. static void custom2_compress(CC_UNUSED ccdigest_state_t state, size_t nblocks, CC_UNUSED const void *in) { is(nblocks, CHUNK_SIZE / CCSHA512_BLOCK_SIZE, "nblocks is correct"); } // Check that .nbits contains the expected value. static void custom_final(CC_UNUSED const struct ccdigest_info *di, ccdigest_ctx_t ctx, CC_UNUSED unsigned char *digest) { is(ccdigest_nbits(di, ctx), (uint64_t)CHUNK_SIZE * NUM_CHUNKS * 8, "nbits is correct"); } // An empty state. const uint8_t custom_initial_state[CCSHA512_STATE_SIZE] = { 0 }; // A custom digest with a 512-bit block size. const struct ccdigest_info custom1_di = { .output_size = CCSHA1_OUTPUT_SIZE, .state_size = CCSHA1_STATE_SIZE, .block_size = CCSHA1_BLOCK_SIZE, .oid_size = ccoid_sha1_len, .oid = CC_DIGEST_OID_SHA1, .initial_state = custom_initial_state, .compress = custom1_compress, .final = custom_final, }; // A custom digest with a 1024-bit block size. const struct ccdigest_info custom2_di = { .output_size = CCSHA512_OUTPUT_SIZE, .state_size = CCSHA512_STATE_SIZE, .block_size = CCSHA512_BLOCK_SIZE, .oid_size = ccoid_sha512_len, .oid = CC_DIGEST_OID_SHA512, .initial_state = custom_initial_state, .compress = custom2_compress, .final = custom_final, }; static int test_huge_input(const struct ccdigest_info *di) { ccdigest_di_decl(di, dc); ccdigest_init(di, dc); for (uint64_t l = 0; l < NUM_CHUNKS; l++) { ccdigest_update(di, dc, CHUNK_SIZE, NULL); } ccdigest_final(di, dc, NULL); return 1; } static int test_finalize(const struct ccdigest_info *di) { uint8_t digest1[di->output_size]; uint8_t digest2[di->output_size]; uint8_t chunk1[128] = { 0 }; uint8_t chunk2[256] = { 0 }; ccdigest_di_decl(di, ctx); ccdigest_init(di, ctx); ccdigest_update(di, ctx, sizeof(chunk1), chunk1); ccdigest_final(di, ctx, digest1); ccdigest_final(di, ctx, digest2); ok_memcmp(digest1, digest2, sizeof(digest1), "digests match"); ccdigest_update(di, ctx, sizeof(chunk1), chunk1); ccdigest_final(di, ctx, digest1); ccdigest(di, sizeof(chunk2), chunk2, digest2); ok_memcmp(digest1, digest2, sizeof(digest1), "digests match"); return 1; } static int test_digest(const struct ccdigest_info *di) { ok(test_digest_of_zero(di), "test_digest_of_zero"); ok(test_digest_lt_blocksize(di), "test_digest_lt_blocksize"); ok(test_digest_eq_blocksize(di), "test_digest_eq_blocksize"); ok(test_digest_many_blocks(di), "test_digest_many_blocks"); ok(test_corrupt_context(di), "test_corrupt_context"); ok(test_finalize(di), "test_finalize"); return 1; } int ccdigest_tests(TM_UNUSED int argc, TM_UNUSED char *const *argv) { if(verbose) diag("Starting digest tests"); int ntests = 956; ntests += 20; // test_huge_input ntests += 45; // test_finalize plan_tests(ntests); ok(test_huge_input(&custom1_di), "test_huge_input #1"); ok(test_huge_input(&custom2_di), "test_huge_input #2"); // Pure C version ok(test_digest(&ccmd2_ltc_di), "ccmd2_di"); ok(test_digest(&ccmd4_ltc_di), "ccmd4_ltc_di"); ok(test_digest(&ccmd5_ltc_di), "ccmd5_ltc_di"); ok(test_digest(&ccsha1_ltc_di), "ccsha1_ltc_di"); ok(test_digest(&ccsha1_eay_di), "ccsha1_eay_di"); ok(test_digest(&ccsha224_ltc_di), "ccsha224_ltc_di"); ok(test_digest(&ccsha256_ltc_di), "ccsha256_ltc_di"); ok(test_digest(&ccsha384_ltc_di), "ccsha384_ltc_di"); ok(test_digest(&ccsha512_ltc_di), "ccsha512_ltc_di"); ok(test_digest(&ccrmd160_ltc_di), "ccrmd160_ltc_di"); ok(test_digest(&ccsha512_256_ltc_di), "ccsha512_256_ltc_di"); // Default (optimized) ok(test_digest(ccsha1_di()), "Default ccsha1_di"); ok(test_digest(ccsha224_di()), "Default ccsha224_di"); ok(test_digest(ccsha256_di()), "Default ccsha256_di"); ok(test_digest(ccsha384_di()), "Default ccsha384_di"); ok(test_digest(ccsha512_di()), "Default ccsha512_di"); ok(test_digest(ccsha512_256_di()), "Default ccsha512_256_di"); //this is a standalone KAT test for sha256. It is used when clients have only sha256 available. ok(sha256_kat()==0, "sha256, standalone KAT"); return 0; } #endif