From 0ddcf3de1cd0168816de7631a16500077ae4dfd6 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Thu, 15 Aug 2019 08:41:33 +0000 Subject: [PATCH] added hmac files --- qse/include/qse/cry/hmac.h | 96 +++++++++++++++ qse/lib/cry/hmac.c | 242 +++++++++++++++++++++++++++++++++++++ 2 files changed, 338 insertions(+) create mode 100644 qse/include/qse/cry/hmac.h create mode 100644 qse/lib/cry/hmac.c diff --git a/qse/include/qse/cry/hmac.h b/qse/include/qse/cry/hmac.h new file mode 100644 index 00000000..ab0a01a4 --- /dev/null +++ b/qse/include/qse/cry/hmac.h @@ -0,0 +1,96 @@ +/* + * $Id$ + * + Copyright (c) 2006-2019 Chung, Hyung-Hwan. 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. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "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 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 _QSE_CRY_HMAC_H_ +#define _QSE_CRY_HMAC_H_ + +#include +#include +#include + +#define QSE_HMAC_MAX_DIGEST_LEN QSE_SHA512_DIGEST_LEN +#define QSE_HMAC_MAX_BLOCK_LEN QSE_SHA512_BLOCK_LEN + +enum qse_hmac_sha_type_t +{ + QSE_HMAC_MD5, + QSE_HMAC_SHA1, + QSE_HMAC_SHA256, + QSE_HMAC_SHA384, + QSE_HMAC_SHA512 +}; +typedef enum qse_hmac_sha_type_t qse_hmac_sha_type_t; + +union qse_hmac_sha_t +{ + qse_md5_t md5; + qse_sha1_t sha1; + qse_sha256_t sha256; + qse_sha384_t sha384; + qse_sha512_t sha512; +}; +typedef union qse_hmac_sha_t qse_hmac_sha_t; + +struct qse_hmac_t +{ + qse_hmac_sha_type_t sha_type; + qse_size_t digest_size; + qse_size_t block_size; + qse_hmac_sha_t sha; + qse_uint8_t k_opad[QSE_HMAC_MAX_BLOCK_LEN]; +}; +typedef struct qse_hmac_t qse_hmac_t; + +#if defined(__cplusplus) +extern "C" { +#endif + +void qse_hmac_initialize ( + qse_hmac_t* ctx, + qse_hmac_sha_type_t sha_type, + const qse_uint8_t* key, + qse_size_t key_len +); + +void qse_hmac_update ( + qse_hmac_t* ctx, + const qse_uint8_t* data, + qse_size_t len +); + +#define qse_hmac_upatex qse_hmac_upate + +qse_size_t qse_hmac_digest ( + qse_hmac_t* ctx, + qse_uint8_t* digest, + qse_size_t size +); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/qse/lib/cry/hmac.c b/qse/lib/cry/hmac.c new file mode 100644 index 00000000..7c5a7c86 --- /dev/null +++ b/qse/lib/cry/hmac.c @@ -0,0 +1,242 @@ +/* + * $Id$ + * + Copyright (c) 2006-2019 Chung, Hyung-Hwan. 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. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "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 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. + */ + +/* + this file is based on and heavily modified of + https://github.com/Yubico/yubikey-personalization/blob/master/hmac.c + +Copyright (c) 2006-2013 Yubico AB +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * 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. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT +OWNER 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 + +static inline qse_size_t sha_block_size (qse_hmac_sha_type_t sha_type) +{ + static qse_size_t block_size[] = + { + QSE_MD5_BLOCK_LEN, + QSE_SHA1_BLOCK_LEN, + QSE_SHA256_BLOCK_LEN, + QSE_SHA384_BLOCK_LEN, + QSE_SHA512_BLOCK_LEN + }; + return block_size[sha_type]; +} + +static inline qse_size_t sha_digest_size (qse_hmac_sha_type_t sha_type) +{ + static qse_size_t digest_size[] = + { + QSE_MD5_DIGEST_LEN, + QSE_SHA1_DIGEST_LEN, + QSE_SHA256_DIGEST_LEN, + QSE_SHA384_DIGEST_LEN, + QSE_SHA512_DIGEST_LEN + }; + return digest_size[sha_type]; +} + +static inline void sha_initialize (qse_hmac_sha_t* ctx, qse_hmac_sha_type_t sha_type) +{ + switch (sha_type) + { + case QSE_HMAC_MD5: + qse_md5_initialize (&ctx->md5); + break; + case QSE_HMAC_SHA1: + qse_sha1_initialize (&ctx->sha1); + break; + case QSE_HMAC_SHA256: + qse_sha256_initialize (&ctx->sha256); + break; + case QSE_HMAC_SHA384: + qse_sha384_initialize (&ctx->sha384); + break; + case QSE_HMAC_SHA512: + qse_sha512_initialize (&ctx->sha512); + break; + } +} +static inline void sha_updatex (qse_hmac_sha_t* ctx, qse_hmac_sha_type_t sha_type, const qse_uint8_t* data, qse_size_t len) +{ + switch (sha_type) + { + case QSE_HMAC_MD5: + qse_md5_updatex (&ctx->md5, data, len); + break; + case QSE_HMAC_SHA1: + qse_sha1_updatex (&ctx->sha1, data, len); + break; + case QSE_HMAC_SHA256: + qse_sha256_updatex (&ctx->sha256, data, len); + break; + case QSE_HMAC_SHA384: + qse_sha384_updatex (&ctx->sha384, data, len); + break; + case QSE_HMAC_SHA512: + qse_sha512_updatex (&ctx->sha512, data, len); + break; + } +} + +static inline qse_size_t sha_digest (qse_hmac_sha_t* ctx, qse_hmac_sha_type_t sha_type, qse_uint8_t* digest, qse_size_t size) +{ + switch (sha_type) + { + case QSE_HMAC_MD5: + return qse_md5_digest(&ctx->md5, digest, size); + + case QSE_HMAC_SHA1: + return qse_sha1_digest(&ctx->sha1, digest, size); + + case QSE_HMAC_SHA256: + return qse_sha256_digest(&ctx->sha256, digest, size); + + case QSE_HMAC_SHA384: + return qse_sha384_digest(&ctx->sha384, digest, size); + + case QSE_HMAC_SHA512: + return qse_sha512_digest(&ctx->sha512, digest, size); + + } + + /* this should not happen */ + return 0; +} + + +/******************** See RFC 4634 for details ******************/ +/* + * Description: + * This file implements the HMAC algorithm (Keyed-Hashing for + * Message Authentication, RFC2104), expressed in terms of the + * various SHA algorithms. + */ + +void qse_hmac_initialize (qse_hmac_t* ctx, qse_hmac_sha_type_t sha_type, const qse_uint8_t* key, qse_size_t key_len) +{ + qse_size_t i, block_size, digest_size; + + /* inner padding - key XORd with ipad */ + qse_uint8_t k_ipad[QSE_HMAC_MAX_BLOCK_LEN]; + + /* temporary buffer when keylen > block_size */ + qse_uint8_t tempkey[QSE_HMAC_MAX_DIGEST_LEN]; + + block_size = ctx->block_size = sha_block_size(sha_type); + digest_size = ctx->digest_size = sha_digest_size(sha_type); + + ctx->sha_type = sha_type; + + /* + * If key is longer than the hash block_size, + * reset it to key = HASH(key). + */ + if (key_len > block_size) + { + qse_hmac_sha_t tctx; + + sha_initialize (&tctx, sha_type); + sha_updatex (&tctx, sha_type, key, key_len); + sha_digest (&tctx, sha_type, tempkey, QSE_SIZEOF(tempkey)); + + key = tempkey; + key_len = digest_size; + } + + /* + * The HMAC transform looks like: + * + * SHA(K XOR opad, SHA(K XOR ipad, text)) + * + * where K is an n byte key. + * ipad is the byte 0x36 repeated block_size times + * opad is the byte 0x5c repeated block_size times + * and text is the data being protected. + */ + + /* store key into the pads, XOR'd with ipad and opad values */ + for (i = 0; i < key_len; i++) + { + k_ipad[i] = key[i] ^ 0x36; + ctx->k_opad[i] = key[i] ^ 0x5c; + } + /* remaining pad bytes are '\0' XOR'd with ipad and opad values */ + for (; i < block_size; i++) + { + k_ipad[i] = 0x36; + ctx->k_opad[i] = 0x5c; + } + + /* perform inner hash */ + sha_initialize (&ctx->sha, sha_type); + sha_updatex (&ctx->sha, sha_type, k_ipad, block_size); +} + +void qse_hmac_update (qse_hmac_t * ctx, const qse_uint8_t* data, qse_size_t len) +{ + sha_updatex (&ctx->sha, ctx->sha_type, data, len); +} + +qse_size_t qse_hmac_digest (qse_hmac_t* ctx, qse_uint8_t* digest, qse_size_t size) +{ + qse_uint8_t tmp[QSE_HMAC_MAX_DIGEST_LEN]; + qse_size_t tmpsz; + + tmpsz = sha_digest(&ctx->sha, ctx->sha_type, tmp, QSE_SIZEOF(tmp)); + QSE_ASSERT (tmpsz == ctx->digest_size); + + /* outer SHA */ + sha_initialize (&ctx->sha, ctx->sha_type); + sha_updatex (&ctx->sha, ctx->sha_type, ctx->k_opad, ctx->block_size); + sha_updatex (&ctx->sha, ctx->sha_type, tmp, tmpsz); + return sha_digest(&ctx->sha, ctx->sha_type, digest, size); +}