1 // SPDX-License-Identifier: BSD-2-Clause
2 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
3 *
4 * LibTomCrypt is a library that provides various cryptographic
5 * algorithms in a highly modular and flexible manner.
6 *
7 * The library is free for all purposes without any express
8 * guarantee it works.
9 */
10
11 #include "tomcrypt_private.h"
12
13 /**
14 @file prngs/sober128.c
15 Implementation of SOBER-128 by Tom St Denis.
16 Based on s128fast.c reference code supplied by Greg Rose of QUALCOMM.
17 */
18
19 #ifdef LTC_SOBER128
20
21 const struct ltc_prng_descriptor sober128_desc =
22 {
23 "sober128",
24 40,
25 &sober128_start,
26 &sober128_add_entropy,
27 &sober128_ready,
28 &sober128_read,
29 &sober128_done,
30 &sober128_export,
31 &sober128_import,
32 &sober128_test
33 };
34
35 /**
36 Start the PRNG
37 @param prng [out] The PRNG state to initialize
38 @return CRYPT_OK if successful
39 */
sober128_start(prng_state * prng)40 int sober128_start(prng_state *prng)
41 {
42 LTC_ARGCHK(prng != NULL);
43 prng->ready = 0;
44 XMEMSET(&prng->u.sober128.ent, 0, sizeof(prng->u.sober128.ent));
45 prng->u.sober128.idx = 0;
46 LTC_MUTEX_INIT(&prng->lock)
47 return CRYPT_OK;
48 }
49
50 /**
51 Add entropy to the PRNG state
52 @param in The data to add
53 @param inlen Length of the data to add
54 @param prng PRNG state to update
55 @return CRYPT_OK if successful
56 */
sober128_add_entropy(const unsigned char * in,unsigned long inlen,prng_state * prng)57 int sober128_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng)
58 {
59 unsigned char buf[40];
60 unsigned long i;
61 int err;
62
63 LTC_ARGCHK(prng != NULL);
64 LTC_ARGCHK(in != NULL);
65 LTC_ARGCHK(inlen > 0);
66
67 LTC_MUTEX_LOCK(&prng->lock);
68 if (prng->ready) {
69 /* sober128_ready() was already called, do "rekey" operation */
70 if ((err = sober128_stream_keystream(&prng->u.sober128.s, buf, sizeof(buf))) != CRYPT_OK) goto LBL_UNLOCK;
71 for(i = 0; i < inlen; i++) buf[i % sizeof(buf)] ^= in[i];
72 /* key 32 bytes, 20 rounds */
73 if ((err = sober128_stream_setup(&prng->u.sober128.s, buf, 32)) != CRYPT_OK) goto LBL_UNLOCK;
74 /* iv 8 bytes */
75 if ((err = sober128_stream_setiv(&prng->u.sober128.s, buf + 32, 8)) != CRYPT_OK) goto LBL_UNLOCK;
76 /* clear KEY + IV */
77 zeromem(buf, sizeof(buf));
78 }
79 else {
80 /* sober128_ready() was not called yet, add entropy to ent buffer */
81 while (inlen--) prng->u.sober128.ent[prng->u.sober128.idx++ % sizeof(prng->u.sober128.ent)] ^= *in++;
82 }
83 err = CRYPT_OK;
84 LBL_UNLOCK:
85 LTC_MUTEX_UNLOCK(&prng->lock);
86 return err;
87 }
88
89 /**
90 Make the PRNG ready to read from
91 @param prng The PRNG to make active
92 @return CRYPT_OK if successful
93 */
sober128_ready(prng_state * prng)94 int sober128_ready(prng_state *prng)
95 {
96 int err;
97
98 LTC_ARGCHK(prng != NULL);
99
100 LTC_MUTEX_LOCK(&prng->lock);
101 if (prng->ready) { err = CRYPT_OK; goto LBL_UNLOCK; }
102 /* key 32 bytes, 20 rounds */
103 if ((err = sober128_stream_setup(&prng->u.sober128.s, prng->u.sober128.ent, 32)) != CRYPT_OK) goto LBL_UNLOCK;
104 /* iv 8 bytes */
105 if ((err = sober128_stream_setiv(&prng->u.sober128.s, prng->u.sober128.ent + 32, 8)) != CRYPT_OK) goto LBL_UNLOCK;
106 XMEMSET(&prng->u.sober128.ent, 0, sizeof(prng->u.sober128.ent));
107 prng->u.sober128.idx = 0;
108 prng->ready = 1;
109 LBL_UNLOCK:
110 LTC_MUTEX_UNLOCK(&prng->lock);
111 return err;
112 }
113
114 /**
115 Read from the PRNG
116 @param out Destination
117 @param outlen Length of output
118 @param prng The active PRNG to read from
119 @return Number of octets read
120 */
sober128_read(unsigned char * out,unsigned long outlen,prng_state * prng)121 unsigned long sober128_read(unsigned char *out, unsigned long outlen, prng_state *prng)
122 {
123 if (outlen == 0 || prng == NULL || out == NULL) return 0;
124 LTC_MUTEX_LOCK(&prng->lock);
125 if (!prng->ready) { outlen = 0; goto LBL_UNLOCK; }
126 if (sober128_stream_keystream(&prng->u.sober128.s, out, outlen) != CRYPT_OK) outlen = 0;
127 LBL_UNLOCK:
128 LTC_MUTEX_UNLOCK(&prng->lock);
129 return outlen;
130 }
131
132 /**
133 Terminate the PRNG
134 @param prng The PRNG to terminate
135 @return CRYPT_OK if successful
136 */
sober128_done(prng_state * prng)137 int sober128_done(prng_state *prng)
138 {
139 int err;
140 LTC_ARGCHK(prng != NULL);
141 LTC_MUTEX_LOCK(&prng->lock);
142 prng->ready = 0;
143 err = sober128_stream_done(&prng->u.sober128.s);
144 LTC_MUTEX_UNLOCK(&prng->lock);
145 LTC_MUTEX_DESTROY(&prng->lock);
146 return err;
147 }
148
149 /**
150 Export the PRNG state
151 @param out [out] Destination
152 @param outlen [in/out] Max size and resulting size of the state
153 @param prng The PRNG to export
154 @return CRYPT_OK if successful
155 */
_LTC_PRNG_EXPORT(sober128)156 _LTC_PRNG_EXPORT(sober128)
157
158 /**
159 Import a PRNG state
160 @param in The PRNG state
161 @param inlen Size of the state
162 @param prng The PRNG to import
163 @return CRYPT_OK if successful
164 */
165 int sober128_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
166 {
167 int err;
168
169 LTC_ARGCHK(prng != NULL);
170 LTC_ARGCHK(in != NULL);
171 if (inlen < (unsigned long)sober128_desc.export_size) return CRYPT_INVALID_ARG;
172
173 if ((err = sober128_start(prng)) != CRYPT_OK) return err;
174 if ((err = sober128_add_entropy(in, inlen, prng)) != CRYPT_OK) return err;
175 return CRYPT_OK;
176 }
177
178 /**
179 PRNG self-test
180 @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
181 */
sober128_test(void)182 int sober128_test(void)
183 {
184 #ifndef LTC_TEST
185 return CRYPT_NOP;
186 #else
187 prng_state st;
188 unsigned char en[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
189 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
190 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
191 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
192 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32 };
193 unsigned char dmp[300];
194 unsigned long dmplen = sizeof(dmp);
195 unsigned char out[500];
196 unsigned char t1[] = { 0x31, 0x82, 0xA7, 0xA5, 0x8B, 0xD7, 0xCB, 0x39, 0x86, 0x1A };
197 unsigned char t2[] = { 0x6B, 0x43, 0x9E, 0xBC, 0xE7, 0x62, 0x9B, 0xE6, 0x9B, 0x83 };
198 unsigned char t3[] = { 0x4A, 0x0E, 0x6C, 0xC1, 0xCF, 0xB4, 0x73, 0x49, 0x99, 0x05 };
199 int err;
200
201 if ((err = sober128_start(&st)) != CRYPT_OK) return err;
202 /* add entropy to uninitialized prng */
203 if ((err = sober128_add_entropy(en, sizeof(en), &st)) != CRYPT_OK) return err;
204 if ((err = sober128_ready(&st)) != CRYPT_OK) return err;
205 if (sober128_read(out, 10, &st) != 10) return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */
206 if (compare_testvector(out, 10, t1, sizeof(t1), "SOBER128-PRNG", 1)) return CRYPT_FAIL_TESTVECTOR;
207 if (sober128_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
208 /* add entropy to already initialized prng */
209 if ((err = sober128_add_entropy(en, sizeof(en), &st)) != CRYPT_OK) return err;
210 if (sober128_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
211 if ((err = sober128_export(dmp, &dmplen, &st)) != CRYPT_OK) return err;
212 if (sober128_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
213 if (sober128_read(out, 10, &st) != 10) return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */
214 if (compare_testvector(out, 10, t2, sizeof(t2), "SOBER128-PRNG", 2)) return CRYPT_FAIL_TESTVECTOR;
215 if ((err = sober128_done(&st)) != CRYPT_OK) return err;
216 if ((err = sober128_import(dmp, dmplen, &st)) != CRYPT_OK) return err;
217 if ((err = sober128_ready(&st)) != CRYPT_OK) return err;
218 if (sober128_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
219 if (sober128_read(out, 10, &st) != 10) return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */
220 if (compare_testvector(out, 10, t3, sizeof(t3), "SOBER128-PRNG", 3)) return CRYPT_FAIL_TESTVECTOR;
221 if ((err = sober128_done(&st)) != CRYPT_OK) return err;
222
223 return CRYPT_OK;
224 #endif
225 }
226
227 #endif
228
229 /* ref: $Format:%D$ */
230 /* git commit: $Format:%H$ */
231 /* commit time: $Format:%ai$ */
232