/src/trezor-firmware/crypto/hmac_drbg.c
Line | Count | Source (jump to first uncovered line) |
1 | | /** |
2 | | * Copyright (c) 2019 Andrew R. Kozlik |
3 | | * |
4 | | * Permission is hereby granted, free of charge, to any person obtaining |
5 | | * a copy of this software and associated documentation files (the "Software"), |
6 | | * to deal in the Software without restriction, including without limitation |
7 | | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
8 | | * and/or sell copies of the Software, and to permit persons to whom the |
9 | | * Software is furnished to do so, subject to the following conditions: |
10 | | * |
11 | | * The above copyright notice and this permission notice shall be included |
12 | | * in all copies or substantial portions of the Software. |
13 | | * |
14 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
15 | | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
16 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
17 | | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES |
18 | | * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
19 | | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
20 | | * OTHER DEALINGS IN THE SOFTWARE. |
21 | | */ |
22 | | |
23 | | #include "hmac_drbg.h" |
24 | | #include <string.h> |
25 | | #include "memzero.h" |
26 | | #include "sha2.h" |
27 | | |
28 | | static void update_k(HMAC_DRBG_CTX *ctx, uint8_t domain, const uint8_t *data1, |
29 | 609 | size_t len1, const uint8_t *data2, size_t len2) { |
30 | | // Computes K = HMAC(K, V || domain || data1 || data 2). |
31 | | |
32 | | // First hash operation of HMAC. |
33 | 609 | uint32_t h[SHA256_BLOCK_LENGTH / sizeof(uint32_t)] = {0}; |
34 | 609 | if (len1 + len2 == 0) { |
35 | 203 | ctx->v[8] = 0x00800000; |
36 | 203 | ctx->v[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH + 1) * 8; |
37 | 203 | sha256_Transform(ctx->idig, ctx->v, h); |
38 | 203 | ctx->v[8] = 0x80000000; |
39 | 203 | ctx->v[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8; |
40 | 406 | } else { |
41 | 406 | SHA256_CTX sha_ctx = {0}; |
42 | 406 | memcpy(sha_ctx.state, ctx->idig, SHA256_DIGEST_LENGTH); |
43 | 3.65k | for (size_t i = 0; i < SHA256_DIGEST_LENGTH / sizeof(uint32_t); i++) { |
44 | 3.24k | #if BYTE_ORDER == LITTLE_ENDIAN |
45 | 3.24k | REVERSE32(ctx->v[i], sha_ctx.buffer[i]); |
46 | | #else |
47 | | sha_ctx.buffer[i] = ctx->v[i]; |
48 | | #endif |
49 | 3.24k | } |
50 | 406 | ((uint8_t *)sha_ctx.buffer)[SHA256_DIGEST_LENGTH] = domain; |
51 | 406 | sha_ctx.bitcount = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH + 1) * 8; |
52 | 406 | sha256_Update(&sha_ctx, data1, len1); |
53 | 406 | sha256_Update(&sha_ctx, data2, len2); |
54 | 406 | sha256_Final(&sha_ctx, (uint8_t *)h); |
55 | 406 | #if BYTE_ORDER == LITTLE_ENDIAN |
56 | 3.65k | for (size_t i = 0; i < SHA256_DIGEST_LENGTH / sizeof(uint32_t); i++) |
57 | 3.24k | REVERSE32(h[i], h[i]); |
58 | 406 | #endif |
59 | 406 | } |
60 | | |
61 | | // Second hash operation of HMAC. |
62 | 609 | h[8] = 0x80000000; |
63 | 609 | h[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8; |
64 | 609 | sha256_Transform(ctx->odig, h, h); |
65 | | |
66 | | // Precompute the inner digest and outer digest of K. |
67 | 609 | h[8] = 0; |
68 | 609 | h[15] = 0; |
69 | 10.3k | for (size_t i = 0; i < SHA256_BLOCK_LENGTH / sizeof(uint32_t); i++) { |
70 | 9.74k | h[i] ^= 0x36363636; |
71 | 9.74k | } |
72 | 609 | sha256_Transform(sha256_initial_hash_value, h, ctx->idig); |
73 | | |
74 | 10.3k | for (size_t i = 0; i < SHA256_BLOCK_LENGTH / sizeof(uint32_t); i++) { |
75 | 9.74k | h[i] = h[i] ^ 0x36363636 ^ 0x5c5c5c5c; |
76 | 9.74k | } |
77 | 609 | sha256_Transform(sha256_initial_hash_value, h, ctx->odig); |
78 | 609 | memzero(h, sizeof(h)); |
79 | 609 | } |
80 | | |
81 | 812 | static void update_v(HMAC_DRBG_CTX *ctx) { |
82 | 812 | sha256_Transform(ctx->idig, ctx->v, ctx->v); |
83 | 812 | sha256_Transform(ctx->odig, ctx->v, ctx->v); |
84 | 812 | } |
85 | | |
86 | | void hmac_drbg_init(HMAC_DRBG_CTX *ctx, const uint8_t *entropy, |
87 | | size_t entropy_len, const uint8_t *nonce, |
88 | 203 | size_t nonce_len) { |
89 | 203 | uint32_t h[SHA256_BLOCK_LENGTH / sizeof(uint32_t)] = {0}; |
90 | | |
91 | | // Precompute the inner digest and outer digest of K = 0x00 ... 0x00. |
92 | 203 | memset(h, 0x36, sizeof(h)); |
93 | 203 | sha256_Transform(sha256_initial_hash_value, h, ctx->idig); |
94 | 203 | memset(h, 0x5c, sizeof(h)); |
95 | 203 | sha256_Transform(sha256_initial_hash_value, h, ctx->odig); |
96 | | |
97 | | // Let V = 0x01 ... 0x01. |
98 | 203 | memset(ctx->v, 1, SHA256_DIGEST_LENGTH); |
99 | 1.42k | for (size_t i = 9; i < 15; i++) ctx->v[i] = 0; |
100 | 203 | ctx->v[8] = 0x80000000; |
101 | 203 | ctx->v[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8; |
102 | | |
103 | 203 | hmac_drbg_reseed(ctx, entropy, entropy_len, nonce, nonce_len); |
104 | | |
105 | 203 | memzero(h, sizeof(h)); |
106 | 203 | } |
107 | | |
108 | | void hmac_drbg_reseed(HMAC_DRBG_CTX *ctx, const uint8_t *entropy, size_t len, |
109 | 203 | const uint8_t *addin, size_t addin_len) { |
110 | 203 | update_k(ctx, 0, entropy, len, addin, addin_len); |
111 | 203 | update_v(ctx); |
112 | 203 | if (len == 0) return; |
113 | 203 | update_k(ctx, 1, entropy, len, addin, addin_len); |
114 | 203 | update_v(ctx); |
115 | 203 | } |
116 | | |
117 | 203 | void hmac_drbg_generate(HMAC_DRBG_CTX *ctx, uint8_t *buf, size_t len) { |
118 | 203 | size_t i = 0; |
119 | 406 | while (i < len) { |
120 | 203 | update_v(ctx); |
121 | 1.82k | for (size_t j = 0; j < 8 && i < len; j++) { |
122 | 1.62k | uint32_t r = ctx->v[j]; |
123 | 8.12k | for (int k = 24; k >= 0 && i < len; k -= 8) { |
124 | 6.49k | buf[i++] = (r >> k) & 0xFF; |
125 | 6.49k | } |
126 | 1.62k | } |
127 | 203 | } |
128 | 203 | update_k(ctx, 0, NULL, 0, NULL, 0); |
129 | 203 | update_v(ctx); |
130 | 203 | } |