1 /* 2 * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org> 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining 5 * a copy of this software and associated documentation files (the 6 * "Software"), to deal in the Software without restriction, including 7 * without limitation the rights to use, copy, modify, merge, publish, 8 * distribute, sublicense, and/or sell copies of the Software, and to 9 * permit persons to whom the Software is furnished to do so, subject to 10 * the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be 13 * included in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 */ 24 25 #include "inner.h" 26 27 /* 28 * An aggregate context that is large enough for all supported hash 29 * functions. 30 */ 31 typedef union { 32 const br_hash_class *vtable; 33 br_md5_context md5; 34 br_sha1_context sha1; 35 br_sha224_context sha224; 36 br_sha256_context sha256; 37 br_sha384_context sha384; 38 br_sha512_context sha512; 39 } gen_hash_context; 40 41 /* 42 * Get the offset to the state for a specific hash function within the 43 * context structure. This shall be called only for the supported hash 44 * functions, 45 */ 46 static size_t 47 get_state_offset(int id) 48 { 49 if (id >= 5) { 50 /* 51 * SHA-384 has id 5, and SHA-512 has id 6. Both use 52 * eight 64-bit words for their state. 53 */ 54 return offsetof(br_multihash_context, val_64) 55 + ((size_t)(id - 5) * (8 * sizeof(uint64_t))); 56 } else { 57 /* 58 * MD5 has id 1, SHA-1 has id 2, SHA-224 has id 3 and 59 * SHA-256 has id 4. They use 32-bit words for their 60 * states (4 words for MD5, 5 for SHA-1, 8 for SHA-224 61 * and 8 for SHA-256). 62 */ 63 unsigned x; 64 65 x = id - 1; 66 x = ((x + (x & (x >> 1))) << 2) + (x >> 1); 67 return offsetof(br_multihash_context, val_32) 68 + x * sizeof(uint32_t); 69 } 70 } 71 72 /* see bearssl_hash.h */ 73 void 74 br_multihash_zero(br_multihash_context *ctx) 75 { 76 /* 77 * This is not standard, but yields very short and efficient code, 78 * and it works "everywhere". 79 */ 80 memset(ctx, 0, sizeof *ctx); 81 } 82 83 /* see bearssl_hash.h */ 84 void 85 br_multihash_init(br_multihash_context *ctx) 86 { 87 int i; 88 89 ctx->count = 0; 90 for (i = 1; i <= 6; i ++) { 91 const br_hash_class *hc; 92 93 hc = ctx->impl[i - 1]; 94 if (hc != NULL) { 95 gen_hash_context g; 96 97 hc->init(&g.vtable); 98 hc->state(&g.vtable, 99 (unsigned char *)ctx + get_state_offset(i)); 100 } 101 } 102 } 103 104 /* see bearssl_hash.h */ 105 void 106 br_multihash_update(br_multihash_context *ctx, const void *data, size_t len) 107 { 108 const unsigned char *buf; 109 size_t ptr; 110 111 buf = data; 112 ptr = (size_t)ctx->count & 127; 113 while (len > 0) { 114 size_t clen; 115 116 clen = 128 - ptr; 117 if (clen > len) { 118 clen = len; 119 } 120 memcpy(ctx->buf + ptr, buf, clen); 121 ptr += clen; 122 buf += clen; 123 len -= clen; 124 ctx->count += (uint64_t)clen; 125 if (ptr == 128) { 126 int i; 127 128 for (i = 1; i <= 6; i ++) { 129 const br_hash_class *hc; 130 131 hc = ctx->impl[i - 1]; 132 if (hc != NULL) { 133 gen_hash_context g; 134 unsigned char *state; 135 136 state = (unsigned char *)ctx 137 + get_state_offset(i); 138 hc->set_state(&g.vtable, 139 state, ctx->count - 128); 140 hc->update(&g.vtable, ctx->buf, 128); 141 hc->state(&g.vtable, state); 142 } 143 } 144 ptr = 0; 145 } 146 } 147 } 148 149 /* see bearssl_hash.h */ 150 size_t 151 br_multihash_out(const br_multihash_context *ctx, int id, void *dst) 152 { 153 const br_hash_class *hc; 154 gen_hash_context g; 155 const unsigned char *state; 156 157 hc = ctx->impl[id - 1]; 158 if (hc == NULL) { 159 return 0; 160 } 161 state = (const unsigned char *)ctx + get_state_offset(id); 162 hc->set_state(&g.vtable, state, ctx->count & ~(uint64_t)127); 163 hc->update(&g.vtable, ctx->buf, ctx->count & (uint64_t)127); 164 hc->out(&g.vtable, dst); 165 return (hc->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK; 166 } 167