1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */ 2 /* SPDX-License-Identifier: Unlicense */ 3 /* 4 * Copyright (c) 2023, Linaro Limited 5 */ 6 7 /* based on https://github.com/brainhub/SHA3IUF (public domain) */ 8 9 #include <crypto/crypto_accel.h> 10 #include <io.h> 11 #include <tomcrypt_private.h> 12 13 #ifdef LTC_SHA3 14 15 const struct ltc_hash_descriptor sha3_224_desc = 16 { 17 "sha3-224", /* name of hash */ 18 17, /* internal ID */ 19 28, /* Size of digest in octets */ 20 144, /* Input block size in octets */ 21 { 2,16,840,1,101,3,4,2,7 }, /* ASN.1 OID */ 22 9, /* Length OID */ 23 &sha3_224_init, 24 &sha3_process, 25 &sha3_done, 26 &sha3_224_test, 27 NULL 28 }; 29 30 const struct ltc_hash_descriptor sha3_256_desc = 31 { 32 "sha3-256", /* name of hash */ 33 18, /* internal ID */ 34 32, /* Size of digest in octets */ 35 136, /* Input block size in octets */ 36 { 2,16,840,1,101,3,4,2,8 }, /* ASN.1 OID */ 37 9, /* Length OID */ 38 &sha3_256_init, 39 &sha3_process, 40 &sha3_done, 41 &sha3_256_test, 42 NULL 43 }; 44 45 const struct ltc_hash_descriptor sha3_384_desc = 46 { 47 "sha3-384", /* name of hash */ 48 19, /* internal ID */ 49 48, /* Size of digest in octets */ 50 104, /* Input block size in octets */ 51 { 2,16,840,1,101,3,4,2,9 }, /* ASN.1 OID */ 52 9, /* Length OID */ 53 &sha3_384_init, 54 &sha3_process, 55 &sha3_done, 56 &sha3_384_test, 57 NULL 58 }; 59 60 const struct ltc_hash_descriptor sha3_512_desc = 61 { 62 "sha3-512", /* name of hash */ 63 20, /* internal ID */ 64 64, /* Size of digest in octets */ 65 72, /* Input block size in octets */ 66 { 2,16,840,1,101,3,4,2,10 }, /* ASN.1 OID */ 67 9, /* Length OID */ 68 &sha3_512_init, 69 &sha3_process, 70 &sha3_done, 71 &sha3_512_test, 72 NULL 73 }; 74 75 /* Public Inteface */ 76 77 int sha3_224_init(hash_state *md) 78 { 79 LTC_ARGCHK(md != NULL); 80 XMEMSET(&md->sha3, 0, sizeof(md->sha3)); 81 md->sha3.capacity_words = 2 * 224 / (8 * sizeof(ulong64)); 82 return CRYPT_OK; 83 } 84 85 int sha3_256_init(hash_state *md) 86 { 87 LTC_ARGCHK(md != NULL); 88 XMEMSET(&md->sha3, 0, sizeof(md->sha3)); 89 md->sha3.capacity_words = 2 * 256 / (8 * sizeof(ulong64)); 90 return CRYPT_OK; 91 } 92 93 int sha3_384_init(hash_state *md) 94 { 95 LTC_ARGCHK(md != NULL); 96 XMEMSET(&md->sha3, 0, sizeof(md->sha3)); 97 md->sha3.capacity_words = 2 * 384 / (8 * sizeof(ulong64)); 98 return CRYPT_OK; 99 } 100 101 int sha3_512_init(hash_state *md) 102 { 103 LTC_ARGCHK(md != NULL); 104 XMEMSET(&md->sha3, 0, sizeof(md->sha3)); 105 md->sha3.capacity_words = 2 * 512 / (8 * sizeof(ulong64)); 106 return CRYPT_OK; 107 } 108 109 int sha3_shake_init(hash_state *md, int num) 110 { 111 LTC_ARGCHK(md != NULL); 112 if (num != 128 && num != 256) return CRYPT_INVALID_ARG; 113 XMEMSET(&md->sha3, 0, sizeof(md->sha3)); 114 md->sha3.capacity_words = (unsigned short)(2 * num / (8 * sizeof(ulong64))); 115 return CRYPT_OK; 116 } 117 118 int sha3_process(hash_state *md, const unsigned char *in, unsigned long inlen) 119 { 120 unsigned int digest_size = 0; 121 unsigned int block_count = 0; 122 unsigned int block_size = 0; 123 void *state = NULL; 124 unsigned int l = 0; 125 126 if (!inlen) 127 return CRYPT_OK; 128 LTC_ARGCHK(md); 129 LTC_ARGCHK(in); 130 131 block_size = 200 - md->sha3.capacity_words * 8; 132 digest_size = md->sha3.capacity_words * 8 / 2; 133 state = md->sha3.s; 134 135 if (md->sha3.byte_index) { 136 l = MIN(block_size - md->sha3.byte_index, inlen); 137 memcpy(md->sha3.sb + md->sha3.byte_index, in, l); 138 in += l; 139 inlen -= l; 140 md->sha3.byte_index += l; 141 if (md->sha3.byte_index == block_size) { 142 crypto_accel_sha3_compress(state, md->sha3.sb, 1, 143 digest_size); 144 md->sha3.byte_index = 0; 145 } 146 147 if (!inlen) 148 return CRYPT_OK; 149 } 150 151 if (inlen > block_size) { 152 block_count = inlen / block_size; 153 crypto_accel_sha3_compress(state, in, block_count, 154 digest_size); 155 in += block_count * block_size; 156 inlen -= block_count * block_size; 157 } 158 159 memcpy(md->sha3.sb + md->sha3.byte_index, in, inlen); 160 md->sha3.byte_index += inlen; 161 162 return CRYPT_OK; 163 } 164 165 static void copy_out_digest(ulong64 *s, unsigned int digest_size, 166 unsigned char *out) 167 { 168 unsigned int n = 0; 169 170 for (n = 0; n < digest_size / sizeof(uint64_t); n++) { 171 put_unaligned_le64(out, s[n]); 172 out += sizeof(uint64_t); 173 } 174 175 if (digest_size % sizeof(uint64_t)) 176 put_unaligned_le32(out, s[n]); 177 } 178 179 int sha3_done(hash_state *md, unsigned char *out) 180 { 181 unsigned int digest_size = 0; 182 unsigned int block_size = 0; 183 void *state = NULL; 184 uint8_t *buf = NULL; 185 186 LTC_ARGCHK(md != NULL); 187 LTC_ARGCHK(out != NULL); 188 189 block_size = 200 - md->sha3.capacity_words * 8; 190 digest_size = md->sha3.capacity_words * 8 / 2; 191 state = md->sha3.s; 192 buf = md->sha3.sb; 193 194 buf[md->sha3.byte_index++] = 0x06; 195 memset(buf + md->sha3.byte_index, 0, block_size - md->sha3.byte_index); 196 buf[block_size - 1] |= 0x80; 197 crypto_accel_sha3_compress(state, buf, 1, digest_size); 198 199 copy_out_digest(state, digest_size, out); 200 201 return CRYPT_OK; 202 } 203 204 205 int sha3_shake_done(hash_state *md, unsigned char *out, unsigned long outlen) 206 { 207 unsigned int digest_size = 0; 208 unsigned int block_size = 0; 209 void *state = NULL; 210 uint8_t *buf = NULL; 211 unsigned int n = 0; 212 213 LTC_ARGCHK(md != NULL); 214 LTC_ARGCHK(out != NULL); 215 216 block_size = 200 - md->sha3.capacity_words * 8; 217 digest_size = md->sha3.capacity_words * 8 / 2; 218 state = md->sha3.s; 219 buf = md->sha3.sb; 220 221 if (!md->sha3.xof_flag) { 222 buf[md->sha3.byte_index++] = 0x1f; 223 memset(buf + md->sha3.byte_index, 0, 224 block_size - md->sha3.byte_index); 225 buf[block_size - 1] |= 0x80; 226 crypto_accel_sha3_compress(state, buf, 1, digest_size); 227 md->sha3.byte_index = 0; 228 copy_out_digest(state, block_size, buf); 229 md->sha3.xof_flag = 1; 230 } 231 232 for (n = 0; n < outlen; n++) { 233 if (md->sha3.byte_index >= block_size) { 234 memset(buf, 0, block_size); 235 crypto_accel_sha3_compress(state, buf, 1, digest_size); 236 md->sha3.byte_index = 0; 237 copy_out_digest(state, block_size, buf); 238 } 239 out[n] = buf[md->sha3.byte_index]; 240 md->sha3.byte_index++; 241 } 242 243 return CRYPT_OK; 244 } 245 #endif 246