diff options
author | Adam Langley <agl@chromium.org> | 2014-06-20 23:00:00 +0400 |
---|---|---|
committer | Adam Langley <agl@chromium.org> | 2014-06-21 00:17:32 +0400 |
commit | 95c29f3cd1f6c08c6c0927868683392eea727ccb (patch) | |
tree | 012767320ced9abca61472a4daa4c4a56b7ebe2b /crypto/hmac |
Inital import.
Initial fork from f2d678e6e89b6508147086610e985d4e8416e867 (1.0.2 beta).
(This change contains substantial changes from the original and
effectively starts a new history.)
Diffstat (limited to 'crypto/hmac')
-rw-r--r-- | crypto/hmac/CMakeLists.txt | 18 | ||||
-rw-r--r-- | crypto/hmac/hmac.c | 208 | ||||
-rw-r--r-- | crypto/hmac/hmac.h | 155 | ||||
-rw-r--r-- | crypto/hmac/hmac_test.c | 151 |
4 files changed, 532 insertions, 0 deletions
diff --git a/crypto/hmac/CMakeLists.txt b/crypto/hmac/CMakeLists.txt new file mode 100644 index 00000000..d647b0a6 --- /dev/null +++ b/crypto/hmac/CMakeLists.txt @@ -0,0 +1,18 @@ +include_directories(. .. ../../include) + +add_library( + hmac + + OBJECT + + hmac.c +) + + +add_executable( + hmac_test + + hmac_test.c +) + +target_link_libraries(hmac_test crypto) diff --git a/crypto/hmac/hmac.c b/crypto/hmac/hmac.c new file mode 100644 index 00000000..1d37b9e4 --- /dev/null +++ b/crypto/hmac/hmac.c @@ -0,0 +1,208 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include <openssl/hmac.h> + +#include <assert.h> + +#include <openssl/mem.h> + + +uint8_t *HMAC(const EVP_MD *evp_md, const void *key, size_t key_len, + const uint8_t *data, size_t data_len, uint8_t *out, + unsigned int *out_len) { + HMAC_CTX ctx; + static uint8_t static_out_buffer[EVP_MAX_MD_SIZE]; + + /* OpenSSL has traditionally supported using a static buffer if |out| is + * NULL. We maintain that but don't document it. This behaviour should be + * considered to be deprecated. */ + if (out == NULL) { + out = static_out_buffer; + } + + HMAC_CTX_init(&ctx); + if (!HMAC_Init(&ctx, key, key_len, evp_md) || + !HMAC_Update(&ctx, data, data_len) || + !HMAC_Final(&ctx, out, out_len)) { + out = NULL; + } + + HMAC_CTX_cleanup(&ctx); + return out; +} + +void HMAC_CTX_init(HMAC_CTX *ctx) { + EVP_MD_CTX_init(&ctx->i_ctx); + EVP_MD_CTX_init(&ctx->o_ctx); + EVP_MD_CTX_init(&ctx->md_ctx); +} + +void HMAC_CTX_cleanup(HMAC_CTX *ctx) { + EVP_MD_CTX_cleanup(&ctx->i_ctx); + EVP_MD_CTX_cleanup(&ctx->o_ctx); + EVP_MD_CTX_cleanup(&ctx->md_ctx); + OPENSSL_cleanse(ctx, sizeof(ctx)); +} + +int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, size_t key_len, + const EVP_MD *md, ENGINE *impl) { + unsigned i, reset = 0; + uint8_t pad[HMAC_MAX_MD_CBLOCK]; + + if (md != NULL) { + reset = 1; + ctx->md = md; + } else { + md = ctx->md; + } + + if (key != NULL) { + size_t block_size = EVP_MD_block_size(md); + reset = 1; + assert(block_size <= sizeof(ctx->key)); + if (block_size < key_len) { + if (!EVP_DigestInit_ex(&ctx->md_ctx, md, impl) || + !EVP_DigestUpdate(&ctx->md_ctx, key, key_len) || + !EVP_DigestFinal_ex(&(ctx->md_ctx), ctx->key, &ctx->key_length)) { + goto err; + } + } else { + assert(key_len >= 0 && key_len <= sizeof(ctx->key)); + memcpy(ctx->key, key, key_len); + ctx->key_length = key_len; + } + if (ctx->key_length != HMAC_MAX_MD_CBLOCK) { + memset(&ctx->key[ctx->key_length], 0, sizeof(ctx->key) - ctx->key_length); + } + } + + if (reset) { + for (i = 0; i < HMAC_MAX_MD_CBLOCK; i++) { + pad[i] = 0x36 ^ ctx->key[i]; + } + if (!EVP_DigestInit_ex(&ctx->i_ctx, md, impl) || + !EVP_DigestUpdate(&ctx->i_ctx, pad, EVP_MD_block_size(md))) { + goto err; + } + + for (i = 0; i < HMAC_MAX_MD_CBLOCK; i++) { + pad[i] = 0x5c ^ ctx->key[i]; + } + if (!EVP_DigestInit_ex(&ctx->o_ctx, md, impl) || + !EVP_DigestUpdate(&ctx->o_ctx, pad, EVP_MD_block_size(md))) { + goto err; + } + } + + if (!EVP_MD_CTX_copy_ex(&ctx->md_ctx, &ctx->i_ctx)) { + goto err; + } + + return 1; + +err: + return 0; +} + +int HMAC_Update(HMAC_CTX *ctx, const uint8_t *data, size_t data_len) { + return EVP_DigestUpdate(&ctx->md_ctx, data, data_len); +} + +int HMAC_Final(HMAC_CTX *ctx, uint8_t *out, unsigned int *out_len) { + unsigned int i; + uint8_t buf[EVP_MAX_MD_SIZE]; + + if (!EVP_DigestFinal_ex(&ctx->md_ctx, buf, &i) || + !EVP_MD_CTX_copy_ex(&ctx->md_ctx, &ctx->o_ctx) || + !EVP_DigestUpdate(&ctx->md_ctx, buf, i) || + !EVP_DigestFinal_ex(&ctx->md_ctx, out, out_len)) { + *out_len = 0; + return 0; + } + + return 1; +} + +size_t HMAC_size(const HMAC_CTX *ctx) { + return EVP_MD_size(ctx->md); +} + +int HMAC_CTX_copy(HMAC_CTX *dest, const HMAC_CTX *src) { + if (!EVP_MD_CTX_copy(&dest->i_ctx, &src->i_ctx) || + !EVP_MD_CTX_copy(&dest->o_ctx, &src->o_ctx) || + !EVP_MD_CTX_copy(&dest->md_ctx, &src->md_ctx)) { + return 0; + } + + memcpy(dest->key, src->key, HMAC_MAX_MD_CBLOCK); + dest->key_length = src->key_length; + dest->md = src->md; + return 1; +} + +void HMAC_CTX_set_flags(HMAC_CTX *ctx, unsigned long flags) { + EVP_MD_CTX_set_flags(&ctx->i_ctx, flags); + EVP_MD_CTX_set_flags(&ctx->o_ctx, flags); + EVP_MD_CTX_set_flags(&ctx->md_ctx, flags); +} + +int HMAC_Init(HMAC_CTX *ctx, const void *key, int key_len, const EVP_MD *md) { + if (key && md) { + HMAC_CTX_init(ctx); + } + return HMAC_Init_ex(ctx, key, key_len, md, NULL); +} diff --git a/crypto/hmac/hmac.h b/crypto/hmac/hmac.h new file mode 100644 index 00000000..33c90615 --- /dev/null +++ b/crypto/hmac/hmac.h @@ -0,0 +1,155 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_HMAC_H +#define OPENSSL_HEADER_HMAC_H + +#include <openssl/base.h> + +#include <openssl/digest.h> + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* HMAC contains functions for constructing PRFs from Merkle–Damgård hash + * functions using HMAC. */ + + +/* One-shot operation. */ + +/* HMAC calculates the HMAC of |data_len| bytes of |data|, using the given key + * and hash function, and writes the result to |out|. On entry, |out| must + * contain |EVP_MAX_MD_SIZE| bytes of space. The actual length of the result is + * written to |*out_len|. It returns |out| or NULL on error. */ +uint8_t *HMAC(const EVP_MD *evp_md, const void *key, size_t key_len, + const uint8_t *data, size_t data_len, uint8_t *out, + unsigned int *out_len); + + +/* Incremental operation. */ + +/* HMAC_CTX_init initialises |ctx| for use in an HMAC operation. It's assumed + * that HMAC_CTX objects will be allocated on the stack thus no allocation + * function is provided. If needed, allocate |sizeof(HMAC_CTX)| and call + * |HMAC_CTX_init| on it. */ +void HMAC_CTX_init(HMAC_CTX *ctx); + +/* HMAC_CTX_cleanup frees data owned by |ctx|. */ +void HMAC_CTX_cleanup(HMAC_CTX *ctx); + +/* HMAC_Init_ex sets up an initialised |HMAC_CTX| to use |md| as the hash + * function and |key| as the key. Any of |md| or |key| can be NULL, in which + * case the previous value will be used. It returns one on success or zero + * otherwise. */ +int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, size_t key_len, + const EVP_MD *md, ENGINE *impl); + +/* HMAC_Update hashes |data_len| bytes from |data| into the current HMAC + * operation in |ctx|. It returns one on success and zero on error. */ +int HMAC_Update(HMAC_CTX *ctx, const uint8_t *data, size_t data_len); + +/* HMAC_Final completes the HMAC operation in |ctx| and writes the result to + * |out| and the sets |*out_len| to the length of the result. On entry, |out| + * must contain at least |EVP_MAX_MD_SIZE| bytes of space. It returns one on + * success or zero on error. */ +int HMAC_Final(HMAC_CTX *ctx, uint8_t *out, unsigned int *out_len); + + +/* Utility functions. */ + +/* HMAC_size returns the size, in bytes, of the HMAC that will be produced by + * |ctx|. On entry, |ctx| must have been setup with |HMAC_Init_ex|. */ +size_t HMAC_size(const HMAC_CTX *ctx); + +/* HMAC_CTX_copy sets |dest| equal to |src|. On entry, |dest| must have been + * initialised by calling |HMAC_CTX_init|. It returns one on success and zero + * on error. */ +int HMAC_CTX_copy(HMAC_CTX *dest, const HMAC_CTX *src); + +/* HMAC_CTX_set_flags ORs |flags| into the flags of the underlying digests of + * |ctx|, which must have been setup by a call to |HMAC_Init_ex|. See + * |EVP_MD_CTX_set_flags|. + * + * TODO(fork): remove? */ +void HMAC_CTX_set_flags(HMAC_CTX *ctx, unsigned long flags); + + +/* Deprecated functions. */ + +int HMAC_Init(HMAC_CTX *ctx, const void *key, int key_len, const EVP_MD *md); + + +/* Private functions */ + +#define HMAC_MAX_MD_CBLOCK 128 /* largest known is SHA512 */ + +struct hmac_ctx_st { + const EVP_MD *md; + EVP_MD_CTX md_ctx; + EVP_MD_CTX i_ctx; + EVP_MD_CTX o_ctx; + unsigned int key_length; + unsigned char key[HMAC_MAX_MD_CBLOCK]; +} /* HMAC_CTX */; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_HMAC_H */ diff --git a/crypto/hmac/hmac_test.c b/crypto/hmac/hmac_test.c new file mode 100644 index 00000000..e2ae4a6f --- /dev/null +++ b/crypto/hmac/hmac_test.c @@ -0,0 +1,151 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include <stdio.h> + +#include <openssl/digest.h> +#include <openssl/hmac.h> + + +struct test_st { + unsigned char key[16]; + unsigned key_len; + unsigned char data[64]; + unsigned data_len; + const char *hex_digest; +}; + +#define NUM_TESTS 4 + +static const struct test_st kTests[NUM_TESTS] = { + { + "", 0, "More text test vectors to stuff up EBCDIC machines :-)", 54, + "e9139d1e6ee064ef8cf514fc7dc83e86", + }, + { + { + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, + }, + 16, + "Hi There", + 8, + "9294727a3638bb1c13f48ef8158bfc9d", + }, + { + "Jefe", 4, "what do ya want for nothing?", 28, + "750c783e6ab0b503eaa86e310a5db738", + }, + { + { + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, + }, + 16, + { + 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, + "56be34521d144c88dbb8c733f0e8b3f6", + }, +}; + +static char *to_hex(const uint8_t *md, size_t md_len) { + size_t i; + static char buf[80]; + + for (i = 0; i < md_len; i++) { + sprintf(&(buf[i * 2]), "%02x", md[i]); + } + return buf; +} + +int main(int argc, char *argv[]) { + unsigned i; + char *p; + int err = 0; + uint8_t out[EVP_MAX_MD_SIZE]; + unsigned out_len; + + for (i = 0; i < NUM_TESTS; i++) { + const struct test_st *test = &kTests[i]; + + if (NULL == HMAC(EVP_md5(), test->key, test->key_len, test->data, + test->data_len, out, &out_len)) { + printf("%u: HMAC failed.\n", i); + err++; + continue; + } + + p = to_hex(out, out_len); + + if (strcmp(p, test->hex_digest) != 0) { + printf("%u: got %s instead of %s\n", i, p, test->hex_digest); + err++; + } + } + + if (err) { + return 1; + } + + printf("PASS\n"); + return 0; +} |