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
sha3_224_init(hash_state * md)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
sha3_256_init(hash_state * md)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
sha3_384_init(hash_state * md)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
sha3_512_init(hash_state * md)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
sha3_shake_init(hash_state * md,int num)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
sha3_process(hash_state * md,const unsigned char * in,unsigned long inlen)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
copy_out_digest(ulong64 * s,unsigned int digest_size,unsigned char * out)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
sha3_done(hash_state * md,unsigned char * out)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
sha3_shake_done(hash_state * md,unsigned char * out,unsigned long outlen)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