/* * Copyright (c) 2015, DiUS Computing Pty Ltd (jmattsson@dius.com.au) * 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. Neither the name of the copyright holder nor the names of contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``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 CONTRIBUTOR(S) 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 "digests.h" #include "user_config.h" #include "lwip/mem.h" #include "lwip/arch.h" #include "ssl/ssl_crypto.h" #include "sha2.h" #include #include typedef char ensure_int_and_size_t_same[(sizeof(int)==sizeof(size_t)) ? 0 : -1]; /* None of the functions match the prototype fully due to the void *, and in some cases also the int vs size_t len, so wrap declarations in a macro. */ #define MECH(pfx, ds, bs) \ { #pfx, \ (create_ctx_fn)pfx ## _Init, \ (update_ctx_fn)pfx ## _Update, \ (finalize_ctx_fn)pfx ## _Final, \ sizeof(pfx ## _CTX), \ ds, \ bs } static const digest_mech_info_t hash_mechs[] = { MECH(MD2, MD2_SIZE, 16) ,MECH(MD5, MD5_SIZE, 64) ,MECH(SHA1, SHA1_SIZE, 64) #ifdef SHA2_ENABLE ,MECH(SHA256, SHA256_DIGEST_LENGTH, SHA256_BLOCK_LENGTH) ,MECH(SHA384, SHA384_DIGEST_LENGTH, SHA384_BLOCK_LENGTH) ,MECH(SHA512, SHA512_DIGEST_LENGTH, SHA512_BLOCK_LENGTH) #endif }; #undef MECH const digest_mech_info_t *crypto_digest_mech (const char *mech) { if (!mech) return 0; size_t i; for (i = 0; i < (sizeof (hash_mechs) / sizeof (digest_mech_info_t)); ++i) { const digest_mech_info_t *mi = hash_mechs + i; if (strcasecmp (mech, mi->name) == 0) return mi; } return 0; } static const char hex[] = "0123456789abcdef"; // note: supports in-place encoding void crypto_encode_asciihex (const char *bin, size_t binlen, char *outbuf) { size_t aidx = binlen * 2 -1; int i; for (i = binlen -1; i >= 0; --i) { outbuf[aidx--] = hex[bin[i] & 0xf]; outbuf[aidx--] = hex[bin[i] >> 4]; } } size_t crypto_digest_size (const char *mech) { const digest_mech_info_t *mi = crypto_digest_mech (mech); return mi ? mi->digest_size : 0; } int crypto_hash (const digest_mech_info_t *mi, const char *data, size_t data_len, uint8_t *digest) { if (!mi) return EINVAL; void *ctx = os_malloc (mi->ctx_size); if (!ctx) return ENOMEM; mi->create (ctx); mi->update (ctx, data, data_len); mi->finalize (digest, ctx); os_free (ctx); return 0; } int crypto_hmac (const digest_mech_info_t *mi, const char *data, size_t data_len, const char *key, size_t key_len, uint8_t *digest) { if (!mi) return EINVAL; void *ctx = os_malloc (mi->ctx_size); if (!ctx) return ENOMEM; // If key too long, it needs to be hashed before use if (key_len > mi->block_size) { mi->create (ctx); mi->update (ctx, key, key_len); mi->finalize (digest, ctx); key = digest; key_len = mi->block_size; } const size_t bs = mi->block_size; uint8_t k_ipad[bs]; uint8_t k_opad[bs]; os_memset (k_ipad, 0x36, bs); os_memset (k_opad, 0x5c, bs); size_t i; for (i = 0; i < key_len; ++i) { k_ipad[i] ^= key[i]; k_opad[i] ^= key[i]; } mi->create (ctx); mi->update (ctx, k_ipad, bs); mi->update (ctx, data, data_len); mi->finalize (digest, ctx); mi->create (ctx); mi->update (ctx, k_opad, bs); mi->update (ctx, digest, mi->digest_size); mi->finalize (digest, ctx); os_free (ctx); return 0; }