diff --git a/configure.ac b/configure.ac index 6d8dfee..fbcc063 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ([2.69]) -AC_INIT([cryb.to], [0.20221002], [des@des.no], [cryb-to], [http://cryb.to/]) +AC_INIT([cryb.to], [0.20221003], [des@des.no], [cryb-to], [http://cryb.to/]) AC_CONFIG_SRCDIR([include/cryb/core.h]) AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE([foreign no-dist-gzip dist-xz]) diff --git a/include/cryb/Makefile.am b/include/cryb/Makefile.am index 368aee4..21bc70b 100644 --- a/include/cryb/Makefile.am +++ b/include/cryb/Makefile.am @@ -78,6 +78,7 @@ endif CRYB_HASH if CRYB_MAC cryb_HEADERS += \ hmac.h \ + hmac_md5.h \ hmac_sha1.h \ hmac_sha224.h \ hmac_sha256.h \ diff --git a/include/cryb/hmac.h b/include/cryb/hmac.h index b03bb01..c0f9d46 100644 --- a/include/cryb/hmac.h +++ b/include/cryb/hmac.h @@ -34,6 +34,7 @@ #include #endif +#include #include #include #include diff --git a/include/cryb/hmac_md5.h b/include/cryb/hmac_md5.h new file mode 100644 index 0000000..f5d84dc --- /dev/null +++ b/include/cryb/hmac_md5.h @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 2012-2014 The University of Oslo + * Copyright (c) 2022 Dag-Erling Smørgrav + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef CRYB_HMAC_MD5_H_INCLUDED +#define CRYB_HMAC_MD5_H_INCLUDED + +#ifndef CRYB_TO +#include +#endif + +#include + +CRYB_BEGIN + +#define HMAC_MD5_MAC_LEN 16 + +#define hmac_md5_ctx cryb_hmac_md5_ctx +#define hmac_md5_init cryb_hmac_md5_init +#define hmac_md5_update cryb_hmac_md5_update +#define hmac_md5_final cryb_hmac_md5_final +#define hmac_md5_complete cryb_hmac_md5_complete + +typedef struct { + md5_ctx ictx; + md5_ctx octx; +} hmac_md5_ctx; + +void hmac_md5_init(hmac_md5_ctx *, const void *, size_t); +void hmac_md5_update(hmac_md5_ctx *, const void *, size_t); +void hmac_md5_final(hmac_md5_ctx *, uint8_t *); +void hmac_md5_complete(const void *, size_t, const void *, size_t, uint8_t *); + +CRYB_END + +#endif diff --git a/include/cryb/to.h b/include/cryb/to.h index d409175..7551563 100644 --- a/include/cryb/to.h +++ b/include/cryb/to.h @@ -30,7 +30,7 @@ #ifndef CRYB_TO_H_INCLUDED #define CRYB_TO_H_INCLUDED -#define CRYB_TO 20221002 +#define CRYB_TO 20221003 #include diff --git a/lib/mac/Makefile.am b/lib/mac/Makefile.am index 46e6700..1d5b011 100644 --- a/lib/mac/Makefile.am +++ b/lib/mac/Makefile.am @@ -3,6 +3,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include lib_LTLIBRARIES = libcryb-mac.la libcryb_mac_la_SOURCES = \ + cryb_hmac_md5.c \ cryb_hmac_sha1.c \ cryb_hmac_sha224.c \ cryb_hmac_sha256.c \ diff --git a/lib/mac/cryb_hmac_md5.c b/lib/mac/cryb_hmac_md5.c new file mode 100644 index 0000000..959d1d6 --- /dev/null +++ b/lib/mac/cryb_hmac_md5.c @@ -0,0 +1,102 @@ +/*- + * Copyright (c) 2012 The University of Oslo + * Copyright (c) 2012-2022 Dag-Erling Smørgrav + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cryb/impl.h" + +#if HAVE_SYS_ENDIAN_H +#include +#endif + +#if HAVE_ENDIAN_H +#include +#endif + +#include +#include + +#include + +void +hmac_md5_init(hmac_md5_ctx *ctx, const void *key, size_t keylen) +{ + uint8_t keybuf[MD5_BLOCK_LEN], pad[MD5_BLOCK_LEN]; + + /* prepare key */ + memset(keybuf, 0, sizeof keybuf); + if (keylen > sizeof keybuf) + md5_complete(key, keylen, keybuf); + else + memcpy(keybuf, key, keylen); + + /* input pad */ + for (unsigned int i = 0; i < sizeof pad; ++i) + pad[i] = 0x36 ^ keybuf[i]; + md5_init(&ctx->ictx); + md5_update(&ctx->ictx, pad, sizeof pad); + + /* output pad */ + for (unsigned int i = 0; i < sizeof pad; ++i) + pad[i] = 0x5c ^ keybuf[i]; + md5_init(&ctx->octx); + md5_update(&ctx->octx, pad, sizeof pad); + + /* hide the evidence */ + memset(keybuf, 0, sizeof keybuf); + memset(pad, 0, sizeof pad); +} + +void +hmac_md5_update(hmac_md5_ctx *ctx, const void *buf, size_t len) +{ + + md5_update(&ctx->ictx, buf, len); +} + +void +hmac_md5_final(hmac_md5_ctx *ctx, uint8_t *mac) +{ + uint8_t digest[MD5_DIGEST_LEN]; + + md5_final(&ctx->ictx, digest); + md5_update(&ctx->octx, digest, sizeof digest); + md5_final(&ctx->octx, mac); + memset(ctx, 0, sizeof *ctx); +} + +void +hmac_md5_complete(const void *key, size_t keylen, + const void *buf, size_t len, uint8_t *mac) +{ + hmac_md5_ctx ctx; + + hmac_md5_init(&ctx, key, keylen); + hmac_md5_update(&ctx, buf, len); + hmac_md5_final(&ctx, mac); +} diff --git a/t/.gitignore b/t/.gitignore index 7cdeb9d..913dd01 100644 --- a/t/.gitignore +++ b/t/.gitignore @@ -14,6 +14,8 @@ /t_fletcher /t_fnv /t_hash +/t_hmac_md5 +/t_hmac_md5_openssl /t_hmac_sha1 /t_hmac_sha1_openssl /t_hmac_sha224 diff --git a/t/Makefile.am b/t/Makefile.am index fe8d80d..3d21e0c 100644 --- a/t/Makefile.am +++ b/t/Makefile.am @@ -192,14 +192,18 @@ endif CRYB_HASH if CRYB_MAC TESTS += t_mac t_mac_LDADD = $(libt) $(libmac) -TESTS += t_hmac_sha1 t_hmac_sha224 t_hmac_sha256 t_hmac_sha384 t_hmac_sha512 +TESTS += t_hmac_md5 t_hmac_sha1 t_hmac_sha224 t_hmac_sha256 t_hmac_sha384 t_hmac_sha512 +t_hmac_md5_LDADD = $(libt) $(libmac) t_hmac_sha1_LDADD = $(libt) $(libmac) t_hmac_sha224_LDADD = $(libt) $(libmac) t_hmac_sha256_LDADD = $(libt) $(libmac) t_hmac_sha384_LDADD = $(libt) $(libmac) t_hmac_sha512_LDADD = $(libt) $(libmac) if OPENSSL_TESTS -TESTS += t_hmac_sha1_openssl t_hmac_sha224_openssl t_hmac_sha256_openssl t_hmac_sha384_openssl t_hmac_sha512_openssl +TESTS += t_hmac_md5_openssl t_hmac_sha1_openssl t_hmac_sha224_openssl t_hmac_sha256_openssl t_hmac_sha384_openssl t_hmac_sha512_openssl +t_hmac_md5_openssl_SOURCES = t_hmac_md5.c +t_hmac_md5_openssl_CFLAGS = $(OPENSSL_INCLUDES) $(OPENSSL_CFLAGS) +t_hmac_md5_openssl_LDADD = $(libt) $(OPENSSL_LDADD) t_hmac_sha1_openssl_SOURCES = t_hmac_sha1.c t_hmac_sha1_openssl_CFLAGS = $(OPENSSL_INCLUDES) $(OPENSSL_CFLAGS) t_hmac_sha1_openssl_LDADD = $(libt) $(OPENSSL_LDADD) diff --git a/t/t_hmac_md5.c b/t/t_hmac_md5.c new file mode 100644 index 0000000..0bda382 --- /dev/null +++ b/t/t_hmac_md5.c @@ -0,0 +1,182 @@ +/*- + * Copyright (c) 2012 The University of Oslo + * Copyright (c) 2012-2022 Dag-Erling Smørgrav + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cryb/impl.h" + +#include +#include +#include +#include + +#include + +#if WITH_OPENSSL + +#include +#include +#include + +#define HMAC_MD5_MAC_LEN MD5_DIGEST_LENGTH + +static void +t_hmac_md5_complete(const void *key, size_t keylen, + const void *msg, size_t msglen, uint8_t *mac) +{ + HMAC_CTX *ctx; + + ctx = HMAC_CTX_new(); + HMAC_Init_ex(ctx, key, keylen, EVP_md5(), NULL); + HMAC_Update(ctx, msg, msglen); + HMAC_Final(ctx, mac, NULL); + HMAC_CTX_free(ctx); +} + +#else + +#include +#include + +#define t_hmac_md5_complete(key, keylen, msg, msglen, mac) \ + hmac_md5_complete(key, keylen, msg, msglen, mac) + +#endif + +/* + * Test vectors from RFC 2104 + */ +static struct t_vector { + const char *desc; + const uint8_t *key; + size_t keylen; + const uint8_t *msg; + size_t msglen; + const uint8_t mac[HMAC_MD5_MAC_LEN]; +} t_hmac_md5_vectors[] = { + { + "zero-length key, zero-length message", + (uint8_t[]){}, + 0, + (uint8_t[]){}, + 0, + { + 0x74, 0xe6, 0xf7, 0x29, 0x8a, 0x9c, 0x2d, 0x16, + 0x89, 0x35, 0xf5, 0x8c, 0x00, 0x1b, 0xad, 0x88, + }, + }, + { + "RFC 2104 example 1", + (uint8_t[]){ + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + }, + 16, + (uint8_t *)"Hi There", + 8, + { + 0x92, 0x94, 0x72, 0x7a, 0x36, 0x38, 0xbb, 0x1c, + 0x13, 0xf4, 0x8e, 0xf8, 0x15, 0x8b, 0xfc, 0x9d, + }, + }, + { + "RFC 2104 example 2", + (uint8_t *)"Jefe", + 4, + (uint8_t *)"what do ya want for nothing?", + 28, + { + 0x75, 0x0c, 0x78, 0x3e, 0x6a, 0xb0, 0xb5, 0x03, + 0xea, 0xa8, 0x6e, 0x31, 0x0a, 0x5d, 0xb7, 0x38, + }, + }, + { + "RFC 2104 example 3", + (uint8_t[]){ + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + }, + 16, + (uint8_t[]){ + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, + }, + 50, + { + 0x56, 0xbe, 0x34, 0x52, 0x1d, 0x14, 0x4c, 0x88, + 0xdb, 0xb8, 0xc7, 0x33, 0xf0, 0xe8, 0xb3, 0xf6, + }, + }, +}; + +/* + * Unit test: compute the HMAC signature of the specified string with the + * specified key and compare it to the expected result. + */ +static int +t_hmac_md5_vector(char **desc CRYB_UNUSED, void *arg) +{ + struct t_vector *vector = (struct t_vector *)arg; + uint8_t mac[HMAC_MD5_MAC_LEN]; + + t_hmac_md5_complete(vector->key, vector->keylen, + (const uint8_t *)vector->msg, vector->msglen, + mac); + return (t_compare_mem(vector->mac, mac, HMAC_MD5_MAC_LEN)); +} + + +/*************************************************************************** + * Boilerplate + */ + +static int +t_prepare(int argc, char *argv[]) +{ + int i, n; + + (void)argc; + (void)argv; + n = sizeof t_hmac_md5_vectors / sizeof t_hmac_md5_vectors[0]; + for (i = 0; i < n; ++i) + t_add_test(t_hmac_md5_vector, &t_hmac_md5_vectors[i], + "%s", t_hmac_md5_vectors[i].desc); + return (0); +} + +int +main(int argc, char *argv[]) +{ + + t_main(t_prepare, NULL, argc, argv); +}