]> pd.if.org Git - zpackage/blob - libtomcrypt/src/prngs/sober128.c
remove md2 md4 md5 hashes
[zpackage] / libtomcrypt / src / prngs / sober128.c
1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
2  *
3  * LibTomCrypt is a library that provides various cryptographic
4  * algorithms in a highly modular and flexible manner.
5  *
6  * The library is free for all purposes without any express
7  * guarantee it works.
8  */
9
10 #include "tomcrypt.h"
11
12 /**
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.
16 */
17
18 #ifdef LTC_SOBER128
19
20 const struct ltc_prng_descriptor sober128_desc =
21 {
22    "sober128",
23    40,
24    &sober128_start,
25    &sober128_add_entropy,
26    &sober128_ready,
27    &sober128_read,
28    &sober128_done,
29    &sober128_export,
30    &sober128_import,
31    &sober128_test
32 };
33
34 /**
35   Start the PRNG
36   @param prng     [out] The PRNG state to initialize
37   @return CRYPT_OK if successful
38 */
39 int sober128_start(prng_state *prng)
40 {
41    LTC_ARGCHK(prng != NULL);
42    prng->ready = 0;
43    XMEMSET(&prng->sober128.ent, 0, sizeof(prng->sober128.ent));
44    prng->sober128.idx = 0;
45    LTC_MUTEX_INIT(&prng->lock)
46    return CRYPT_OK;
47 }
48
49 /**
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
55 */
56 int sober128_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng)
57 {
58    unsigned char buf[40];
59    unsigned long i;
60    int err;
61
62    LTC_ARGCHK(prng != NULL);
63    LTC_ARGCHK(in != NULL);
64    LTC_ARGCHK(inlen > 0);
65
66    LTC_MUTEX_LOCK(&prng->lock);
67    if (prng->ready) {
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;
73       /* iv 8 bytes */
74       if ((err = sober128_stream_setiv(&prng->sober128.s, buf + 32, 8)) != CRYPT_OK) goto LBL_UNLOCK;
75       /* clear KEY + IV */
76       zeromem(buf, sizeof(buf));
77    }
78    else {
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++;
81    }
82    err = CRYPT_OK;
83 LBL_UNLOCK:
84    LTC_MUTEX_UNLOCK(&prng->lock);
85    return err;
86 }
87
88 /**
89   Make the PRNG ready to read from
90   @param prng   The PRNG to make active
91   @return CRYPT_OK if successful
92 */
93 int sober128_ready(prng_state *prng)
94 {
95    int err;
96
97    LTC_ARGCHK(prng != NULL);
98
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;
103    /* iv 8 bytes */
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;
107    prng->ready = 1;
108 LBL_UNLOCK:
109    LTC_MUTEX_UNLOCK(&prng->lock);
110    return err;
111 }
112
113 /**
114   Read from the PRNG
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
119 */
120 unsigned long sober128_read(unsigned char *out, unsigned long outlen, prng_state *prng)
121 {
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;
126 LBL_UNLOCK:
127    LTC_MUTEX_UNLOCK(&prng->lock);
128    return outlen;
129 }
130
131 /**
132   Terminate the PRNG
133   @param prng   The PRNG to terminate
134   @return CRYPT_OK if successful
135 */
136 int sober128_done(prng_state *prng)
137 {
138    int err;
139    LTC_ARGCHK(prng != NULL);
140    LTC_MUTEX_LOCK(&prng->lock);
141    prng->ready = 0;
142    err = sober128_stream_done(&prng->sober128.s);
143    LTC_MUTEX_UNLOCK(&prng->lock);
144    LTC_MUTEX_DESTROY(&prng->lock);
145    return err;
146 }
147
148 /**
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
154 */
155 int sober128_export(unsigned char *out, unsigned long *outlen, prng_state *prng)
156 {
157    unsigned long len = sober128_desc.export_size;
158
159    LTC_ARGCHK(prng   != NULL);
160    LTC_ARGCHK(out    != NULL);
161    LTC_ARGCHK(outlen != NULL);
162
163    if (*outlen < len) {
164       *outlen = len;
165       return CRYPT_BUFFER_OVERFLOW;
166    }
167
168    if (sober128_read(out, len, prng) != len) {
169       return CRYPT_ERROR_READPRNG;
170    }
171
172    *outlen = len;
173    return CRYPT_OK;
174 }
175
176 /**
177   Import a PRNG state
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
182 */
183 int sober128_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
184 {
185    int err;
186
187    LTC_ARGCHK(prng != NULL);
188    LTC_ARGCHK(in   != NULL);
189    if (inlen < (unsigned long)sober128_desc.export_size) return CRYPT_INVALID_ARG;
190
191    if ((err = sober128_start(prng)) != CRYPT_OK) return err;
192    if ((err = sober128_add_entropy(in, inlen, prng)) != CRYPT_OK) return err;
193    return CRYPT_OK;
194 }
195
196 /**
197   PRNG self-test
198   @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
199 */
200 int sober128_test(void)
201 {
202 #ifndef LTC_TEST
203    return CRYPT_NOP;
204 #else
205    prng_state st;
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 };
217    int err;
218
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;
240
241    return CRYPT_OK;
242 #endif
243 }
244
245 #endif
246
247 /* ref:         $Format:%D$ */
248 /* git commit:  $Format:%H$ */
249 /* commit time: $Format:%ai$ */