/* * cifra - embedded cryptography library * Written in 2014 by Joseph Birr-Pixton * * To the extent possible under law, the author(s) have dedicated all * copyright and related and neighboring rights to this software to the * public domain worldwide. This software is distributed without any * warranty. * * You should have received a copy of the CC0 Public Domain Dedication * along with this software. If not, see * . */ #ifndef TESTSHA_H #define TESTSHA_H #include "hmac.h" /* Common functions for testing hash functions. * You shouldn't use this file. */ static void vector(const cf_chash *hash, const void *vmsg, size_t nmsg, const char *expect, size_t nexpect) { uint8_t digest[CF_MAXHASH]; const uint8_t *msg = vmsg; size_t orig_nmsg = nmsg; cf_chash_ctx ctx; hash->init(&ctx); /* Input in carefully chosen chunk sizes to exercise blockwise code. */ if (nmsg) { hash->update(&ctx, msg, 1); nmsg--; msg++; } hash->update(&ctx, msg, nmsg); hash->digest(&ctx, digest); TEST_CHECK(nexpect == hash->hashsz); TEST_CHECK(memcmp(digest, expect, nexpect) == 0); /* Now try with other arrangements. */ msg = vmsg; nmsg = orig_nmsg; hash->init(&ctx); if (nmsg >= hash->blocksz) { hash->update(&ctx, msg, hash->blocksz - 1); nmsg -= hash->blocksz - 1; msg += hash->blocksz - 1; } hash->update(&ctx, msg, nmsg); hash->digest(&ctx, digest); TEST_CHECK(memcmp(digest, expect, nexpect) == 0); } /* These are shared between RFC2202 and RFC4231. */ static inline void hmac_test(const cf_chash *hash, const void *hi_there, const void *jefe, const void *aa_dd, const void *counter_key) { uint8_t sig[CF_MAXHASH]; uint8_t key[25], message[50]; /* Key: 0x0b * 20 * Message: "Hi There" */ memset(key, 0x0b, 20); memcpy(message, "Hi There", 8); cf_hmac(key, 20, message, 8, sig, hash); TEST_CHECK(memcmp(sig, hi_there, hash->hashsz) == 0); /* Key: "Jefe" * Message: "what do ya want for nothing?" */ memcpy(key, "Jefe", 4); memcpy(message, "what do ya want for nothing?", 28); cf_hmac(key, 4, message, 28, sig, hash); TEST_CHECK(memcmp(sig, jefe, hash->hashsz) == 0); /* Key: 0xaa * 20 * Message: 0xdd * 50 */ memset(key, 0xaa, 20); memset(message, 0xdd, 50); cf_hmac(key, 20, message, 50, sig, hash); TEST_CHECK(memcmp(sig, aa_dd, hash->hashsz) == 0); /* Key: 0x01..0x19 * Message: 0xcd * 50 */ for (uint8_t i = 1; i < 26; i++) key[i - 1] = i; memset(message, 0xcd, 50); cf_hmac(key, 25, message, 50, sig, hash); TEST_CHECK(memcmp(sig, counter_key, hash->hashsz) == 0); } /* These are specific to RFC4231. */ static inline void hmac_test_sha2(const cf_chash *hash, const char *long_key, const char *long_message) { uint8_t sig[CF_MAXHASH]; uint8_t key[131], message[152]; /* Key: 0xaa * 131 * Message: "Test Using Larger Than Block-Size Key - Hash Key First" */ memset(key, 0xaa, 131); memcpy(message, "Test Using Larger Than Block-Size Key - Hash Key First", 54); cf_hmac(key, 131, message, 54, sig, hash); TEST_CHECK(memcmp(sig, long_key, hash->hashsz) == 0); /* Key: 0xaa * 131 * Message: "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm." */ memset(key, 0xaa, 131); memcpy(message, "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.", 152); cf_hmac(key, 131, message, 152, sig, hash); TEST_CHECK(memcmp(sig, long_message, hash->hashsz) == 0); } /* This is as hmac_test_sha2, except the sizes are specific to * a 512-bit block. This is from RFC2202. */ static inline void hmac_test_sha1(const cf_chash *hash, const char *long_key, const char *long_message) { uint8_t sig[CF_MAXHASH]; uint8_t key[80], message[73]; /* Key: 0xaa * 80 * Message: "Test Using Larger Than Block-Size Key - Hash Key First" */ memset(key, 0xaa, 80); memcpy(message, "Test Using Larger Than Block-Size Key - Hash Key First", 54); cf_hmac(key, 80, message, 54, sig, hash); TEST_CHECK(memcmp(sig, long_key, hash->hashsz) == 0); /* Key: 0xaa * 80 * Message: "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data" */ memset(key, 0xaa, 80); memcpy(message, "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data", 73); cf_hmac(key, 80, message, 73, sig, hash); TEST_CHECK(memcmp(sig, long_message, hash->hashsz) == 0); } typedef void (*final_fn)(void *ctx, uint8_t *out); /* Check incremental interface works, and final function likewise. */ static void vector_abc_final(const cf_chash *hash, const void *vfinal_fn, const void *expect, size_t nexpect) { uint8_t digest[CF_MAXHASH]; final_fn final = vfinal_fn; cf_chash_ctx ctx; hash->init(&ctx); hash->update(&ctx, "a", 1); hash->digest(&ctx, digest); hash->update(&ctx, "b", 1); hash->digest(&ctx, digest); hash->update(&ctx, "c", 1); final(&ctx, digest); TEST_CHECK(hash->hashsz == nexpect); TEST_CHECK(memcmp(expect, digest, nexpect) == 0); } /* Check length-checking vectors work (generated by programs in ../extra_vecs) */ static inline void vector_length(const cf_chash *h, size_t max, const void *expect, size_t nexpect) { cf_chash_ctx outer, inner; uint8_t digest[CF_MAXHASH]; h->init(&outer); for (size_t n = 0; n < max; n++) { h->init(&inner); for (size_t i = 0; i < n; i++) { uint8_t byte = (uint8_t) n & 0xff; h->update(&inner, &byte, 1); } h->digest(&inner, digest); h->update(&outer, digest, h->hashsz); } h->digest(&outer, digest); TEST_CHECK(h->hashsz == nexpect); TEST_CHECK(memcmp(expect, digest, nexpect) == 0); } #endif