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