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