]>
Commit | Line | Data |
---|---|---|
0c1f3509 MG |
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 "scrypt_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 | |
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, 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, 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 | |
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 | |
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 | |
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 | } |