1 /*-
2  * Copyright 2009 Colin Percival
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * This file was originally written by Colin Percival as part of the Tarsnap
27  * online backup system.
28  */
29 #include "bsdtar_platform.h"
30 
31 #include <sys/types.h>
32 #include <sys/mman.h>
33 
34 #include <errno.h>
35 #include <stdint.h>
36 #include <stdlib.h>
37 #include <string.h>
38 
39 #include "cpusupport.h"
40 #include "sha256.h"
41 #include "warnp.h"
42 
43 #include "crypto_scrypt_smix.h"
44 #include "crypto_scrypt_smix_sse2.h"
45 
46 #include "crypto_scrypt.h"
47 
48 static void (*smix_func)(uint8_t *, size_t, uint64_t, void *, void *) = NULL;
49 
50 /**
51  * _crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen, smix):
52  * Perform the requested scrypt computation, using ${smix} as the smix routine.
53  */
54 static int
_crypto_scrypt(const uint8_t * passwd,size_t passwdlen,const uint8_t * salt,size_t saltlen,uint64_t N,uint32_t _r,uint32_t _p,uint8_t * buf,size_t buflen,void (* smix)(uint8_t *,size_t,uint64_t,void *,void *))55 _crypto_scrypt(const uint8_t * passwd, size_t passwdlen,
56     const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t _r, uint32_t _p,
57     uint8_t * buf, size_t buflen,
58     void (*smix)(uint8_t *, size_t, uint64_t, void *, void *))
59 {
60 	void * B0, * V0, * XY0;
61 	uint8_t * B;
62 	uint32_t * V;
63 	uint32_t * XY;
64 	size_t r = _r, p = _p;
65 	uint32_t i;
66 
67 	/* Sanity-check parameters. */
68 #if SIZE_MAX > UINT32_MAX
69 	if (buflen > (((uint64_t)(1) << 32) - 1) * 32) {
70 		errno = EFBIG;
71 		goto err0;
72 	}
73 #endif
74 	if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) {
75 		errno = EFBIG;
76 		goto err0;
77 	}
78 	if (((N & (N - 1)) != 0) || (N < 2)) {
79 		errno = EINVAL;
80 		goto err0;
81 	}
82 	if ((r > SIZE_MAX / 128 / p) ||
83 #if SIZE_MAX / 256 <= UINT32_MAX
84 	    (r > (SIZE_MAX - 64) / 256) ||
85 #endif
86 	    (N > SIZE_MAX / 128 / r)) {
87 		errno = ENOMEM;
88 		goto err0;
89 	}
90 
91 	/* Allocate memory. */
92 #ifdef HAVE_POSIX_MEMALIGN
93 	if ((errno = posix_memalign(&B0, 64, 128 * r * p)) != 0)
94 		goto err0;
95 	B = (uint8_t *)(B0);
96 	if ((errno = posix_memalign(&XY0, 64, 256 * r + 64)) != 0)
97 		goto err1;
98 	XY = (uint32_t *)(XY0);
99 #if !defined(MAP_ANON) || !defined(HAVE_MMAP)
100 	if ((errno = posix_memalign(&V0, 64, (size_t)(128 * r * N))) != 0)
101 		goto err2;
102 	V = (uint32_t *)(V0);
103 #endif
104 #else
105 	if ((B0 = malloc(128 * r * p + 63)) == NULL)
106 		goto err0;
107 	B = (uint8_t *)(((uintptr_t)(B0) + 63) & ~ (uintptr_t)(63));
108 	if ((XY0 = malloc(256 * r + 64 + 63)) == NULL)
109 		goto err1;
110 	XY = (uint32_t *)(((uintptr_t)(XY0) + 63) & ~ (uintptr_t)(63));
111 #if !defined(MAP_ANON) || !defined(HAVE_MMAP)
112 	if ((V0 = malloc(128 * r * N + 63)) == NULL)
113 		goto err2;
114 	V = (uint32_t *)(((uintptr_t)(V0) + 63) & ~ (uintptr_t)(63));
115 #endif
116 #endif
117 #if defined(MAP_ANON) && defined(HAVE_MMAP)
118 	if ((V0 = mmap(NULL, (size_t)(128 * r * N), PROT_READ | PROT_WRITE,
119 #ifdef MAP_NOCORE
120 	    MAP_ANON | MAP_PRIVATE | MAP_NOCORE,
121 #else
122 	    MAP_ANON | MAP_PRIVATE,
123 #endif
124 	    -1, 0)) == MAP_FAILED)
125 		goto err2;
126 	V = (uint32_t *)(V0);
127 #endif
128 
129 	/* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */
130 	PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r);
131 
132 	/* 2: for i = 0 to p - 1 do */
133 	for (i = 0; i < p; i++) {
134 		/* 3: B_i <-- MF(B_i, N) */
135 		(smix)(&B[i * 128 * r], r, N, V, XY);
136 	}
137 
138 	/* 5: DK <-- PBKDF2(P, B, 1, dkLen) */
139 	PBKDF2_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen);
140 
141 	/* Free memory. */
142 #if defined(MAP_ANON) && defined(HAVE_MMAP)
143 	if (munmap(V0, (size_t)(128 * r * N)))
144 		goto err2;
145 #else
146 	free(V0);
147 #endif
148 	free(XY0);
149 	free(B0);
150 
151 	/* Success! */
152 	return (0);
153 
154 err2:
155 	free(XY0);
156 err1:
157 	free(B0);
158 err0:
159 	/* Failure! */
160 	return (-1);
161 }
162 
163 #define TESTLEN 64
164 static struct scrypt_test {
165 	const char * passwd;
166 	const char * salt;
167 	uint64_t N;
168 	uint32_t r;
169 	uint32_t p;
170 	uint8_t result[TESTLEN];
171 } testcase = {
172 	.passwd = "pleaseletmein",
173 	.salt = "SodiumChloride",
174 	.N = 16,
175 	.r = 8,
176 	.p = 1,
177 	.result = {
178 		0x25, 0xa9, 0xfa, 0x20, 0x7f, 0x87, 0xca, 0x09,
179 		0xa4, 0xef, 0x8b, 0x9f, 0x77, 0x7a, 0xca, 0x16,
180 		0xbe, 0xb7, 0x84, 0xae, 0x18, 0x30, 0xbf, 0xbf,
181 		0xd3, 0x83, 0x25, 0xaa, 0xbb, 0x93, 0x77, 0xdf,
182 		0x1b, 0xa7, 0x84, 0xd7, 0x46, 0xea, 0x27, 0x3b,
183 		0xf5, 0x16, 0xa4, 0x6f, 0xbf, 0xac, 0xf5, 0x11,
184 		0xc5, 0xbe, 0xba, 0x4c, 0x4a, 0xb3, 0xac, 0xc7,
185 		0xfa, 0x6f, 0x46, 0x0b, 0x6c, 0x0f, 0x47, 0x7b,
186 	}
187 };
188 
189 static int
testsmix(void (* smix)(uint8_t *,size_t,uint64_t,void *,void *))190 testsmix(void (*smix)(uint8_t *, size_t, uint64_t, void *, void *))
191 {
192 	uint8_t hbuf[TESTLEN];
193 
194 	/* Perform the computation. */
195 	if (_crypto_scrypt(
196 	    (const uint8_t *)testcase.passwd, strlen(testcase.passwd),
197 	    (const uint8_t *)testcase.salt, strlen(testcase.salt),
198 	    testcase.N, testcase.r, testcase.p, hbuf, TESTLEN, smix))
199 		return (-1);
200 
201 	/* Does it match? */
202 	return (memcmp(testcase.result, hbuf, TESTLEN));
203 }
204 
205 static void
selectsmix(void)206 selectsmix(void)
207 {
208 
209 #ifdef CPUSUPPORT_X86_SSE2
210 	/* If we're running on an SSE2-capable CPU, try that code. */
211 	if (cpusupport_x86_sse2()) {
212 		/* If SSE2ized smix works, use it. */
213 		if (!testsmix(crypto_scrypt_smix_sse2)) {
214 			smix_func = crypto_scrypt_smix_sse2;
215 			return;
216 		}
217 		warn0("Disabling broken SSE2 scrypt support - please report bug!");
218 	}
219 #endif
220 
221 	/* If generic smix works, use it. */
222 	if (!testsmix(crypto_scrypt_smix)) {
223 		smix_func = crypto_scrypt_smix;
224 		return;
225 	}
226 	warn0("Generic scrypt code is broken - please report bug!");
227 
228 	/* If we get here, something really bad happened. */
229 	abort();
230 }
231 
232 /**
233  * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen):
234  * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r,
235  * p, buflen) and write the result into buf.  The parameters r, p, and buflen
236  * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32.  The parameter N
237  * must be a power of 2 greater than 1.
238  *
239  * Return 0 on success; or -1 on error.
240  */
241 int
crypto_scrypt(const uint8_t * passwd,size_t passwdlen,const uint8_t * salt,size_t saltlen,uint64_t N,uint32_t _r,uint32_t _p,uint8_t * buf,size_t buflen)242 crypto_scrypt(const uint8_t * passwd, size_t passwdlen,
243     const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t _r, uint32_t _p,
244     uint8_t * buf, size_t buflen)
245 {
246 
247 	if (smix_func == NULL)
248 		selectsmix();
249 
250 	return (_crypto_scrypt(passwd, passwdlen, salt, saltlen, N, _r, _p,
251 	    buf, buflen, smix_func));
252 }
253