Commit d32033ad authored by Rusty Russell's avatar Rusty Russell

crypto/hmac_sha256: new module.

Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent 346058c0
../../../licenses/BSD-MIT
\ No newline at end of file
#include "config.h"
#include <stdio.h>
#include <string.h>
/**
* crypto/hmac_sha256 - RFC2104 HMAC using SHA256.
*
* This code implements RFC2104, which is a fairly standard HMAC.
*
* License: BSD-MIT
* Maintainer: Rusty Russell <rusty@rustcorp.com.au>
*
* Example:
* #include <ccan/crypto/hmac_sha256/hmac_sha256.h>
* #include <err.h>
* #include <stdio.h>
* #include <string.h>
*
* // Simple demonstration: idential strings will have the same hash, but
* // two different strings will not.
* int main(int argc, char *argv[])
* {
* struct hmac_sha256 hash1, hash2;
*
* if (argc != 3)
* errx(1, "Usage: %s <string1> <string2>", argv[0]);
*
* hmac_sha256(&hash1, "key", 3, argv[1], strlen(argv[1]));
* hmac_sha256(&hash2, "key", 3, argv[2], strlen(argv[2]));
* printf("Hash is %s\n", memcmp(&hash1, &hash2, sizeof(hash1))
* ? "different" : "same");
* return 0;
* }
*/
int main(int argc, char *argv[])
{
/* Expect exactly one argument */
if (argc != 2)
return 1;
if (strcmp(argv[1], "depends") == 0) {
printf("ccan/crypto/sha256\n");
return 0;
}
if (strcmp(argv[1], "testdepends") == 0) {
printf("ccan/str/hex\n");
return 0;
}
return 1;
}
/* MIT (BSD) license - see LICENSE file for details */
#include <ccan/crypto/hmac_sha256/hmac_sha256.h>
#include <string.h>
#define IPAD 0x3636363636363636ULL
#define OPAD 0x5C5C5C5C5C5C5C5CULL
#define BLOCK_U64S (64 / sizeof(uint64_t))
static inline void xor_block(uint64_t block[BLOCK_U64S], uint64_t pad)
{
size_t i;
for (i = 0; i < BLOCK_U64S; i++)
block[i] ^= pad;
}
#if 1
void hmac_sha256(struct hmac_sha256 *hmac,
const void *k, size_t ksize,
const void *d, size_t dsize)
{
struct sha256_ctx shactx;
uint64_t block[BLOCK_U64S];
struct sha256 hash, hashed_key;
/* (keys longer than B bytes are first hashed using H) */
if (ksize > sizeof(block)) {
sha256(&hashed_key, k, ksize);
k = &hashed_key;
ksize = sizeof(hashed_key);
}
/* From RFC2104:
*
* (1) append zeros to the end of K to create a B byte string
* (e.g., if K is of length 20 bytes and B=64, then K will be
* appended with 44 zero bytes 0x00)
*/
memcpy(block, k, ksize);
memset((char *)block + ksize, 0, sizeof(block) - ksize);
/*
* (2) XOR (bitwise exclusive-OR) the B byte string computed
* in step (1) with ipad
*/
xor_block(block, IPAD);
/*
* (3) append the stream of data 'text' to the B byte string resulting
* from step (2)
* (4) apply H to the stream generated in step (3)
*/
sha256_init(&shactx);
sha256_update(&shactx, block, sizeof(block));
sha256_update(&shactx, d, dsize);
sha256_done(&shactx, &hash);
/*
* (5) XOR (bitwise exclusive-OR) the B byte string computed in
* step (1) with opad
*/
xor_block(block, IPAD^OPAD);
/*
* (6) append the H result from step (4) to the B byte string
* resulting from step (5)
* (7) apply H to the stream generated in step (6) and output
* the result
*/
sha256_init(&shactx);
sha256_update(&shactx, block, sizeof(block));
sha256_update(&shactx, &hash, sizeof(hash));
sha256_done(&shactx, &hmac->sha);
}
#else
/* Direct mapping from MD5 example in RFC2104 */
void hmac_sha256(struct hmac_sha256 *hmac,
const void *key, size_t key_len,
const void *text, size_t text_len)
{
struct sha256_ctx context;
unsigned char k_ipad[65]; /* inner padding -
* key XORd with ipad
*/
unsigned char k_opad[65]; /* outer padding -
* key XORd with opad
*//* start out by storing key in pads */
unsigned char tk[32];
int i;
/* if key is longer than 64 bytes reset it to key=MD5(key) */
if (key_len > 64) {
struct sha256_ctx tctx;
sha256_init(&tctx);
sha256_update(&tctx, key, key_len);
sha256_done(&tctx, tk);
key = tk;
key_len = 32;
}
bzero( k_ipad, sizeof k_ipad);
bzero( k_opad, sizeof k_opad);
bcopy( key, k_ipad, key_len);
bcopy( key, k_opad, key_len);
/* XOR key with ipad and opad values */
for (i=0; i<64; i++) {
k_ipad[i] ^= 0x36;
k_opad[i] ^= 0x5c;
}
/*
* perform inner MD5
*/
sha256_init(&context); /* init context for 1st
* pass */
sha256_update(&context, k_ipad, 64); /* start with inner pad */
sha256_update(&context, text, text_len); /* then text of datagram */
sha256_done(&context, &hmac->sha); /* finish up 1st pass */
/*
* perform outer MD5
*/
sha256_init(&context); /* init context for 2nd
* pass */
sha256_update(&context, k_opad, 64); /* start with outer pad */
sha256_update(&context, &hmac->sha, 32); /* then results of 1st
* hash */
sha256_done(&context, &hmac->sha); /* finish up 2nd pass */
}
#endif
#ifndef CCAN_CRYPTO_HMAC_SHA256_H
#define CCAN_CRYPTO_HMAC_SHA256_H
/* BSD-MIT - see LICENSE file for details */
#include "config.h"
#include <stdint.h>
#include <stdlib.h>
#include <ccan/crypto/sha256/sha256.h>
/* Uncomment this to use openssl's HMAC routines (and link with -lcrypto) */
/*#define CCAN_CRYPTO_HMAC_USE_OPENSSL 1*/
#ifdef CCAN_CRYPTO_HMAC_USE_OPENSSL
#include <openssl/hmac.h>
#endif
/**
* struct hmac_sha256 - structure representing a completed HMAC.
*/
struct hmac_sha256 {
struct sha256 sha;
};
/**
* hmac_sha256 - return hmac of an object with a key.
* @hmac: the hmac to fill in
* @k: pointer to the key,
* @ksize: the number of bytes pointed to by @k
* @d: pointer to memory,
* @dsize: the number of bytes pointed to by @d
*/
void hmac_sha256(struct hmac_sha256 *hmac,
const void *k, size_t ksize,
const void *d, size_t dsize);
#endif /* CCAN_CRYPTO_HMAC_SHA256_H */
/* From RFC4231 "Identifiers and Test Vectors for HMAC-SHA-224, HMAC-SHA-256,
* HMAC-SHA-384, and HMAC-SHA-512"
*
* https://tools.ietf.org/html/rfc4231
*/
#include <ccan/crypto/hmac_sha256/hmac_sha256.h>
#include <ccan/tap/tap.h>
#include <ccan/str/hex/hex.h>
#include <string.h>
#include <assert.h>
struct test {
const char *key, *data, *hmac;
};
static struct test tests[] = { {
/* Test Case 1 */
"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", /* (20 bytes) */
"4869205468657265", /* ("Hi There") */
"b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7"
},
/* Test Case 2:
Test with a key shorter than the length of the HMAC output. */
{
"4a656665", /* ("Jefe") */
/* ("what do ya want for nothing?") */
"7768617420646f2079612077616e7420666f72206e6f7468696e673f",
"5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843"
},
{
/* Test Case 3
Test with a combined length of key and data that is larger than 64
bytes (= block-size of SHA-224 and SHA-256).
*/
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", /* (20 bytes) */
"dddddddddddddddddddddddddddddddd"
"dddddddddddddddddddddddddddddddd"
"dddddddddddddddddddddddddddddddd"
"dddd", /* (50 bytes) */
"773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe"
},
{
/* Test Case 4
Test with a combined length of key and data that is larger than 64
bytes (= block-size of SHA-224 and SHA-256).
*/
"0102030405060708090a0b0c0d0e0f10111213141516171819", /* (25 bytes) */
"cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
"cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
"cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
"cdcd", /* (50 bytes) */
"82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b"
},
#if 0
{
/* Test Case 5
Test with a truncation of output to 128 bits.
*/
"0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", /* (20 bytes) */
"546573742057697468205472756e636174696f6e", /* ("Test With Truncation") */
"a3b6167473100ee06e0c796c2955552b"
},
#endif
{
/* Test Case 6
Test with a key larger than 128 bytes (= block-size of SHA-384 and
SHA-512).
*/
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaa", /* (131 bytes) */
"54657374205573696e67204c61726765" /* ("Test Using Large") */
"72205468616e20426c6f636b2d53697a" /* ("r Than Block-Siz") */
"65204b6579202d2048617368204b6579" /* ("e Key - Hash Key") */
"204669727374", /* (" First") */
"60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54"
},
{
/* Test Case 7
Test with a key and data that is larger than 128 bytes (= block-size
of SHA-384 and SHA-512). */
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaa", /* (131 bytes) */
"54686973206973206120746573742075" /* ("This is a test u") */
"73696e672061206c6172676572207468" /* ("sing a larger th") */
"616e20626c6f636b2d73697a65206b65" /* ("an block-size ke") */
"7920616e642061206c61726765722074" /* ("y and a larger t") */
"68616e20626c6f636b2d73697a652064" /* ("han block-size d") */
"6174612e20546865206b6579206e6565" /* ("ata. The key nee") */
"647320746f2062652068617368656420" /* ("ds to be hashed ") */
"6265666f7265206265696e6720757365" /* ("before being use") */
"642062792074686520484d414320616c" /* ("d by the HMAC al") */
"676f726974686d2e", /* ("gorithm.") */
"9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2"
}
};
static void *fromhex(const char *str, size_t *len)
{
void *p;
*len = hex_data_size(strlen(str));
p = malloc(*len);
if (!hex_decode(str, strlen(str), p, *len))
abort();
return p;
}
int main(void)
{
size_t i;
struct hmac_sha256 hmac;
plan_tests(sizeof(tests) / sizeof(tests[0]));
for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
size_t ksize, dsize, hmacsize;
void *k, *d, *expect;
k = fromhex(tests[i].key, &ksize);
d = fromhex(tests[i].data, &dsize);
expect = fromhex(tests[i].hmac, &hmacsize);
assert(hmacsize == sizeof(hmac));
hmac_sha256(&hmac, k, ksize, d, dsize);
ok1(memcmp(&hmac, expect, hmacsize) == 0);
free(k);
free(d);
free(expect);
}
return exit_status();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment