From 17266cc44a0a386ec006970317e2d5941141867b Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 31 Oct 2007 04:56:59 +0000 Subject: [PATCH] r16287@catbus: nickm | 2007-10-31 00:53:53 -0400 HMAC-SHA-1 implementation, with unit tests based on vectors from RVFC2202. Steven's stuff will need this. svn:r12289 --- src/common/crypto.c | 50 ++++++++++++++++++++++++++++++++++++++++++++- src/common/crypto.h | 3 +++ src/or/test.c | 37 +++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 1 deletion(-) diff --git a/src/common/crypto.c b/src/common/crypto.c index 6c1dae9a73..8762840a54 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -1261,7 +1261,7 @@ void crypto_digest_get_digest(crypto_digest_env_t *digest, char *out, size_t out_len) { - static unsigned char r[DIGEST_LEN]; + static unsigned char r[DIGEST_LEN]; /*XXXXX020 why static? */ SHA_CTX tmpctx; tor_assert(digest); tor_assert(out); @@ -1297,6 +1297,54 @@ crypto_digest_assign(crypto_digest_env_t *into, memcpy(into,from,sizeof(crypto_digest_env_t)); } +/**DOCDOC */ +#define DIGEST_BLOCKSIZE 64 + +/** Compute the HMAC-SHA-1 of the msg_len bytes in msg, using + * the key of length key_len. Store the DIGEST_LEN-byte result + * in hmac_out. + */ +void +crypto_hmac_sha1(char *hmac_out, + const char *key, size_t key_len, + const char *msg, size_t msg_len) +{ + SHA_CTX sha; + uint8_t K[DIGEST_BLOCKSIZE], D[DIGEST_LEN], K_SHORT[DIGEST_LEN]; + const uint8_t *real_key; + unsigned int i; + + if (key_len > DIGEST_BLOCKSIZE) { + SHA1((const unsigned char*)key, key_len, K_SHORT); + key_len = DIGEST_LEN; + real_key = K_SHORT; + } else { + real_key = (const uint8_t*)key; + } + + memset(K, 0, sizeof(K)); + memcpy(K, real_key, key_len); + for (i=0; i < sizeof(K); ++i) + K[i] ^= 0x36; + SHA1_Init(&sha); + SHA1_Update(&sha, K, sizeof(K)); + SHA1_Update(&sha, msg, msg_len); + SHA1_Final(D, &sha); + + /* + memset(K, 0, sizeof(K)); + memcpy(K, real_key, key_len); + for (i=0; i < sizeof(K); ++i) + K[i] ^= 0x5c; + */ + for (i=0; i < sizeof(K); ++i) + K[i] ^= (0x36 ^ 0x5c); + SHA1_Init(&sha); + SHA1_Update(&sha, K, sizeof(K)); + SHA1_Update(&sha, D, sizeof(D)); + SHA1_Final((unsigned char*)hmac_out, &sha); +} + /* DH */ /** Shared P parameter for our DH key exchanged. */ diff --git a/src/common/crypto.h b/src/common/crypto.h index 09cbbe704a..610ea460d7 100644 --- a/src/common/crypto.h +++ b/src/common/crypto.h @@ -146,6 +146,9 @@ void crypto_digest_get_digest(crypto_digest_env_t *digest, crypto_digest_env_t *crypto_digest_dup(const crypto_digest_env_t *digest); void crypto_digest_assign(crypto_digest_env_t *into, const crypto_digest_env_t *from); +void crypto_hmac_sha1(char *hmac_out, + const char *key, size_t key_len, + const char *msg, size_t msg_len); /* Key negotiation */ crypto_dh_env_t *crypto_dh_new(void); diff --git a/src/or/test.c b/src/or/test.c index a8dcb053df..6c71a07e32 100644 --- a/src/or/test.c +++ b/src/or/test.c @@ -445,6 +445,42 @@ test_crypto(void) "\xA9\x99\x3E\x36\x47\x06\x81\x6A\xBA\x3E\x25\x71\x78" "\x50\xC2\x6C\x9C\xD0\xD8\x9D", 20); + /* Test HMAC-SHA-1 with test cases from RFC2202. */ + { + char key[80]; + char digest[20]; + char data[50]; + + /* Case 1. */ + memset(key, 0x0b, 20); + crypto_hmac_sha1(digest, key, 20, "Hi There", 8); + test_streq(hex_str(digest, 20), + "B617318655057264E28BC0B6FB378C8EF146BE00"); + + /* Case 2. */ + crypto_hmac_sha1(digest, "Jefe", 4, "what do ya want for nothing?", 28); + test_streq(hex_str(digest, 20), + "EFFCDF6AE5EB2FA2D27416D5F184DF9C259A7C79"); + + /* Case 4. */ + base16_decode(key, 25, + "0102030405060708090a0b0c0d0e0f10111213141516171819", 50); + memset(data, 0xcd, 50); + crypto_hmac_sha1(digest, key, 25, data, 50); + test_streq(hex_str(digest, 20), + "4C9007F4026250C6BC8414F9BF50C86C2D7235DA"); + + /* Case . */ + memset(key, 0xaa, 80); + crypto_hmac_sha1(digest, key, 80, + "Test Using Larger Than Block-Size Key - Hash Key First", + 54); + test_streq(hex_str(digest, 20), + "AA4AE5E15272D00E95705637CE8A3B55ED402112"); + + } + + /* Public-key ciphers */ pk1 = pk_generate(0); pk2 = crypto_new_pk_env(); @@ -2175,6 +2211,7 @@ test_dir_format(void) "platform Tor "VERSION" on ", sizeof(buf2)); strlcat(buf2, get_uname(), sizeof(buf2)); strlcat(buf2, "\n" + "opt protocols Link 1 Circuit 1\n" "published 1970-01-01 00:00:00\n" "opt fingerprint ", sizeof(buf2)); test_assert(!crypto_pk_get_fingerprint(pk2, fingerprint, 1));