Initial commit
[authen-passphrase-scrypt.git] / scrypt-1.2.1 / lib / crypto / crypto_scrypt.c
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 }
This page took 0.028509 seconds and 4 git commands to generate.