| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- /**
- * Copyright (c) 2019 Andrew R. Kozlik
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
- * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
- #include "hmac_drbg.h"
- #include <string.h>
- #include "memzero.h"
- #include "sha2.h"
- static void update_k(
- HMAC_DRBG_CTX* ctx,
- uint8_t domain,
- const uint8_t* data1,
- size_t len1,
- const uint8_t* data2,
- size_t len2) {
- // Computes K = HMAC(K, V || domain || data1 || data 2).
- // First hash operation of HMAC.
- uint32_t h[SHA256_BLOCK_LENGTH / sizeof(uint32_t)] = {0};
- if(len1 + len2 == 0) {
- ctx->v[8] = 0x00800000;
- ctx->v[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH + 1) * 8;
- sha256_Transform(ctx->idig, ctx->v, h);
- ctx->v[8] = 0x80000000;
- ctx->v[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8;
- } else {
- SHA256_CTX sha_ctx = {0};
- memcpy(sha_ctx.state, ctx->idig, SHA256_DIGEST_LENGTH);
- for(size_t i = 0; i < SHA256_DIGEST_LENGTH / sizeof(uint32_t); i++) {
- #if BYTE_ORDER == LITTLE_ENDIAN
- REVERSE32(ctx->v[i], sha_ctx.buffer[i]);
- #else
- sha_ctx.buffer[i] = ctx->v[i];
- #endif
- }
- ((uint8_t*)sha_ctx.buffer)[SHA256_DIGEST_LENGTH] = domain;
- sha_ctx.bitcount = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH + 1) * 8;
- sha256_Update(&sha_ctx, data1, len1);
- sha256_Update(&sha_ctx, data2, len2);
- sha256_Final(&sha_ctx, (uint8_t*)h);
- #if BYTE_ORDER == LITTLE_ENDIAN
- for(size_t i = 0; i < SHA256_DIGEST_LENGTH / sizeof(uint32_t); i++) REVERSE32(h[i], h[i]);
- #endif
- }
- // Second hash operation of HMAC.
- h[8] = 0x80000000;
- h[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8;
- sha256_Transform(ctx->odig, h, h);
- // Precompute the inner digest and outer digest of K.
- h[8] = 0;
- h[15] = 0;
- for(size_t i = 0; i < SHA256_BLOCK_LENGTH / sizeof(uint32_t); i++) {
- h[i] ^= 0x36363636;
- }
- sha256_Transform(sha256_initial_hash_value, h, ctx->idig);
- for(size_t i = 0; i < SHA256_BLOCK_LENGTH / sizeof(uint32_t); i++) {
- h[i] = h[i] ^ 0x36363636 ^ 0x5c5c5c5c;
- }
- sha256_Transform(sha256_initial_hash_value, h, ctx->odig);
- memzero(h, sizeof(h));
- }
- static void update_v(HMAC_DRBG_CTX* ctx) {
- sha256_Transform(ctx->idig, ctx->v, ctx->v);
- sha256_Transform(ctx->odig, ctx->v, ctx->v);
- }
- void hmac_drbg_init(
- HMAC_DRBG_CTX* ctx,
- const uint8_t* entropy,
- size_t entropy_len,
- const uint8_t* nonce,
- size_t nonce_len) {
- uint32_t h[SHA256_BLOCK_LENGTH / sizeof(uint32_t)] = {0};
- // Precompute the inner digest and outer digest of K = 0x00 ... 0x00.
- memset(h, 0x36, sizeof(h));
- sha256_Transform(sha256_initial_hash_value, h, ctx->idig);
- memset(h, 0x5c, sizeof(h));
- sha256_Transform(sha256_initial_hash_value, h, ctx->odig);
- // Let V = 0x01 ... 0x01.
- memset(ctx->v, 1, SHA256_DIGEST_LENGTH);
- for(size_t i = 9; i < 15; i++) ctx->v[i] = 0;
- ctx->v[8] = 0x80000000;
- ctx->v[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8;
- hmac_drbg_reseed(ctx, entropy, entropy_len, nonce, nonce_len);
- memzero(h, sizeof(h));
- }
- void hmac_drbg_reseed(
- HMAC_DRBG_CTX* ctx,
- const uint8_t* entropy,
- size_t len,
- const uint8_t* addin,
- size_t addin_len) {
- update_k(ctx, 0, entropy, len, addin, addin_len);
- update_v(ctx);
- if(len == 0) return;
- update_k(ctx, 1, entropy, len, addin, addin_len);
- update_v(ctx);
- }
- void hmac_drbg_generate(HMAC_DRBG_CTX* ctx, uint8_t* buf, size_t len) {
- size_t i = 0;
- while(i < len) {
- update_v(ctx);
- for(size_t j = 0; j < 8 && i < len; j++) {
- uint32_t r = ctx->v[j];
- for(int k = 24; k >= 0 && i < len; k -= 8) {
- buf[i++] = (r >> k) & 0xFF;
- }
- }
- }
- update_k(ctx, 0, NULL, 0, NULL, 0);
- update_v(ctx);
- }
|