aboutsummaryrefslogtreecommitdiff
path: root/libbb/yescrypt/alg-yescrypt-common.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libbb/yescrypt/alg-yescrypt-common.c408
1 files changed, 408 insertions, 0 deletions
diff --git a/libbb/yescrypt/alg-yescrypt-common.c b/libbb/yescrypt/alg-yescrypt-common.c
new file mode 100644
index 000000000..c51823787
--- /dev/null
+++ b/libbb/yescrypt/alg-yescrypt-common.c
@@ -0,0 +1,408 @@
1/*-
2 * Copyright 2013-2018 Alexander Peslyak
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted.
7 *
8 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
9 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
10 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
11 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
12 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
15 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
16 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
17 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
18 * SUCH DAMAGE.
19 */
20
21#if RESTRICTED_PARAMS
22
23#define decode64_uint32(dst, src, min) \
24({ \
25 uint32_t d32 = a2i64(*(src)); \
26 if (d32 > 47) \
27 goto fail; \
28 *(dst) = d32 + (min); \
29 ++src; \
30})
31#define test_decode64_uint32() ((void)0)
32#define FULL_PARAMS(...)
33
34#else
35
36#define FULL_PARAMS(...) __VA_ARGS__
37
38/* Not inlining:
39 * de/encode64 functions are only used to read
40 * yescrypt_params_t field, and convert salt to binary -
41 * both of these are negligible compared to main hashing operation
42 */
43static NOINLINE const uint8_t *decode64_uint32(
44 uint32_t *dst,
45 const uint8_t *src, uint32_t val)
46{
47 uint32_t start = 0, end = 47, bits = 0;
48 uint32_t c;
49
50 if (!src) /* previous decode failed already? */
51 goto fail;
52
53 c = a2i64(*src++);
54 if (c > 63)
55 goto fail;
56
57// The encoding of number N:
58// start = 0 end = 47
59// If N < 48, it is encoded verbatim, else
60// N -= 48
61// start = end+1 = 48
62// end += (64-end)/2 = 55
63// If N < (end+1-start)<<6 = 8<<6, it is encoded as 48+(N>>6)|low6bits (that is, 48...55|<6bit>), else
64// N -= 8<<6
65// start = end+1 = 56
66// end += (64-end)/2 = 59
67// If N < (end+1-start)<<2*6 = 4<<12, it is encoded as 56+(N>>2*6)|low12bits (that is, 56...59|<6bit>|<6bit>), else
68// ...same for 60..61|<6bit>|<6bit>|<6bit>
69// .......same for 62|<6bit>|<6bit>|<6bit>|<6bit>
70// .......same for 63|<6bit>|<6bit>|<6bit>|<6bit>|<6bit>
71 dbg_dec64("c:%d val:0x%08x", (int)c, (unsigned)val);
72 while (c > end) {
73 dbg_dec64("c:%d > end:%d", (int)c, (int)end);
74 val += (end + 1 - start) << bits;
75 dbg_dec64("val+=0x%08x", (int)((end + 1 - start) << bits));
76 dbg_dec64(" val:0x%08x", (unsigned)val);
77 start = end + 1;
78 end += (64 - end) / 2;
79 bits += 6;
80 dbg_dec64("start=%d", (int)start);
81 dbg_dec64("end=%d", (int)end);
82 dbg_dec64("bits=%d", (int)bits);
83 }
84
85 val += (c - start) << bits;
86 dbg_dec64("final val+=0x%08x", (int)((c - start) << bits));
87 dbg_dec64(" val:0x%08x", (unsigned)val);
88
89 while (bits != 0) {
90 c = a2i64(*src++);
91 if (c > 63)
92 goto fail;
93 bits -= 6;
94 val += c << bits;
95 dbg_dec64("low bits val+=0x%08x", (int)(c << bits));
96 dbg_dec64(" val:0x%08x", (unsigned)val);
97 }
98 ret:
99 *dst = val;
100 return src;
101 fail:
102 val = 0;
103 src = NULL;
104 goto ret;
105}
106
107#if TEST_DECODE64
108static void test_decode64_uint32(void)
109{
110 const uint8_t *src, *end;
111 uint32_t u32;
112 int a = 48;
113 int b = 8<<6; // 0x0200
114 int c = 4<<12; // 0x04000
115 int d = 2<<18; // 0x080000
116 int e = 1<<24; // 0x1000000
117
118 src = (void*)"wzzz";
119 end = decode64_uint32(&u32, src, 0);
120 if (u32 != 0x0003ffff+c+b+a) bb_error_msg_and_die("Incorrect decode '%s':0x%08x", src, (unsigned)u32);
121 if (end != src + 4) bb_error_msg_and_die("Incorrect decode '%s': %p end:%p", src, src, end);
122 src = (void*)"xzzz";
123 end = decode64_uint32(&u32, src, 0);
124 if (u32 != 0x0007ffff+c+b+a) bb_error_msg_and_die("Incorrect decode '%s':0x%08x", src, (unsigned)u32);
125 if (end != src + 4) bb_error_msg_and_die("Incorrect decode '%s': %p end:%p", src, src, end);
126 // Note how the last representable "x---" encoding, 0x7ffff, is exactly d-1!
127 // And if we now increment it, we get:
128 src = (void*)"y....";
129 end = decode64_uint32(&u32, src, 0);
130 if (u32 != 0x00000000+d+c+b+a) bb_error_msg_and_die("Incorrect decode '%s':0x%08x", src, (unsigned)u32);
131 if (end != src + 5) bb_error_msg_and_die("Incorrect decode '%s': %p end:%p", src, src, end);
132 src = (void*)"yzzzz";
133 end = decode64_uint32(&u32, src, 0);
134 if (u32 != 0x00ffffff+d+c+b+a) bb_error_msg_and_die("Incorrect decode '%s':0x%08x", src, (unsigned)u32);
135 if (end != src + 5) bb_error_msg_and_die("Incorrect decode '%s': %p end:%p", src, src, end);
136
137 src = (void*)"zzzzzz";
138 end = decode64_uint32(&u32, src, 0);
139 if (u32 != 0x3fffffff+e+d+c+b+a) bb_error_msg_and_die("Incorrect decode '%s':0x%08x", src, (unsigned)u32);
140 if (end != src + 6) bb_error_msg_and_die("Incorrect decode '%s': %p end:%p", src, src, end);
141
142 bb_error_msg("test_decode64_uint32() OK");
143}
144#else
145# define test_decode64_uint32() ((void)0)
146#endif
147
148#endif /* !RESTRICTED_PARAMS */
149
150#if 1
151static const uint8_t *decode64(
152 uint8_t *dst, size_t *dstlen,
153 const uint8_t *src)
154{
155 unsigned dstpos = 0;
156
157 dbg_dec64("src:'%s'", src);
158 for (;;) {
159 uint32_t c, value = 0;
160 int bits = 0;
161 while (*src != '\0' && *src != '$') {
162 c = a2i64(*src);
163 if (c > 63) { /* bad ascii64 char, stop decoding at it */
164 break;
165 }
166 src++;
167 value |= c << bits;
168 bits += 6;
169 if (bits == 24) /* got 4 chars */
170 goto store;
171 }
172 /* we read entire src, or met a non-ascii64 char (such as "$") */
173 if (bits == 0)
174 break;
175 /* else: we got last, partial bit block - store it */
176 store:
177 dbg_dec64(" storing bits:%d dstpos:%u v:%08x", bits, dstpos, (int)SWAP_BE32(value)); //BE to see lsb first
178 for (;;) {
179 if ((*src == '\0' || *src == '$')
180 && value == 0 && bits < 8
181 ) {
182 /* Example: mkpasswd PWD '$y$j9T$123':
183 * the "123" is bits:18 value:03,51,00
184 * is considered to be 2 bytes, not 3!
185 *
186 * '$y$j9T$zzz' in upstream fails outright (3rd byte isn't zero).
187 * IOW: for upstream, validity of salt depends on VALUE,
188 * not just size of salt. Which is a bug.
189 * The '$y$j9T$zzz.' salt is the same
190 * (it adds 6 zero msbits) but upstream works with it,
191 * thus '$y$j9T$zzz' should work too and give the same result.
192 */
193 goto end;
194 }
195 if (dstpos >= *dstlen) {
196 dbg_dec64(" ERR: bits:%d dstpos:%u dst[] is too small", bits, dstpos);
197 goto fail;
198 }
199 *dst++ = value;
200 dstpos++;
201 value >>= 8;
202 bits -= 8;
203 if (bits <= 0) /* can get negative, if we e.g. had 6 bits */
204 break;
205 }
206 if (*src == '\0' || *src == '$')
207 break;
208 }
209 end:
210 *dstlen = dstpos;
211 dbg_dec64("dec64: OK, dst[%d]", (int)dstpos);
212 return src;
213 fail:
214 /* *dstlen = 0; - not needed, caller detects error by seeing NULL */
215 return NULL;
216}
217#else
218/* Buggy (and larger) original code */
219static const uint8_t *decode64(
220 uint8_t *dst, size_t *dstlen,
221 const uint8_t *src, size_t srclen)
222{
223 size_t dstpos = 0;
224
225 while (dstpos <= *dstlen && srclen) {
226 uint32_t value = 0, bits = 0;
227 while (srclen--) {
228 uint32_t c = a2i64(*src);
229 if (c > 63) {
230 srclen = 0;
231 break;
232 }
233 src++;
234 value |= c << bits;
235 bits += 6;
236 if (bits >= 24)
237 break;
238 }
239 if (!bits)
240 break;
241 if (bits < 12) /* must have at least one full byte */
242 goto fail;
243 dbg_dec64(" storing bits:%d v:%08x", (int)bits, (int)SWAP_BE32(value)); //BE to see lsb first
244 while (dstpos++ < *dstlen) {
245 *dst++ = value;
246 value >>= 8;
247 bits -= 8;
248 if (bits < 8) { /* 2 or 4 */
249 if (value) /* must be 0 */
250 goto fail;
251 bits = 0;
252 break;
253 }
254 }
255 if (bits)
256 goto fail;
257 }
258
259 if (!srclen && dstpos <= *dstlen) {
260 *dstlen = dstpos;
261 dbg_dec64("dec64: OK, dst[%d]", (int)dstpos);
262 return src;
263 }
264 fail:
265 /* *dstlen = 0; - not needed, caller detects error by seeing NULL */
266 return NULL;
267}
268#endif
269
270static char *encode64(
271 char *dst, size_t dstlen,
272 const uint8_t *src, size_t srclen)
273{
274 while (srclen) {
275 uint32_t value = 0, b = 0;
276 do {
277 value |= (uint32_t)(*src++ << b);
278 b += 8;
279 srclen--;
280 } while (srclen && b < 24);
281
282 b >>= 3; /* number of bits to number of bytes */
283 b++; /* 1, 2 or 3 bytes will become 2, 3 or 4 ascii64 chars */
284 dstlen -= b;
285 if ((ssize_t)dstlen <= 0)
286 return NULL;
287 dst = num2str64_lsb_first(dst, value, b);
288 }
289 *dst = '\0';
290 return dst;
291}
292
293char *yescrypt_r(
294 const uint8_t *passwd, size_t passwdlen,
295 const uint8_t *setting,
296 char *buf, size_t buflen)
297{
298 struct {
299 yescrypt_ctx_t yctx[1];
300 unsigned char hashbin32[32];
301 } u;
302#define yctx u.yctx
303#define hashbin32 u.hashbin32
304 char *dst;
305 const uint8_t *src, *saltend;
306 size_t need, prefixlen;
307 uint32_t u32;
308
309 test_decode64_uint32();
310
311 memset(yctx, 0, sizeof(yctx));
312 FULL_PARAMS(yctx->param.p = 1;)
313
314 /* we assume setting starts with "$y$" (caller must ensure this) */
315 src = setting + 3;
316
317 src = decode64_uint32(&yctx->param.flags, src, 0);
318 /* "j9T" returns: 0x2f */
319 //if (!src)
320 // goto fail;
321
322 if (yctx->param.flags < YESCRYPT_RW) {
323 dbg("yctx->param.flags=0x%x", (unsigned)yctx->param.flags);
324 goto fail; // bbox: we don't support scrypt - only yescrypt
325 } else if (yctx->param.flags <= YESCRYPT_RW + (YESCRYPT_RW_FLAVOR_MASK >> 2)) {
326 /* "j9T" sets flags to 0xb6 */
327 yctx->param.flags = YESCRYPT_RW + ((yctx->param.flags - YESCRYPT_RW) << 2);
328 dbg("yctx->param.flags=0x%x", (unsigned)yctx->param.flags);
329 dbg(" YESCRYPT_RW:%u", !!(yctx->param.flags & YESCRYPT_RW));
330 dbg((yctx->param.flags & YESCRYPT_RW_FLAVOR_MASK) ==
331 (YESCRYPT_ROUNDS_6 | YESCRYPT_GATHER_4 | YESCRYPT_SIMPLE_2 | YESCRYPT_SBOX_12K)
332 ? " YESCRYPT_ROUNDS_6 | YESCRYPT_GATHER_4 | YESCRYPT_SIMPLE_2 | YESCRYPT_SBOX_12K"
333 : " flags are not standard"
334 );
335 } else {
336 goto fail;
337 }
338
339 src = decode64_uint32(&u32, src, 1);
340 if (/*!src ||*/ u32 > 63)
341 goto fail;
342 yctx->param.N = (uint64_t)1 << u32;
343 /* "j9T" sets to 4096 (1<<12) */
344 dbg("yctx->param.N=%llu (1<<%u)", (unsigned long long)yctx->param.N, (unsigned)u32);
345
346 src = decode64_uint32(&yctx->param.r, src, 1);
347 /* "j9T" sets to 32 */
348 dbg("yctx->param.r=%u", yctx->param.r);
349
350 if (!src)
351 goto fail;
352 if (*src != '$') {
353#if RESTRICTED_PARAMS
354 goto fail;
355#else
356 src = decode64_uint32(&u32, src, 1);
357 dbg("yescrypt has extended params:0x%x", (unsigned)u32);
358 if (u32 & 1)
359 src = decode64_uint32(&yctx->param.p, src, 2);
360 if (u32 & 2)
361 src = decode64_uint32(&yctx->param.t, src, 1);
362 if (u32 & 4)
363 src = decode64_uint32(&yctx->param.g, src, 1);
364 if (u32 & 8) {
365 src = decode64_uint32(&u32, src, 1);
366 if (/*!src ||*/ u32 > 63)
367 goto fail;
368 yctx->param.NROM = (uint64_t)1 << u32;
369 }
370 if (!src)
371 goto fail;
372 if (*src != '$')
373 goto fail;
374#endif
375 }
376
377 yctx->saltlen = sizeof(yctx->salt);
378 src++; /* now points to salt */
379 saltend = decode64(yctx->salt, &yctx->saltlen, src);
380 if (!saltend || (*saltend != '\0' && *saltend != '$'))
381 goto fail; /* salt[] is too small, or bad char during decode */
382 dbg_dec64("salt is %d ascii64 chars -> %d bytes (in binary)", (int)(saltend - src), (int)yctx->saltlen);
383
384 prefixlen = saltend - setting;
385 need = prefixlen + 1 + YESCRYPT_HASH_LEN + 1;
386 if (need > buflen /*overflow is quite unlikely: || need < prefixlen*/)
387 goto fail;
388
389 if (yescrypt_kdf32(yctx, passwd, passwdlen, hashbin32)) {
390 dbg("error in yescrypt_kdf32");
391 goto fail;
392 }
393
394 dst = mempcpy(buf, setting, prefixlen);
395 *dst++ = '$';
396 dst = encode64(dst, buflen - (dst - buf), hashbin32, sizeof(hashbin32));
397 if (!dst)
398 goto fail;
399 ret:
400 free_region(yctx->local);
401 explicit_bzero(&u, sizeof(u));
402 return buf;
403 fail:
404 buf = NULL;
405 goto ret;
406#undef yctx
407#undef hashbin32
408}