| 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 | } |