Skip to content

Commit a3c6146

Browse files
author
Chandra Pratap
committed
fuzz-tests: Add differential test for HMAC-SHA256
Changelog-Added: Add a differential fuzz test for HMAC-SHA256, similar to those for SHA256 and RIPEMD160, to verify CCAN’s implementation against OpenSSL’s.
1 parent 63e15c1 commit a3c6146

File tree

2 files changed

+88
-0
lines changed

2 files changed

+88
-0
lines changed

tests/fuzz/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ LIBFUZZ_OBJS := $(LIBFUZZ_SRC:.c=.o)
55
tests/fuzz/fuzz-connectd-handshake-act*.o: tests/fuzz/connectd_handshake.h
66
tests/fuzz/fuzz-ripemd160: LDLIBS += -lcrypto
77
tests/fuzz/fuzz-sha256: LDLIBS += -lcrypto
8+
tests/fuzz/fuzz-hmac-sha256: LDLIBS += -lcrypto
89
tests/fuzz/fuzz-wire-*.o: tests/fuzz/wire.h
910
tests/fuzz/fuzz-bolt12-*.o: tests/fuzz/bolt12.h
1011

tests/fuzz/fuzz-hmac-sha256.c

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/* This is a differential fuzz test comparing CCAN's HMAC‑SHA256 implementation
2+
* against OpenSSL's HMAC.
3+
*/
4+
#include "config.h"
5+
#include <assert.h>
6+
#include <ccan/crypto/hmac_sha256/hmac_sha256.h>
7+
#include <ccan/mem/mem.h>
8+
#include <openssl/hmac.h>
9+
#include <openssl/evp.h>
10+
#include <openssl/sha.h>
11+
#include <tests/fuzz/libfuzz.h>
12+
13+
/* Fixed key for testing purposes */
14+
static const unsigned char hmac_key[] = "fuzz";
15+
static const size_t hmac_key_len = sizeof(hmac_key) - 1;
16+
17+
static EVP_MAC *hmac_sha256_algo;
18+
19+
void init(int *argc, char ***argv)
20+
{
21+
hmac_sha256_algo = EVP_MAC_fetch(NULL, "HMAC", NULL);
22+
assert(hmac_sha256_algo);
23+
}
24+
25+
/* Test that splitting the data and updating via multiple calls yields the same
26+
* result as processing the data in a single pass.
27+
*/
28+
static void test_split_update(int num_splits, const struct hmac_sha256 *expected,
29+
const u8 *data, size_t size)
30+
{
31+
const size_t split_size = size / (num_splits + 1);
32+
struct hmac_sha256_ctx ctx;
33+
struct hmac_sha256 actual;
34+
35+
hmac_sha256_init(&ctx, hmac_key, hmac_key_len);
36+
for (int i = 0; i < num_splits; ++i) {
37+
hmac_sha256_update(&ctx, data, split_size);
38+
data += split_size;
39+
size -= split_size;
40+
}
41+
hmac_sha256_update(&ctx, data, size); /* Process remaining data. */
42+
hmac_sha256_done(&ctx, &actual);
43+
assert(memeq(expected, sizeof(*expected), &actual, sizeof(actual)));
44+
}
45+
46+
/* Test that the HMAC calculated by CCAN matches OpenSSL's HMAC. */
47+
static void test_vs_openssl(const struct hmac_sha256 *expected, const u8 *data, size_t size)
48+
{
49+
u8 openssl_hash[SHA256_DIGEST_LENGTH];
50+
size_t hash_size;
51+
EVP_MAC_CTX *ctx;
52+
OSSL_PARAM params[] = {
53+
OSSL_PARAM_construct_utf8_string("digest", "SHA256", 0),
54+
OSSL_PARAM_END
55+
};
56+
57+
ctx = EVP_MAC_CTX_new(hmac_sha256_algo);
58+
assert(ctx);
59+
60+
assert(EVP_MAC_init(ctx, hmac_key, hmac_key_len, params));
61+
assert(EVP_MAC_update(ctx, data, size));
62+
assert(EVP_MAC_final(ctx, openssl_hash, &hash_size, sizeof(openssl_hash)));
63+
EVP_MAC_CTX_free(ctx);
64+
65+
assert(hash_size == SHA256_DIGEST_LENGTH);
66+
assert(memeq(expected, sizeof(*expected), openssl_hash, sizeof(openssl_hash)));
67+
}
68+
69+
void run(const u8 *data, size_t size)
70+
{
71+
struct hmac_sha256 expected;
72+
u8 num_splits;
73+
74+
if (size < 1)
75+
return;
76+
77+
num_splits = *data;
78+
++data;
79+
--size;
80+
81+
/* Compute expected HMAC using the one-shot function. */
82+
hmac_sha256(&expected, hmac_key, hmac_key_len, data, size);
83+
84+
test_split_update(num_splits, &expected, data, size);
85+
test_vs_openssl(&expected, data, size);
86+
}
87+

0 commit comments

Comments
 (0)