1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
3 * LibTomCrypt is a library that provides various cryptographic
4 * algorithms in a highly modular and flexible manner.
6 * The library is free for all purposes without any express
13 @file prngs/sober128.c
14 Implementation of SOBER-128 by Tom St Denis.
15 Based on s128fast.c reference code supplied by Greg Rose of QUALCOMM.
20 const struct ltc_prng_descriptor sober128_desc =
25 &sober128_add_entropy,
36 @param prng [out] The PRNG state to initialize
37 @return CRYPT_OK if successful
39 int sober128_start(prng_state *prng)
41 LTC_ARGCHK(prng != NULL);
43 XMEMSET(&prng->sober128.ent, 0, sizeof(prng->sober128.ent));
44 prng->sober128.idx = 0;
45 LTC_MUTEX_INIT(&prng->lock)
50 Add entropy to the PRNG state
51 @param in The data to add
52 @param inlen Length of the data to add
53 @param prng PRNG state to update
54 @return CRYPT_OK if successful
56 int sober128_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng)
58 unsigned char buf[40];
62 LTC_ARGCHK(prng != NULL);
63 LTC_ARGCHK(in != NULL);
64 LTC_ARGCHK(inlen > 0);
66 LTC_MUTEX_LOCK(&prng->lock);
68 /* sober128_ready() was already called, do "rekey" operation */
69 if ((err = sober128_stream_keystream(&prng->sober128.s, buf, sizeof(buf))) != CRYPT_OK) goto LBL_UNLOCK;
70 for(i = 0; i < inlen; i++) buf[i % sizeof(buf)] ^= in[i];
71 /* key 32 bytes, 20 rounds */
72 if ((err = sober128_stream_setup(&prng->sober128.s, buf, 32)) != CRYPT_OK) goto LBL_UNLOCK;
74 if ((err = sober128_stream_setiv(&prng->sober128.s, buf + 32, 8)) != CRYPT_OK) goto LBL_UNLOCK;
76 zeromem(buf, sizeof(buf));
79 /* sober128_ready() was not called yet, add entropy to ent buffer */
80 while (inlen--) prng->sober128.ent[prng->sober128.idx++ % sizeof(prng->sober128.ent)] ^= *in++;
84 LTC_MUTEX_UNLOCK(&prng->lock);
89 Make the PRNG ready to read from
90 @param prng The PRNG to make active
91 @return CRYPT_OK if successful
93 int sober128_ready(prng_state *prng)
97 LTC_ARGCHK(prng != NULL);
99 LTC_MUTEX_LOCK(&prng->lock);
100 if (prng->ready) { err = CRYPT_OK; goto LBL_UNLOCK; }
101 /* key 32 bytes, 20 rounds */
102 if ((err = sober128_stream_setup(&prng->sober128.s, prng->sober128.ent, 32)) != CRYPT_OK) goto LBL_UNLOCK;
104 if ((err = sober128_stream_setiv(&prng->sober128.s, prng->sober128.ent + 32, 8)) != CRYPT_OK) goto LBL_UNLOCK;
105 XMEMSET(&prng->sober128.ent, 0, sizeof(prng->sober128.ent));
106 prng->sober128.idx = 0;
109 LTC_MUTEX_UNLOCK(&prng->lock);
115 @param out Destination
116 @param outlen Length of output
117 @param prng The active PRNG to read from
118 @return Number of octets read
120 unsigned long sober128_read(unsigned char *out, unsigned long outlen, prng_state *prng)
122 if (outlen == 0 || prng == NULL || out == NULL) return 0;
123 LTC_MUTEX_LOCK(&prng->lock);
124 if (!prng->ready) { outlen = 0; goto LBL_UNLOCK; }
125 if (sober128_stream_keystream(&prng->sober128.s, out, outlen) != CRYPT_OK) outlen = 0;
127 LTC_MUTEX_UNLOCK(&prng->lock);
133 @param prng The PRNG to terminate
134 @return CRYPT_OK if successful
136 int sober128_done(prng_state *prng)
139 LTC_ARGCHK(prng != NULL);
140 LTC_MUTEX_LOCK(&prng->lock);
142 err = sober128_stream_done(&prng->sober128.s);
143 LTC_MUTEX_UNLOCK(&prng->lock);
144 LTC_MUTEX_DESTROY(&prng->lock);
149 Export the PRNG state
150 @param out [out] Destination
151 @param outlen [in/out] Max size and resulting size of the state
152 @param prng The PRNG to export
153 @return CRYPT_OK if successful
155 int sober128_export(unsigned char *out, unsigned long *outlen, prng_state *prng)
157 unsigned long len = sober128_desc.export_size;
159 LTC_ARGCHK(prng != NULL);
160 LTC_ARGCHK(out != NULL);
161 LTC_ARGCHK(outlen != NULL);
165 return CRYPT_BUFFER_OVERFLOW;
168 if (sober128_read(out, len, prng) != len) {
169 return CRYPT_ERROR_READPRNG;
178 @param in The PRNG state
179 @param inlen Size of the state
180 @param prng The PRNG to import
181 @return CRYPT_OK if successful
183 int sober128_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
187 LTC_ARGCHK(prng != NULL);
188 LTC_ARGCHK(in != NULL);
189 if (inlen < (unsigned long)sober128_desc.export_size) return CRYPT_INVALID_ARG;
191 if ((err = sober128_start(prng)) != CRYPT_OK) return err;
192 if ((err = sober128_add_entropy(in, inlen, prng)) != CRYPT_OK) return err;
198 @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
200 int sober128_test(void)
206 unsigned char en[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
207 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
208 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
209 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
210 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32 };
211 unsigned char dmp[300];
212 unsigned long dmplen = sizeof(dmp);
213 unsigned char out[500];
214 unsigned char t1[] = { 0x31, 0x82, 0xA7, 0xA5, 0x8B, 0xD7, 0xCB, 0x39, 0x86, 0x1A };
215 unsigned char t2[] = { 0x6B, 0x43, 0x9E, 0xBC, 0xE7, 0x62, 0x9B, 0xE6, 0x9B, 0x83 };
216 unsigned char t3[] = { 0x4A, 0x0E, 0x6C, 0xC1, 0xCF, 0xB4, 0x73, 0x49, 0x99, 0x05 };
219 if ((err = sober128_start(&st)) != CRYPT_OK) return err;
220 /* add entropy to uninitialized prng */
221 if ((err = sober128_add_entropy(en, sizeof(en), &st)) != CRYPT_OK) return err;
222 if ((err = sober128_ready(&st)) != CRYPT_OK) return err;
223 if (sober128_read(out, 10, &st) != 10) return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */
224 if (compare_testvector(out, 10, t1, sizeof(t1), "SOBER128-PRNG", 1)) return CRYPT_FAIL_TESTVECTOR;
225 if (sober128_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
226 /* add entropy to already initialized prng */
227 if ((err = sober128_add_entropy(en, sizeof(en), &st)) != CRYPT_OK) return err;
228 if (sober128_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
229 if ((err = sober128_export(dmp, &dmplen, &st)) != CRYPT_OK) return err;
230 if (sober128_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
231 if (sober128_read(out, 10, &st) != 10) return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */
232 if (compare_testvector(out, 10, t2, sizeof(t2), "SOBER128-PRNG", 2)) return CRYPT_FAIL_TESTVECTOR;
233 if ((err = sober128_done(&st)) != CRYPT_OK) return err;
234 if ((err = sober128_import(dmp, dmplen, &st)) != CRYPT_OK) return err;
235 if ((err = sober128_ready(&st)) != CRYPT_OK) return err;
236 if (sober128_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
237 if (sober128_read(out, 10, &st) != 10) return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */
238 if (compare_testvector(out, 10, t3, sizeof(t3), "SOBER128-PRNG", 3)) return CRYPT_FAIL_TESTVECTOR;
239 if ((err = sober128_done(&st)) != CRYPT_OK) return err;
247 /* ref: $Format:%D$ */
248 /* git commit: $Format:%H$ */
249 /* commit time: $Format:%ai$ */