comparison libtomcrypt/src/prngs/chacha20.c @ 1471:6dba84798cd5

Update to libtomcrypt 1.18.1, merged with Dropbear changes
author Matt Johnston <matt@ucc.asn.au>
date Fri, 09 Feb 2018 21:44:05 +0800
parents
children
comparison
equal deleted inserted replaced
1470:8bba51a55704 1471:6dba84798cd5
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 /* the idea of re-keying loosely follows the approach used in:
11 * http://bxr.su/OpenBSD/lib/libc/crypt/arc4random.c
12 */
13
14 #include "tomcrypt.h"
15
16 #ifdef LTC_CHACHA20_PRNG
17
18 const struct ltc_prng_descriptor chacha20_prng_desc =
19 {
20 "chacha20",
21 40,
22 &chacha20_prng_start,
23 &chacha20_prng_add_entropy,
24 &chacha20_prng_ready,
25 &chacha20_prng_read,
26 &chacha20_prng_done,
27 &chacha20_prng_export,
28 &chacha20_prng_import,
29 &chacha20_prng_test
30 };
31
32 /**
33 Start the PRNG
34 @param prng The PRNG state to initialize
35 @return CRYPT_OK if successful
36 */
37 int chacha20_prng_start(prng_state *prng)
38 {
39 LTC_ARGCHK(prng != NULL);
40 prng->ready = 0;
41 XMEMSET(&prng->chacha.ent, 0, sizeof(prng->chacha.ent));
42 prng->chacha.idx = 0;
43 LTC_MUTEX_INIT(&prng->lock)
44 return CRYPT_OK;
45 }
46
47 /**
48 Add entropy to the PRNG state
49 @param in The data to add
50 @param inlen Length of the data to add
51 @param prng PRNG state to update
52 @return CRYPT_OK if successful
53 */
54 int chacha20_prng_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng)
55 {
56 unsigned char buf[40];
57 unsigned long i;
58 int err;
59
60 LTC_ARGCHK(prng != NULL);
61 LTC_ARGCHK(in != NULL);
62 LTC_ARGCHK(inlen > 0);
63
64 LTC_MUTEX_LOCK(&prng->lock);
65 if (prng->ready) {
66 /* chacha20_prng_ready() was already called, do "rekey" operation */
67 if ((err = chacha_keystream(&prng->chacha.s, buf, sizeof(buf))) != CRYPT_OK) goto LBL_UNLOCK;
68 for(i = 0; i < inlen; i++) buf[i % sizeof(buf)] ^= in[i];
69 /* key 32 bytes, 20 rounds */
70 if ((err = chacha_setup(&prng->chacha.s, buf, 32, 20)) != CRYPT_OK) goto LBL_UNLOCK;
71 /* iv 8 bytes */
72 if ((err = chacha_ivctr64(&prng->chacha.s, buf + 32, 8, 0)) != CRYPT_OK) goto LBL_UNLOCK;
73 /* clear KEY + IV */
74 zeromem(buf, sizeof(buf));
75 }
76 else {
77 /* chacha20_prng_ready() was not called yet, add entropy to ent buffer */
78 while (inlen--) prng->chacha.ent[prng->chacha.idx++ % sizeof(prng->chacha.ent)] ^= *in++;
79 }
80 err = CRYPT_OK;
81 LBL_UNLOCK:
82 LTC_MUTEX_UNLOCK(&prng->lock);
83 return err;
84 }
85
86 /**
87 Make the PRNG ready to read from
88 @param prng The PRNG to make active
89 @return CRYPT_OK if successful
90 */
91 int chacha20_prng_ready(prng_state *prng)
92 {
93 int err;
94
95 LTC_ARGCHK(prng != NULL);
96
97 LTC_MUTEX_LOCK(&prng->lock);
98 if (prng->ready) { err = CRYPT_OK; goto LBL_UNLOCK; }
99 /* key 32 bytes, 20 rounds */
100 if ((err = chacha_setup(&prng->chacha.s, prng->chacha.ent, 32, 20)) != CRYPT_OK) goto LBL_UNLOCK;
101 /* iv 8 bytes */
102 if ((err = chacha_ivctr64(&prng->chacha.s, prng->chacha.ent + 32, 8, 0)) != CRYPT_OK) goto LBL_UNLOCK;
103 XMEMSET(&prng->chacha.ent, 0, sizeof(prng->chacha.ent));
104 prng->chacha.idx = 0;
105 prng->ready = 1;
106 LBL_UNLOCK:
107 LTC_MUTEX_UNLOCK(&prng->lock);
108 return err;
109 }
110
111 /**
112 Read from the PRNG
113 @param out Destination
114 @param outlen Length of output
115 @param prng The active PRNG to read from
116 @return Number of octets read
117 */
118 unsigned long chacha20_prng_read(unsigned char *out, unsigned long outlen, prng_state *prng)
119 {
120 if (outlen == 0 || prng == NULL || out == NULL) return 0;
121 LTC_MUTEX_LOCK(&prng->lock);
122 if (!prng->ready) { outlen = 0; goto LBL_UNLOCK; }
123 if (chacha_keystream(&prng->chacha.s, out, outlen) != CRYPT_OK) outlen = 0;
124 LBL_UNLOCK:
125 LTC_MUTEX_UNLOCK(&prng->lock);
126 return outlen;
127 }
128
129 /**
130 Terminate the PRNG
131 @param prng The PRNG to terminate
132 @return CRYPT_OK if successful
133 */
134 int chacha20_prng_done(prng_state *prng)
135 {
136 int err;
137 LTC_ARGCHK(prng != NULL);
138 LTC_MUTEX_LOCK(&prng->lock);
139 prng->ready = 0;
140 err = chacha_done(&prng->chacha.s);
141 LTC_MUTEX_UNLOCK(&prng->lock);
142 LTC_MUTEX_DESTROY(&prng->lock);
143 return err;
144 }
145
146 /**
147 Export the PRNG state
148 @param out [out] Destination
149 @param outlen [in/out] Max size and resulting size of the state
150 @param prng The PRNG to export
151 @return CRYPT_OK if successful
152 */
153 int chacha20_prng_export(unsigned char *out, unsigned long *outlen, prng_state *prng)
154 {
155 unsigned long len = chacha20_prng_desc.export_size;
156
157 LTC_ARGCHK(prng != NULL);
158 LTC_ARGCHK(out != NULL);
159 LTC_ARGCHK(outlen != NULL);
160
161 if (*outlen < len) {
162 *outlen = len;
163 return CRYPT_BUFFER_OVERFLOW;
164 }
165
166 if (chacha20_prng_read(out, len, prng) != len) {
167 return CRYPT_ERROR_READPRNG;
168 }
169
170 *outlen = len;
171 return CRYPT_OK;
172 }
173
174 /**
175 Import a PRNG state
176 @param in The PRNG state
177 @param inlen Size of the state
178 @param prng The PRNG to import
179 @return CRYPT_OK if successful
180 */
181 int chacha20_prng_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
182 {
183 int err;
184
185 LTC_ARGCHK(prng != NULL);
186 LTC_ARGCHK(in != NULL);
187 if (inlen < (unsigned long)chacha20_prng_desc.export_size) return CRYPT_INVALID_ARG;
188
189 if ((err = chacha20_prng_start(prng)) != CRYPT_OK) return err;
190 if ((err = chacha20_prng_add_entropy(in, inlen, prng)) != CRYPT_OK) return err;
191 return CRYPT_OK;
192 }
193
194 /**
195 PRNG self-test
196 @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
197 */
198 int chacha20_prng_test(void)
199 {
200 #ifndef LTC_TEST
201 return CRYPT_NOP;
202 #else
203 prng_state st;
204 unsigned char en[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
205 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
206 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
207 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
208 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32 };
209 unsigned char dmp[300];
210 unsigned long dmplen = sizeof(dmp);
211 unsigned char out[500];
212 unsigned char t1[] = { 0x59, 0xB2, 0x26, 0x95, 0x2B, 0x01, 0x8F, 0x05, 0xBE, 0xD8 };
213 unsigned char t2[] = { 0x47, 0xC9, 0x0D, 0x03, 0xE4, 0x75, 0x34, 0x27, 0xBD, 0xDE };
214 unsigned char t3[] = { 0xBC, 0xFA, 0xEF, 0x59, 0x37, 0x7F, 0x1A, 0x91, 0x1A, 0xA6 };
215 int err;
216
217 if ((err = chacha20_prng_start(&st)) != CRYPT_OK) return err;
218 /* add entropy to uninitialized prng */
219 if ((err = chacha20_prng_add_entropy(en, sizeof(en), &st)) != CRYPT_OK) return err;
220 if ((err = chacha20_prng_ready(&st)) != CRYPT_OK) return err;
221 if (chacha20_prng_read(out, 10, &st) != 10) return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */
222 if (compare_testvector(out, 10, t1, sizeof(t1), "CHACHA-PRNG", 1)) return CRYPT_FAIL_TESTVECTOR;
223 if (chacha20_prng_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
224 /* add entropy to already initialized prng */
225 if ((err = chacha20_prng_add_entropy(en, sizeof(en), &st)) != CRYPT_OK) return err;
226 if (chacha20_prng_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
227 if ((err = chacha20_prng_export(dmp, &dmplen, &st)) != CRYPT_OK) return err;
228 if (chacha20_prng_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
229 if (chacha20_prng_read(out, 10, &st) != 10) return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */
230 if (compare_testvector(out, 10, t2, sizeof(t2), "CHACHA-PRNG", 2)) return CRYPT_FAIL_TESTVECTOR;
231 if ((err = chacha20_prng_done(&st)) != CRYPT_OK) return err;
232 if ((err = chacha20_prng_import(dmp, dmplen, &st)) != CRYPT_OK) return err;
233 if ((err = chacha20_prng_ready(&st)) != CRYPT_OK) return err;
234 if (chacha20_prng_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
235 if (chacha20_prng_read(out, 10, &st) != 10) return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */
236 if (compare_testvector(out, 10, t3, sizeof(t3), "CHACHA-PRNG", 3)) return CRYPT_FAIL_TESTVECTOR;
237 if ((err = chacha20_prng_done(&st)) != CRYPT_OK) return err;
238
239 return CRYPT_OK;
240 #endif
241 }
242
243 #endif
244
245 /* ref: $Format:%D$ */
246 /* git commit: $Format:%H$ */
247 /* commit time: $Format:%ai$ */