summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Kendrick (fatigue) <rjek@rjek.com>2013-07-30 13:20:59 +0100
committerRob Kendrick (fatigue) <rjek@rjek.com>2013-07-30 13:20:59 +0100
commitd1dd923d50995a472f41f1a958f7665598fd8941 (patch)
tree85b72aef933c29f01b8c9c1f1998da7c148b80f7
downloadlua-scrypt-d1dd923d50995a472f41f1a958f7665598fd8941.tar.gz
Import upstream scrypt implementation
-rw-r--r--lib/README6
-rw-r--r--lib/crypto/crypto_aesctr.c124
-rw-r--r--lib/crypto/crypto_aesctr.h59
-rw-r--r--lib/crypto/crypto_scrypt-nosse.c338
-rw-r--r--lib/crypto/crypto_scrypt-ref.c284
-rw-r--r--lib/crypto/crypto_scrypt-sse.c366
-rw-r--r--lib/crypto/crypto_scrypt.h46
-rw-r--r--lib/crypto/sha256.c412
-rw-r--r--lib/crypto/sha256.h62
-rw-r--r--lib/scryptenc/scryptenc.c606
-rw-r--r--lib/scryptenc/scryptenc.h112
-rw-r--r--lib/scryptenc/scryptenc_cpuperf.c185
-rw-r--r--lib/scryptenc/scryptenc_cpuperf.h39
-rw-r--r--lib/util/memlimit.c302
-rw-r--r--lib/util/memlimit.h42
-rw-r--r--lib/util/readpass.c143
-rw-r--r--lib/util/readpass.h45
-rw-r--r--lib/util/sysendian.h140
-rw-r--r--lib/util/warn.c75
-rw-r--r--lib/util/warn.h13
20 files changed, 3399 insertions, 0 deletions
diff --git a/lib/README b/lib/README
new file mode 100644
index 0000000..3bb211e
--- /dev/null
+++ b/lib/README
@@ -0,0 +1,6 @@
+The source code under this directory is taken from the client for the
+Tarsnap online backup system (and released under the 2-clause BSD license
+with permission of the author); keeping this code in sync with the Tarsnap
+code is highly desirable and explains why there is some functionality
+included here which is not actually used by the scrypt file encryption
+utility.
diff --git a/lib/crypto/crypto_aesctr.c b/lib/crypto/crypto_aesctr.c
new file mode 100644
index 0000000..00db8f0
--- /dev/null
+++ b/lib/crypto/crypto_aesctr.c
@@ -0,0 +1,124 @@
+/*-
+ * Copyright 2007-2009 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file was originally written by Colin Percival as part of the Tarsnap
+ * online backup system.
+ */
+#include "scrypt_platform.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <openssl/aes.h>
+
+#include "sysendian.h"
+
+#include "crypto_aesctr.h"
+
+struct crypto_aesctr {
+ AES_KEY * key;
+ uint64_t nonce;
+ uint64_t bytectr;
+ uint8_t buf[16];
+};
+
+/**
+ * crypto_aesctr_init(key, nonce):
+ * Prepare to encrypt/decrypt data with AES in CTR mode, using the provided
+ * expanded key and nonce. The key provided must remain valid for the
+ * lifetime of the stream.
+ */
+struct crypto_aesctr *
+crypto_aesctr_init(AES_KEY * key, uint64_t nonce)
+{
+ struct crypto_aesctr * stream;
+
+ /* Allocate memory. */
+ if ((stream = malloc(sizeof(struct crypto_aesctr))) == NULL)
+ goto err0;
+
+ /* Initialize values. */
+ stream->key = key;
+ stream->nonce = nonce;
+ stream->bytectr = 0;
+
+ /* Success! */
+ return (stream);
+
+err0:
+ /* Failure! */
+ return (NULL);
+}
+
+/**
+ * crypto_aesctr_stream(stream, inbuf, outbuf, buflen):
+ * Generate the next ${buflen} bytes of the AES-CTR stream and xor them with
+ * bytes from ${inbuf}, writing the result into ${outbuf}. If the buffers
+ * ${inbuf} and ${outbuf} overlap, they must be identical.
+ */
+void
+crypto_aesctr_stream(struct crypto_aesctr * stream, const uint8_t * inbuf,
+ uint8_t * outbuf, size_t buflen)
+{
+ uint8_t pblk[16];
+ size_t pos;
+ int bytemod;
+
+ for (pos = 0; pos < buflen; pos++) {
+ /* How far through the buffer are we? */
+ bytemod = stream->bytectr % 16;
+
+ /* Generate a block of cipherstream if needed. */
+ if (bytemod == 0) {
+ be64enc(pblk, stream->nonce);
+ be64enc(pblk + 8, stream->bytectr / 16);
+ AES_encrypt(pblk, stream->buf, stream->key);
+ }
+
+ /* Encrypt a byte. */
+ outbuf[pos] = inbuf[pos] ^ stream->buf[bytemod];
+
+ /* Move to the next byte of cipherstream. */
+ stream->bytectr += 1;
+ }
+}
+
+/**
+ * crypto_aesctr_free(stream):
+ * Free the provided stream object.
+ */
+void
+crypto_aesctr_free(struct crypto_aesctr * stream)
+{
+ int i;
+
+ /* Zero potentially sensitive information. */
+ for (i = 0; i < 16; i++)
+ stream->buf[i] = 0;
+ stream->bytectr = stream->nonce = 0;
+
+ /* Free the stream. */
+ free(stream);
+}
diff --git a/lib/crypto/crypto_aesctr.h b/lib/crypto/crypto_aesctr.h
new file mode 100644
index 0000000..b50398f
--- /dev/null
+++ b/lib/crypto/crypto_aesctr.h
@@ -0,0 +1,59 @@
+/*-
+ * Copyright 2009 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file was originally written by Colin Percival as part of the Tarsnap
+ * online backup system.
+ */
+#ifndef _CRYPTO_AESCTR_H_
+#define _CRYPTO_AESCTR_H_
+
+#include <stdint.h>
+
+#include <openssl/aes.h>
+
+/**
+ * crypto_aesctr_init(key, nonce):
+ * Prepare to encrypt/decrypt data with AES in CTR mode, using the provided
+ * expanded key and nonce. The key provided must remain valid for the
+ * lifetime of the stream.
+ */
+struct crypto_aesctr * crypto_aesctr_init(AES_KEY *, uint64_t);
+
+/**
+ * crypto_aesctr_stream(stream, inbuf, outbuf, buflen):
+ * Generate the next ${buflen} bytes of the AES-CTR stream and xor them with
+ * bytes from ${inbuf}, writing the result into ${outbuf}. If the buffers
+ * ${inbuf} and ${outbuf} overlap, they must be identical.
+ */
+void crypto_aesctr_stream(struct crypto_aesctr *, const uint8_t *,
+ uint8_t *, size_t);
+
+/**
+ * crypto_aesctr_free(stream):
+ * Free the provided stream object.
+ */
+void crypto_aesctr_free(struct crypto_aesctr *);
+
+#endif /* !_CRYPTO_AESCTR_H_ */
diff --git a/lib/crypto/crypto_scrypt-nosse.c b/lib/crypto/crypto_scrypt-nosse.c
new file mode 100644
index 0000000..cad4d0e
--- /dev/null
+++ b/lib/crypto/crypto_scrypt-nosse.c
@@ -0,0 +1,338 @@
+/*-
+ * Copyright 2009 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file was originally written by Colin Percival as part of the Tarsnap
+ * online backup system.
+ */
+#include "scrypt_platform.h"
+
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sha256.h"
+#include "sysendian.h"
+
+#include "crypto_scrypt.h"
+
+static void blkcpy(void *, void *, size_t);
+static void blkxor(void *, void *, size_t);
+static void salsa20_8(uint32_t[16]);
+static void blockmix_salsa8(uint32_t *, uint32_t *, uint32_t *, size_t);
+static uint64_t integerify(void *, size_t);
+static void smix(uint8_t *, size_t, uint64_t, uint32_t *, uint32_t *);
+
+static void
+blkcpy(void * dest, void * src, size_t len)
+{
+ size_t * D = dest;
+ size_t * S = src;
+ size_t L = len / sizeof(size_t);
+ size_t i;
+
+ for (i = 0; i < L; i++)
+ D[i] = S[i];
+}
+
+static void
+blkxor(void * dest, void * src, size_t len)
+{
+ size_t * D = dest;
+ size_t * S = src;
+ size_t L = len / sizeof(size_t);
+ size_t i;
+
+ for (i = 0; i < L; i++)
+ D[i] ^= S[i];
+}
+
+/**
+ * salsa20_8(B):
+ * Apply the salsa20/8 core to the provided block.
+ */
+static void
+salsa20_8(uint32_t B[16])
+{
+ uint32_t x[16];
+ size_t i;
+
+ blkcpy(x, B, 64);
+ for (i = 0; i < 8; i += 2) {
+#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b))))
+ /* Operate on columns. */
+ x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9);
+ x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18);
+
+ x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9);
+ x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18);
+
+ x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9);
+ x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18);
+
+ x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9);
+ x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18);
+
+ /* Operate on rows. */
+ x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9);
+ x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18);
+
+ x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9);
+ x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18);
+
+ x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9);
+ x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18);
+
+ x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9);
+ x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18);
+#undef R
+ }
+ for (i = 0; i < 16; i++)
+ B[i] += x[i];
+}
+
+/**
+ * blockmix_salsa8(Bin, Bout, X, r):
+ * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r
+ * bytes in length; the output Bout must also be the same size. The
+ * temporary space X must be 64 bytes.
+ */
+static void
+blockmix_salsa8(uint32_t * Bin, uint32_t * Bout, uint32_t * X, size_t r)
+{
+ size_t i;
+
+ /* 1: X <-- B_{2r - 1} */
+ blkcpy(X, &Bin[(2 * r - 1) * 16], 64);
+
+ /* 2: for i = 0 to 2r - 1 do */
+ for (i = 0; i < 2 * r; i += 2) {
+ /* 3: X <-- H(X \xor B_i) */
+ blkxor(X, &Bin[i * 16], 64);
+ salsa20_8(X);
+
+ /* 4: Y_i <-- X */
+ /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */
+ blkcpy(&Bout[i * 8], X, 64);
+
+ /* 3: X <-- H(X \xor B_i) */
+ blkxor(X, &Bin[i * 16 + 16], 64);
+ salsa20_8(X);
+
+ /* 4: Y_i <-- X */
+ /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */
+ blkcpy(&Bout[i * 8 + r * 16], X, 64);
+ }
+}
+
+/**
+ * integerify(B, r):
+ * Return the result of parsing B_{2r-1} as a little-endian integer.
+ */
+static uint64_t
+integerify(void * B, size_t r)
+{
+ uint32_t * X = (void *)((uintptr_t)(B) + (2 * r - 1) * 64);
+
+ return (((uint64_t)(X[1]) << 32) + X[0]);
+}
+
+/**
+ * smix(B, r, N, V, XY):
+ * Compute B = SMix_r(B, N). The input B must be 128r bytes in length;
+ * the temporary storage V must be 128rN bytes in length; the temporary
+ * storage XY must be 256r + 64 bytes in length. The value N must be a
+ * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a
+ * multiple of 64 bytes.
+ */
+static void
+smix(uint8_t * B, size_t r, uint64_t N, uint32_t * V, uint32_t * XY)
+{
+ uint32_t * X = XY;
+ uint32_t * Y = &XY[32 * r];
+ uint32_t * Z = &XY[64 * r];
+ uint64_t i;
+ uint64_t j;
+ size_t k;
+
+ /* 1: X <-- B */
+ for (k = 0; k < 32 * r; k++)
+ X[k] = le32dec(&B[4 * k]);
+
+ /* 2: for i = 0 to N - 1 do */
+ for (i = 0; i < N; i += 2) {
+ /* 3: V_i <-- X */
+ blkcpy(&V[i * (32 * r)], X, 128 * r);
+
+ /* 4: X <-- H(X) */
+ blockmix_salsa8(X, Y, Z, r);
+
+ /* 3: V_i <-- X */
+ blkcpy(&V[(i + 1) * (32 * r)], Y, 128 * r);
+
+ /* 4: X <-- H(X) */
+ blockmix_salsa8(Y, X, Z, r);
+ }
+
+ /* 6: for i = 0 to N - 1 do */
+ for (i = 0; i < N; i += 2) {
+ /* 7: j <-- Integerify(X) mod N */
+ j = integerify(X, r) & (N - 1);
+
+ /* 8: X <-- H(X \xor V_j) */
+ blkxor(X, &V[j * (32 * r)], 128 * r);
+ blockmix_salsa8(X, Y, Z, r);
+
+ /* 7: j <-- Integerify(X) mod N */
+ j = integerify(Y, r) & (N - 1);
+
+ /* 8: X <-- H(X \xor V_j) */
+ blkxor(Y, &V[j * (32 * r)], 128 * r);
+ blockmix_salsa8(Y, X, Z, r);
+ }
+
+ /* 10: B' <-- X */
+ for (k = 0; k < 32 * r; k++)
+ le32enc(&B[4 * k], X[k]);
+}
+
+/**
+ * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen):
+ * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r,
+ * p, buflen) and write the result into buf. The parameters r, p, and buflen
+ * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N
+ * must be a power of 2 greater than 1.
+ *
+ * Return 0 on success; or -1 on error.
+ */
+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 * B0, * V0, * XY0;
+ uint8_t * B;
+ uint32_t * V;
+ uint32_t * XY;
+ uint32_t i;
+
+ /* Sanity-check parameters. */
+#if SIZE_MAX > UINT32_MAX
+ if (buflen > (((uint64_t)(1) << 32) - 1) * 32) {
+ errno = EFBIG;
+ goto err0;
+ }
+#endif
+ if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) {
+ errno = EFBIG;
+ goto err0;
+ }
+ if (((N & (N - 1)) != 0) || (N == 0)) {
+ errno = EINVAL;
+ goto err0;
+ }
+ if ((r > SIZE_MAX / 128 / p) ||
+#if SIZE_MAX / 256 <= UINT32_MAX
+ (r > SIZE_MAX / 256) ||
+#endif
+ (N > SIZE_MAX / 128 / r)) {
+ errno = ENOMEM;
+ goto err0;
+ }
+
+ /* Allocate memory. */
+#ifdef HAVE_POSIX_MEMALIGN
+ if ((errno = posix_memalign(&B0, 64, 128 * r * p)) != 0)
+ goto err0;
+ B = (uint8_t *)(B0);
+ if ((errno = posix_memalign(&XY0, 64, 256 * r + 64)) != 0)
+ goto err1;
+ XY = (uint32_t *)(XY0);
+#ifndef MAP_ANON
+ if ((errno = posix_memalign(&V0, 64, 128 * r * N)) != 0)
+ goto err2;
+ V = (uint32_t *)(V0);
+#endif
+#else
+ if ((B0 = malloc(128 * r * p + 63)) == NULL)
+ goto err0;
+ B = (uint8_t *)(((uintptr_t)(B0) + 63) & ~ (uintptr_t)(63));
+ if ((XY0 = malloc(256 * r + 64 + 63)) == NULL)
+ goto err1;
+ XY = (uint32_t *)(((uintptr_t)(XY0) + 63) & ~ (uintptr_t)(63));
+#ifndef MAP_ANON
+ if ((V0 = malloc(128 * r * N + 63)) == NULL)
+ goto err2;
+ V = (uint32_t *)(((uintptr_t)(V0) + 63) & ~ (uintptr_t)(63));
+#endif
+#endif
+#ifdef MAP_ANON
+ if ((V0 = mmap(NULL, 128 * r * N, PROT_READ | PROT_WRITE,
+#ifdef MAP_NOCORE
+ MAP_ANON | MAP_PRIVATE | MAP_NOCORE,
+#else
+ MAP_ANON | MAP_PRIVATE,
+#endif
+ -1, 0)) == MAP_FAILED)
+ goto err2;
+ V = (uint32_t *)(V0);
+#endif
+
+ /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */
+ PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r);
+
+ /* 2: for i = 0 to p - 1 do */
+ for (i = 0; i < p; i++) {
+ /* 3: B_i <-- MF(B_i, N) */
+ smix(&B[i * 128 * r], r, N, V, XY);
+ }
+
+ /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */
+ PBKDF2_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen);
+
+ /* Free memory. */
+#ifdef MAP_ANON
+ if (munmap(V0, 128 * r * N))
+ goto err2;
+#else
+ free(V0);
+#endif
+ free(XY0);
+ free(B0);
+
+ /* Success! */
+ return (0);
+
+err2:
+ free(XY0);
+err1:
+ free(B0);
+err0:
+ /* Failure! */
+ return (-1);
+}
diff --git a/lib/crypto/crypto_scrypt-ref.c b/lib/crypto/crypto_scrypt-ref.c
new file mode 100644
index 0000000..b47ca45
--- /dev/null
+++ b/lib/crypto/crypto_scrypt-ref.c
@@ -0,0 +1,284 @@
+/*-
+ * Copyright 2009 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file was originally written by Colin Percival as part of the Tarsnap
+ * online backup system.
+ */
+#include "scrypt_platform.h"
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sha256.h"
+#include "sysendian.h"
+
+#include "crypto_scrypt.h"
+
+static void blkcpy(uint8_t *, uint8_t *, size_t);
+static void blkxor(uint8_t *, uint8_t *, size_t);
+static void salsa20_8(uint8_t[64]);
+static void blockmix_salsa8(uint8_t *, uint8_t *, size_t);
+static uint64_t integerify(uint8_t *, size_t);
+static void smix(uint8_t *, size_t, uint64_t, uint8_t *, uint8_t *);
+
+static void
+blkcpy(uint8_t * dest, uint8_t * src, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++)
+ dest[i] = src[i];
+}
+
+static void
+blkxor(uint8_t * dest, uint8_t * src, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++)
+ dest[i] ^= src[i];
+}
+
+/**
+ * salsa20_8(B):
+ * Apply the salsa20/8 core to the provided block.
+ */
+static void
+salsa20_8(uint8_t B[64])
+{
+ uint32_t B32[16];
+ uint32_t x[16];
+ size_t i;
+
+ /* Convert little-endian values in. */
+ for (i = 0; i < 16; i++)
+ B32[i] = le32dec(&B[i * 4]);
+
+ /* Compute x = doubleround^4(B32). */
+ for (i = 0; i < 16; i++)
+ x[i] = B32[i];
+ for (i = 0; i < 8; i += 2) {
+#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b))))
+ /* Operate on columns. */
+ x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9);
+ x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18);
+
+ x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9);
+ x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18);
+
+ x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9);
+ x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18);
+
+ x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9);
+ x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18);
+
+ /* Operate on rows. */
+ x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9);
+ x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18);
+
+ x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9);
+ x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18);
+
+ x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9);
+ x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18);
+
+ x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9);
+ x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18);
+#undef R
+ }
+
+ /* Compute B32 = B32 + x. */
+ for (i = 0; i < 16; i++)
+ B32[i] += x[i];
+
+ /* Convert little-endian values out. */
+ for (i = 0; i < 16; i++)
+ le32enc(&B[4 * i], B32[i]);
+}
+
+/**
+ * blockmix_salsa8(B, Y, r):
+ * Compute B = BlockMix_{salsa20/8, r}(B). The input B must be 128r bytes in
+ * length; the temporary space Y must also be the same size.
+ */
+static void
+blockmix_salsa8(uint8_t * B, uint8_t * Y, size_t r)
+{
+ uint8_t X[64];
+ size_t i;
+
+ /* 1: X <-- B_{2r - 1} */
+ blkcpy(X, &B[(2 * r - 1) * 64], 64);
+
+ /* 2: for i = 0 to 2r - 1 do */
+ for (i = 0; i < 2 * r; i++) {
+ /* 3: X <-- H(X \xor B_i) */
+ blkxor(X, &B[i * 64], 64);
+ salsa20_8(X);
+
+ /* 4: Y_i <-- X */
+ blkcpy(&Y[i * 64], X, 64);
+ }
+
+ /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */
+ for (i = 0; i < r; i++)
+ blkcpy(&B[i * 64], &Y[(i * 2) * 64], 64);
+ for (i = 0; i < r; i++)
+ blkcpy(&B[(i + r) * 64], &Y[(i * 2 + 1) * 64], 64);
+}
+
+/**
+ * integerify(B, r):
+ * Return the result of parsing B_{2r-1} as a little-endian integer.
+ */
+static uint64_t
+integerify(uint8_t * B, size_t r)
+{
+ uint8_t * X = &B[(2 * r - 1) * 64];
+
+ return (le64dec(X));
+}
+
+/**
+ * smix(B, r, N, V, XY):
+ * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; the
+ * temporary storage V must be 128rN bytes in length; the temporary storage
+ * XY must be 256r bytes in length. The value N must be a power of 2.
+ */
+static void
+smix(uint8_t * B, size_t r, uint64_t N, uint8_t * V, uint8_t * XY)
+{
+ uint8_t * X = XY;
+ uint8_t * Y = &XY[128 * r];
+ uint64_t i;
+ uint64_t j;
+
+ /* 1: X <-- B */
+ blkcpy(X, B, 128 * r);
+
+ /* 2: for i = 0 to N - 1 do */
+ for (i = 0; i < N; i++) {
+ /* 3: V_i <-- X */
+ blkcpy(&V[i * (128 * r)], X, 128 * r);
+
+ /* 4: X <-- H(X) */
+ blockmix_salsa8(X, Y, r);
+ }
+
+ /* 6: for i = 0 to N - 1 do */
+ for (i = 0; i < N; i++) {
+ /* 7: j <-- Integerify(X) mod N */
+ j = integerify(X, r) & (N - 1);
+
+ /* 8: X <-- H(X \xor V_j) */
+ blkxor(X, &V[j * (128 * r)], 128 * r);
+ blockmix_salsa8(X, Y, r);
+ }
+
+ /* 10: B' <-- X */
+ blkcpy(B, X, 128 * r);
+}
+
+/**
+ * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen):
+ * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r,
+ * p, buflen) and write the result into buf. The parameters r, p, and buflen
+ * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N
+ * must be a power of 2.
+ *
+ * Return 0 on success; or -1 on error.
+ */
+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)
+{
+ uint8_t * B;
+ uint8_t * V;
+ uint8_t * XY;
+ uint32_t i;
+
+ /* Sanity-check parameters. */
+#if SIZE_MAX > UINT32_MAX
+ if (buflen > (((uint64_t)(1) << 32) - 1) * 32) {
+ errno = EFBIG;
+ goto err0;
+ }
+#endif
+ if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) {
+ errno = EFBIG;
+ goto err0;
+ }
+ if (((N & (N - 1)) != 0) || (N == 0)) {
+ errno = EINVAL;
+ goto err0;
+ }
+ if ((r > SIZE_MAX / 128 / p) ||
+#if SIZE_MAX / 256 <= UINT32_MAX
+ (r > SIZE_MAX / 256) ||
+#endif
+ (N > SIZE_MAX / 128 / r)) {
+ errno = ENOMEM;
+ goto err0;
+ }
+
+ /* Allocate memory. */
+ if ((B = malloc(128 * r * p)) == NULL)
+ goto err0;
+ if ((XY = malloc(256 * r)) == NULL)
+ goto err1;
+ if ((V = malloc(128 * r * N)) == NULL)
+ goto err2;
+
+ /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */
+ PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r);
+
+ /* 2: for i = 0 to p - 1 do */
+ for (i = 0; i < p; i++) {
+ /* 3: B_i <-- MF(B_i, N) */
+ smix(&B[i * 128 * r], r, N, V, XY);
+ }
+
+ /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */
+ PBKDF2_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen);
+
+ /* Free memory. */
+ free(V);
+ free(XY);
+ free(B);
+
+ /* Success! */
+ return (0);
+
+err2:
+ free(XY);
+err1:
+ free(B);
+err0:
+ /* Failure! */
+ return (-1);
+}
diff --git a/lib/crypto/crypto_scrypt-sse.c b/lib/crypto/crypto_scrypt-sse.c
new file mode 100644
index 0000000..875175e
--- /dev/null
+++ b/lib/crypto/crypto_scrypt-sse.c
@@ -0,0 +1,366 @@
+/*-
+ * Copyright 2009 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file was originally written by Colin Percival as part of the Tarsnap
+ * online backup system.
+ */
+#include "scrypt_platform.h"
+
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <emmintrin.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sha256.h"
+#include "sysendian.h"
+
+#include "crypto_scrypt.h"
+
+static void blkcpy(void *, void *, size_t);
+static void blkxor(void *, void *, size_t);
+static void salsa20_8(__m128i *);
+static void blockmix_salsa8(__m128i *, __m128i *, __m128i *, size_t);
+static uint64_t integerify(void *, size_t);
+static void smix(uint8_t *, size_t, uint64_t, void *, void *);
+
+static void
+blkcpy(void * dest, void * src, size_t len)
+{
+ __m128i * D = dest;
+ __m128i * S = src;
+ size_t L = len / 16;
+ size_t i;
+
+ for (i = 0; i < L; i++)
+ D[i] = S[i];
+}
+
+static void
+blkxor(void * dest, void * src, size_t len)
+{
+ __m128i * D = dest;
+ __m128i * S = src;
+ size_t L = len / 16;
+ size_t i;
+
+ for (i = 0; i < L; i++)
+ D[i] = _mm_xor_si128(D[i], S[i]);
+}
+
+/**
+ * salsa20_8(B):
+ * Apply the salsa20/8 core to the provided block.
+ */
+static void
+salsa20_8(__m128i B[4])
+{
+ __m128i X0, X1, X2, X3;
+ __m128i T;
+ size_t i;
+
+ X0 = B[0];
+ X1 = B[1];
+ X2 = B[2];
+ X3 = B[3];
+
+ for (i = 0; i < 8; i += 2) {
+ /* Operate on "columns". */
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(X1, _mm_slli_epi32(T, 7));
+ X1 = _mm_xor_si128(X1, _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(X2, _mm_slli_epi32(T, 9));
+ X2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(X3, _mm_slli_epi32(T, 13));
+ X3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(X0, _mm_slli_epi32(T, 18));
+ X0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14));
+
+ /* Rearrange data. */
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+
+ /* Operate on "rows". */
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(X3, _mm_slli_epi32(T, 7));
+ X3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(X2, _mm_slli_epi32(T, 9));
+ X2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(X1, _mm_slli_epi32(T, 13));
+ X1 = _mm_xor_si128(X1, _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(X0, _mm_slli_epi32(T, 18));
+ X0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14));
+
+ /* Rearrange data. */
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+ }
+
+ B[0] = _mm_add_epi32(B[0], X0);
+ B[1] = _mm_add_epi32(B[1], X1);
+ B[2] = _mm_add_epi32(B[2], X2);
+ B[3] = _mm_add_epi32(B[3], X3);
+}
+
+/**
+ * blockmix_salsa8(Bin, Bout, X, r):
+ * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r
+ * bytes in length; the output Bout must also be the same size. The
+ * temporary space X must be 64 bytes.
+ */
+static void
+blockmix_salsa8(__m128i * Bin, __m128i * Bout, __m128i * X, size_t r)
+{
+ size_t i;
+
+ /* 1: X <-- B_{2r - 1} */
+ blkcpy(X, &Bin[8 * r - 4], 64);
+
+ /* 2: for i = 0 to 2r - 1 do */
+ for (i = 0; i < r; i++) {
+ /* 3: X <-- H(X \xor B_i) */
+ blkxor(X, &Bin[i * 8], 64);
+ salsa20_8(X);
+
+ /* 4: Y_i <-- X */
+ /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */
+ blkcpy(&Bout[i * 4], X, 64);
+
+ /* 3: X <-- H(X \xor B_i) */
+ blkxor(X, &Bin[i * 8 + 4], 64);
+ salsa20_8(X);
+
+ /* 4: Y_i <-- X */
+ /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */
+ blkcpy(&Bout[(r + i) * 4], X, 64);
+ }
+}
+
+/**
+ * integerify(B, r):
+ * Return the result of parsing B_{2r-1} as a little-endian integer.
+ */
+static uint64_t
+integerify(void * B, size_t r)
+{
+ uint32_t * X = (void *)((uintptr_t)(B) + (2 * r - 1) * 64);
+
+ return (((uint64_t)(X[13]) << 32) + X[0]);
+}
+
+/**
+ * smix(B, r, N, V, XY):
+ * Compute B = SMix_r(B, N). The input B must be 128r bytes in length;
+ * the temporary storage V must be 128rN bytes in length; the temporary
+ * storage XY must be 256r + 64 bytes in length. The value N must be a
+ * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a
+ * multiple of 64 bytes.
+ */
+static void
+smix(uint8_t * B, size_t r, uint64_t N, void * V, void * XY)
+{
+ __m128i * X = XY;
+ __m128i * Y = (void *)((uintptr_t)(XY) + 128 * r);
+ __m128i * Z = (void *)((uintptr_t)(XY) + 256 * r);
+ uint32_t * X32 = (void *)X;
+ uint64_t i, j;
+ size_t k;
+
+ /* 1: X <-- B */
+ for (k = 0; k < 2 * r; k++) {
+ for (i = 0; i < 16; i++) {
+ X32[k * 16 + i] =
+ le32dec(&B[(k * 16 + (i * 5 % 16)) * 4]);
+ }
+ }
+
+ /* 2: for i = 0 to N - 1 do */
+ for (i = 0; i < N; i += 2) {
+ /* 3: V_i <-- X */
+ blkcpy((void *)((uintptr_t)(V) + i * 128 * r), X, 128 * r);
+
+ /* 4: X <-- H(X) */
+ blockmix_salsa8(X, Y, Z, r);
+
+ /* 3: V_i <-- X */
+ blkcpy((void *)((uintptr_t)(V) + (i + 1) * 128 * r),
+ Y, 128 * r);
+
+ /* 4: X <-- H(X) */
+ blockmix_salsa8(Y, X, Z, r);
+ }
+
+ /* 6: for i = 0 to N - 1 do */
+ for (i = 0; i < N; i += 2) {
+ /* 7: j <-- Integerify(X) mod N */
+ j = integerify(X, r) & (N - 1);
+
+ /* 8: X <-- H(X \xor V_j) */
+ blkxor(X, (void *)((uintptr_t)(V) + j * 128 * r), 128 * r);
+ blockmix_salsa8(X, Y, Z, r);
+
+ /* 7: j <-- Integerify(X) mod N */
+ j = integerify(Y, r) & (N - 1);
+
+ /* 8: X <-- H(X \xor V_j) */
+ blkxor(Y, (void *)((uintptr_t)(V) + j * 128 * r), 128 * r);
+ blockmix_salsa8(Y, X, Z, r);
+ }
+
+ /* 10: B' <-- X */
+ for (k = 0; k < 2 * r; k++) {
+ for (i = 0; i < 16; i++) {
+ le32enc(&B[(k * 16 + (i * 5 % 16)) * 4],
+ X32[k * 16 + i]);
+ }
+ }
+}
+
+/**
+ * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen):
+ * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r,
+ * p, buflen) and write the result into buf. The parameters r, p, and buflen
+ * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N
+ * must be a power of 2 greater than 1.
+ *
+ * Return 0 on success; or -1 on error.
+ */
+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 * B0, * V0, * XY0;
+ uint8_t * B;
+ uint32_t * V;
+ uint32_t * XY;
+ uint32_t i;
+
+ /* Sanity-check parameters. */
+#if SIZE_MAX > UINT32_MAX
+ if (buflen > (((uint64_t)(1) << 32) - 1) * 32) {
+ errno = EFBIG;
+ goto err0;
+ }
+#endif
+ if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) {
+ errno = EFBIG;
+ goto err0;
+ }
+ if (((N & (N - 1)) != 0) || (N == 0)) {
+ errno = EINVAL;
+ goto err0;
+ }
+ if ((r > SIZE_MAX / 128 / p) ||
+#if SIZE_MAX / 256 <= UINT32_MAX
+ (r > (SIZE_MAX - 64) / 256) ||
+#endif
+ (N > SIZE_MAX / 128 / r)) {
+ errno = ENOMEM;
+ goto err0;
+ }
+
+ /* Allocate memory. */
+#ifdef HAVE_POSIX_MEMALIGN
+ if ((errno = posix_memalign(&B0, 64, 128 * r * p)) != 0)
+ goto err0;
+ B = (uint8_t *)(B0);
+ if ((errno = posix_memalign(&XY0, 64, 256 * r + 64)) != 0)
+ goto err1;
+ XY = (uint32_t *)(XY0);
+#ifndef MAP_ANON
+ if ((errno = posix_memalign(&V0, 64, 128 * r * N)) != 0)
+ goto err2;
+ V = (uint32_t *)(V0);
+#endif
+#else
+ if ((B0 = malloc(128 * r * p + 63)) == NULL)
+ goto err0;
+ B = (uint8_t *)(((uintptr_t)(B0) + 63) & ~ (uintptr_t)(63));
+ if ((XY0 = malloc(256 * r + 64 + 63)) == NULL)
+ goto err1;
+ XY = (uint32_t *)(((uintptr_t)(XY0) + 63) & ~ (uintptr_t)(63));
+#ifndef MAP_ANON
+ if ((V0 = malloc(128 * r * N + 63)) == NULL)
+ goto err2;
+ V = (uint32_t *)(((uintptr_t)(V0) + 63) & ~ (uintptr_t)(63));
+#endif
+#endif
+#ifdef MAP_ANON
+ if ((V0 = mmap(NULL, 128 * r * N, PROT_READ | PROT_WRITE,
+#ifdef MAP_NOCORE
+ MAP_ANON | MAP_PRIVATE | MAP_NOCORE,
+#else
+ MAP_ANON | MAP_PRIVATE,
+#endif
+ -1, 0)) == MAP_FAILED)
+ goto err2;
+ V = (uint32_t *)(V0);
+#endif
+
+ /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */
+ PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r);
+
+ /* 2: for i = 0 to p - 1 do */
+ for (i = 0; i < p; i++) {
+ /* 3: B_i <-- MF(B_i, N) */
+ smix(&B[i * 128 * r], r, N, V, XY);
+ }
+
+ /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */
+ PBKDF2_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen);
+
+ /* Free memory. */
+#ifdef MAP_ANON
+ if (munmap(V0, 128 * r * N))
+ goto err2;
+#else
+ free(V0);
+#endif
+ free(XY0);
+ free(B0);
+
+ /* Success! */
+ return (0);
+
+err2:
+ free(XY0);
+err1:
+ free(B0);
+err0:
+ /* Failure! */
+ return (-1);
+}
diff --git a/lib/crypto/crypto_scrypt.h b/lib/crypto/crypto_scrypt.h
new file mode 100644
index 0000000..f72e1f4
--- /dev/null
+++ b/lib/crypto/crypto_scrypt.h
@@ -0,0 +1,46 @@
+/*-
+ * Copyright 2009 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file was originally written by Colin Percival as part of the Tarsnap
+ * online backup system.
+ */
+#ifndef _CRYPTO_SCRYPT_H_
+#define _CRYPTO_SCRYPT_H_
+
+#include <stdint.h>
+
+/**
+ * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen):
+ * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r,
+ * p, buflen) and write the result into buf. The parameters r, p, and buflen
+ * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N
+ * must be a power of 2 greater than 1.
+ *
+ * Return 0 on success; or -1 on error.
+ */
+int crypto_scrypt(const uint8_t *, size_t, const uint8_t *, size_t, uint64_t,
+ uint32_t, uint32_t, uint8_t *, size_t);
+
+#endif /* !_CRYPTO_SCRYPT_H_ */
diff --git a/lib/crypto/sha256.c b/lib/crypto/sha256.c
new file mode 100644
index 0000000..52148a3
--- /dev/null
+++ b/lib/crypto/sha256.c
@@ -0,0 +1,412 @@
+/*-
+ * Copyright 2005,2007,2009 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include "scrypt_platform.h"
+
+#include <sys/types.h>
+
+#include <stdint.h>
+#include <string.h>
+
+#include "sysendian.h"
+
+#include "sha256.h"
+
+/*
+ * Encode a length len/4 vector of (uint32_t) into a length len vector of
+ * (unsigned char) in big-endian form. Assumes len is a multiple of 4.
+ */
+static void
+be32enc_vect(unsigned char *dst, const uint32_t *src, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len / 4; i++)
+ be32enc(dst + i * 4, src[i]);
+}
+
+/*
+ * Decode a big-endian length len vector of (unsigned char) into a length
+ * len/4 vector of (uint32_t). Assumes len is a multiple of 4.
+ */
+static void
+be32dec_vect(uint32_t *dst, const unsigned char *src, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len / 4; i++)
+ dst[i] = be32dec(src + i * 4);
+}
+
+/* Elementary functions used by SHA256 */
+#define Ch(x, y, z) ((x & (y ^ z)) ^ z)
+#define Maj(x, y, z) ((x & (y | z)) | (y & z))
+#define SHR(x, n) (x >> n)
+#define ROTR(x, n) ((x >> n) | (x << (32 - n)))
+#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
+#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
+#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3))
+#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10))
+
+/* SHA256 round function */
+#define RND(a, b, c, d, e, f, g, h, k) \
+ t0 = h + S1(e) + Ch(e, f, g) + k; \
+ t1 = S0(a) + Maj(a, b, c); \
+ d += t0; \
+ h = t0 + t1;
+
+/* Adjusted round function for rotating state */
+#define RNDr(S, W, i, k) \
+ RND(S[(64 - i) % 8], S[(65 - i) % 8], \
+ S[(66 - i) % 8], S[(67 - i) % 8], \
+ S[(68 - i) % 8], S[(69 - i) % 8], \
+ S[(70 - i) % 8], S[(71 - i) % 8], \
+ W[i] + k)
+
+/*
+ * SHA256 block compression function. The 256-bit state is transformed via
+ * the 512-bit input block to produce a new state.
+ */
+static void
+SHA256_Transform(uint32_t * state, const unsigned char block[64])
+{
+ uint32_t W[64];
+ uint32_t S[8];
+ uint32_t t0, t1;
+ int i;
+
+ /* 1. Prepare message schedule W. */
+ be32dec_vect(W, block, 64);
+ for (i = 16; i < 64; i++)
+ W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16];
+
+ /* 2. Initialize working variables. */
+ memcpy(S, state, 32);
+
+ /* 3. Mix. */
+ RNDr(S, W, 0, 0x428a2f98);
+ RNDr(S, W, 1, 0x71374491);
+ RNDr(S, W, 2, 0xb5c0fbcf);
+ RNDr(S, W, 3, 0xe9b5dba5);
+ RNDr(S, W, 4, 0x3956c25b);
+ RNDr(S, W, 5, 0x59f111f1);
+ RNDr(S, W, 6, 0x923f82a4);
+ RNDr(S, W, 7, 0xab1c5ed5);
+ RNDr(S, W, 8, 0xd807aa98);
+ RNDr(S, W, 9, 0x12835b01);
+ RNDr(S, W, 10, 0x243185be);
+ RNDr(S, W, 11, 0x550c7dc3);
+ RNDr(S, W, 12, 0x72be5d74);
+ RNDr(S, W, 13, 0x80deb1fe);
+ RNDr(S, W, 14, 0x9bdc06a7);
+ RNDr(S, W, 15, 0xc19bf174);
+ RNDr(S, W, 16, 0xe49b69c1);
+ RNDr(S, W, 17, 0xefbe4786);
+ RNDr(S, W, 18, 0x0fc19dc6);
+ RNDr(S, W, 19, 0x240ca1cc);
+ RNDr(S, W, 20, 0x2de92c6f);
+ RNDr(S, W, 21, 0x4a7484aa);
+ RNDr(S, W, 22, 0x5cb0a9dc);
+ RNDr(S, W, 23, 0x76f988da);
+ RNDr(S, W, 24, 0x983e5152);
+ RNDr(S, W, 25, 0xa831c66d);
+ RNDr(S, W, 26, 0xb00327c8);
+ RNDr(S, W, 27, 0xbf597fc7);
+ RNDr(S, W, 28, 0xc6e00bf3);
+ RNDr(S, W, 29, 0xd5a79147);
+ RNDr(S, W, 30, 0x06ca6351);
+ RNDr(S, W, 31, 0x14292967);
+ RNDr(S, W, 32, 0x27b70a85);
+ RNDr(S, W, 33, 0x2e1b2138);
+ RNDr(S, W, 34, 0x4d2c6dfc);
+ RNDr(S, W, 35, 0x53380d13);
+ RNDr(S, W, 36, 0x650a7354);
+ RNDr(S, W, 37, 0x766a0abb);
+ RNDr(S, W, 38, 0x81c2c92e);
+ RNDr(S, W, 39, 0x92722c85);
+ RNDr(S, W, 40, 0xa2bfe8a1);
+ RNDr(S, W, 41, 0xa81a664b);
+ RNDr(S, W, 42, 0xc24b8b70);
+ RNDr(S, W, 43, 0xc76c51a3);
+ RNDr(S, W, 44, 0xd192e819);
+ RNDr(S, W, 45, 0xd6990624);
+ RNDr(S, W, 46, 0xf40e3585);
+ RNDr(S, W, 47, 0x106aa070);
+ RNDr(S, W, 48, 0x19a4c116);
+ RNDr(S, W, 49, 0x1e376c08);
+ RNDr(S, W, 50, 0x2748774c);
+ RNDr(S, W, 51, 0x34b0bcb5);
+ RNDr(S, W, 52, 0x391c0cb3);
+ RNDr(S, W, 53, 0x4ed8aa4a);
+ RNDr(S, W, 54, 0x5b9cca4f);
+ RNDr(S, W, 55, 0x682e6ff3);
+ RNDr(S, W, 56, 0x748f82ee);
+ RNDr(S, W, 57, 0x78a5636f);
+ RNDr(S, W, 58, 0x84c87814);
+ RNDr(S, W, 59, 0x8cc70208);
+ RNDr(S, W, 60, 0x90befffa);
+ RNDr(S, W, 61, 0xa4506ceb);
+ RNDr(S, W, 62, 0xbef9a3f7);
+ RNDr(S, W, 63, 0xc67178f2);
+
+ /* 4. Mix local working variables into global state */
+ for (i = 0; i < 8; i++)
+ state[i] += S[i];
+
+ /* Clean the stack. */
+ memset(W, 0, 256);
+ memset(S, 0, 32);
+ t0 = t1 = 0;
+}
+
+static unsigned char PAD[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* Add padding and terminating bit-count. */
+static void
+SHA256_Pad(SHA256_CTX * ctx)
+{
+ unsigned char len[8];
+ uint32_t r, plen;
+
+ /*
+ * Convert length to a vector of bytes -- we do this now rather
+ * than later because the length will change after we pad.
+ */
+ be32enc_vect(len, ctx->count, 8);
+
+ /* Add 1--64 bytes so that the resulting length is 56 mod 64 */
+ r = (ctx->count[1] >> 3) & 0x3f;
+ plen = (r < 56) ? (56 - r) : (120 - r);
+ SHA256_Update(ctx, PAD, (size_t)plen);
+
+ /* Add the terminating bit-count */
+ SHA256_Update(ctx, len, 8);
+}
+
+/* SHA-256 initialization. Begins a SHA-256 operation. */
+void
+SHA256_Init(SHA256_CTX * ctx)
+{
+
+ /* Zero bits processed so far */
+ ctx->count[0] = ctx->count[1] = 0;
+
+ /* Magic initialization constants */
+ ctx->state[0] = 0x6A09E667;
+ ctx->state[1] = 0xBB67AE85;
+ ctx->state[2] = 0x3C6EF372;
+ ctx->state[3] = 0xA54FF53A;
+ ctx->state[4] = 0x510E527F;
+ ctx->state[5] = 0x9B05688C;
+ ctx->state[6] = 0x1F83D9AB;
+ ctx->state[7] = 0x5BE0CD19;
+}
+
+/* Add bytes into the hash */
+void
+SHA256_Update(SHA256_CTX * ctx, const void *in, size_t len)
+{
+ uint32_t bitlen[2];
+ uint32_t r;
+ const unsigned char *src = in;
+
+ /* Number of bytes left in the buffer from previous updates */
+ r = (ctx->count[1] >> 3) & 0x3f;
+
+ /* Convert the length into a number of bits */
+ bitlen[1] = ((uint32_t)len) << 3;
+ bitlen[0] = (uint32_t)(len >> 29);
+
+ /* Update number of bits */
+ if ((ctx->count[1] += bitlen[1]) < bitlen[1])
+ ctx->count[0]++;
+ ctx->count[0] += bitlen[0];
+
+ /* Handle the case where we don't need to perform any transforms */
+ if (len < 64 - r) {
+ memcpy(&ctx->buf[r], src, len);
+ return;
+ }
+
+ /* Finish the current block */
+ memcpy(&ctx->buf[r], src, 64 - r);
+ SHA256_Transform(ctx->state, ctx->buf);
+ src += 64 - r;
+ len -= 64 - r;
+
+ /* Perform complete blocks */
+ while (len >= 64) {
+ SHA256_Transform(ctx->state, src);
+ src += 64;
+ len -= 64;
+ }
+
+ /* Copy left over data into buffer */
+ memcpy(ctx->buf, src, len);
+}
+
+/*
+ * SHA-256 finalization. Pads the input data, exports the hash value,
+ * and clears the context state.
+ */
+void
+SHA256_Final(unsigned char digest[32], SHA256_CTX * ctx)
+{
+
+ /* Add padding */
+ SHA256_Pad(ctx);
+
+ /* Write the hash */
+ be32enc_vect(digest, ctx->state, 32);
+
+ /* Clear the context state */
+ memset((void *)ctx, 0, sizeof(*ctx));
+}
+
+/* Initialize an HMAC-SHA256 operation with the given key. */
+void
+HMAC_SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen)
+{
+ unsigned char pad[64];
+ unsigned char khash[32];
+ const unsigned char * K = _K;
+ size_t i;
+
+ /* If Klen > 64, the key is really SHA256(K). */
+ if (Klen > 64) {
+ SHA256_Init(&ctx->ictx);
+ SHA256_Update(&ctx->ictx, K, Klen);
+ SHA256_Final(khash, &ctx->ictx);
+ K = khash;
+ Klen = 32;
+ }
+
+ /* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */
+ SHA256_Init(&ctx->ictx);
+ memset(pad, 0x36, 64);
+ for (i = 0; i < Klen; i++)
+ pad[i] ^= K[i];
+ SHA256_Update(&ctx->ictx, pad, 64);
+
+ /* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */
+ SHA256_Init(&ctx->octx);
+ memset(pad, 0x5c, 64);
+ for (i = 0; i < Klen; i++)
+ pad[i] ^= K[i];
+ SHA256_Update(&ctx->octx, pad, 64);
+
+ /* Clean the stack. */
+ memset(khash, 0, 32);
+}
+
+/* Add bytes to the HMAC-SHA256 operation. */
+void
+HMAC_SHA256_Update(HMAC_SHA256_CTX * ctx, const void *in, size_t len)
+{
+
+ /* Feed data to the inner SHA256 operation. */
+ SHA256_Update(&ctx->ictx, in, len);
+}
+
+/* Finish an HMAC-SHA256 operation. */
+void
+HMAC_SHA256_Final(unsigned char digest[32], HMAC_SHA256_CTX * ctx)
+{
+ unsigned char ihash[32];
+
+ /* Finish the inner SHA256 operation. */
+ SHA256_Final(ihash, &ctx->ictx);
+
+ /* Feed the inner hash to the outer SHA256 operation. */
+ SHA256_Update(&ctx->octx, ihash, 32);
+
+ /* Finish the outer SHA256 operation. */
+ SHA256_Final(digest, &ctx->octx);
+
+ /* Clean the stack. */
+ memset(ihash, 0, 32);
+}
+
+/**
+ * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen):
+ * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and
+ * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1).
+ */
+void
+PBKDF2_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt,
+ size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen)
+{
+ HMAC_SHA256_CTX PShctx, hctx;
+ size_t i;
+ uint8_t ivec[4];
+ uint8_t U[32];
+ uint8_t T[32];
+ uint64_t j;
+ int k;
+ size_t clen;
+
+ /* Compute HMAC state after processing P and S. */
+ HMAC_SHA256_Init(&PShctx, passwd, passwdlen);
+ HMAC_SHA256_Update(&PShctx, salt, saltlen);
+
+ /* Iterate through the blocks. */
+ for (i = 0; i * 32 < dkLen; i++) {
+ /* Generate INT(i + 1). */
+ be32enc(ivec, (uint32_t)(i + 1));
+
+ /* Compute U_1 = PRF(P, S || INT(i)). */
+ memcpy(&hctx, &PShctx, sizeof(HMAC_SHA256_CTX));
+ HMAC_SHA256_Update(&hctx, ivec, 4);
+ HMAC_SHA256_Final(U, &hctx);
+
+ /* T_i = U_1 ... */
+ memcpy(T, U, 32);
+
+ for (j = 2; j <= c; j++) {
+ /* Compute U_j. */
+ HMAC_SHA256_Init(&hctx, passwd, passwdlen);
+ HMAC_SHA256_Update(&hctx, U, 32);
+ HMAC_SHA256_Final(U, &hctx);
+
+ /* ... xor U_j ... */
+ for (k = 0; k < 32; k++)
+ T[k] ^= U[k];
+ }
+
+ /* Copy as many bytes as necessary into buf. */
+ clen = dkLen - i * 32;
+ if (clen > 32)
+ clen = 32;
+ memcpy(&buf[i * 32], T, clen);
+ }
+
+ /* Clean PShctx, since we never called _Final on it. */
+ memset(&PShctx, 0, sizeof(HMAC_SHA256_CTX));
+}
diff --git a/lib/crypto/sha256.h b/lib/crypto/sha256.h
new file mode 100644
index 0000000..289a523
--- /dev/null
+++ b/lib/crypto/sha256.h
@@ -0,0 +1,62 @@
+/*-
+ * Copyright 2005,2007,2009 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libmd/sha256.h,v 1.2 2006/01/17 15:35:56 phk Exp $
+ */
+
+#ifndef _SHA256_H_
+#define _SHA256_H_
+
+#include <sys/types.h>
+
+#include <stdint.h>
+
+typedef struct SHA256Context {
+ uint32_t state[8];
+ uint32_t count[2];
+ unsigned char buf[64];
+} SHA256_CTX;
+
+typedef struct HMAC_SHA256Context {
+ SHA256_CTX ictx;
+ SHA256_CTX octx;
+} HMAC_SHA256_CTX;
+
+void SHA256_Init(SHA256_CTX *);
+void SHA256_Update(SHA256_CTX *, const void *, size_t);
+void SHA256_Final(unsigned char [32], SHA256_CTX *);
+void HMAC_SHA256_Init(HMAC_SHA256_CTX *, const void *, size_t);
+void HMAC_SHA256_Update(HMAC_SHA256_CTX *, const void *, size_t);
+void HMAC_SHA256_Final(unsigned char [32], HMAC_SHA256_CTX *);
+
+/**
+ * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen):
+ * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and
+ * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1).
+ */
+void PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t,
+ uint64_t, uint8_t *, size_t);
+
+#endif /* !_SHA256_H_ */
diff --git a/lib/scryptenc/scryptenc.c b/lib/scryptenc/scryptenc.c
new file mode 100644
index 0000000..3b7fd0f
--- /dev/null
+++ b/lib/scryptenc/scryptenc.c
@@ -0,0 +1,606 @@
+/*-
+ * Copyright 2009 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file was originally written by Colin Percival as part of the Tarsnap
+ * online backup system.
+ */
+#include "scrypt_platform.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <openssl/aes.h>
+
+#include "crypto_aesctr.h"
+#include "crypto_scrypt.h"
+#include "memlimit.h"
+#include "scryptenc_cpuperf.h"
+#include "sha256.h"
+#include "sysendian.h"
+
+#include "scryptenc.h"
+
+#define ENCBLOCK 65536
+
+static int pickparams(size_t, double, double,
+ int *, uint32_t *, uint32_t *);
+static int checkparams(size_t, double, double, int, uint32_t, uint32_t);
+static int getsalt(uint8_t[32]);
+
+static int
+pickparams(size_t maxmem, double maxmemfrac, double maxtime,
+ int * logN, uint32_t * r, uint32_t * p)
+{
+ size_t memlimit;
+ double opps;
+ double opslimit;
+ double maxN, maxrp;
+ int rc;
+
+ /* Figure out how much memory to use. */
+ if (memtouse(maxmem, maxmemfrac, &memlimit))
+ return (1);
+
+ /* Figure out how fast the CPU is. */
+ if ((rc = scryptenc_cpuperf(&opps)) != 0)
+ return (rc);
+ opslimit = opps * maxtime;
+
+ /* Allow a minimum of 2^15 salsa20/8 cores. */
+ if (opslimit < 32768)
+ opslimit = 32768;
+
+ /* Fix r = 8 for now. */
+ *r = 8;
+
+ /*
+ * The memory limit requires that 128Nr <= memlimit, while the CPU
+ * limit requires that 4Nrp <= opslimit. If opslimit < memlimit/32,
+ * opslimit imposes the stronger limit on N.
+ */
+#ifdef DEBUG
+ fprintf(stderr, "Requiring 128Nr <= %zu, 4Nrp <= %f\n",
+ memlimit, opslimit);
+#endif
+ if (opslimit < memlimit/32) {
+ /* Set p = 1 and choose N based on the CPU limit. */
+ *p = 1;
+ maxN = opslimit / (*r * 4);
+ for (*logN = 1; *logN < 63; *logN += 1) {
+ if ((uint64_t)(1) << *logN > maxN / 2)
+ break;
+ }
+ } else {
+ /* Set N based on the memory limit. */
+ maxN = memlimit / (*r * 128);
+ for (*logN = 1; *logN < 63; *logN += 1) {
+ if ((uint64_t)(1) << *logN > maxN / 2)
+ break;
+ }
+
+ /* Choose p based on the CPU limit. */
+ maxrp = (opslimit / 4) / ((uint64_t)(1) << *logN);
+ if (maxrp > 0x3fffffff)
+ maxrp = 0x3fffffff;
+ *p = (uint32_t)(maxrp) / *r;
+ }
+
+#ifdef DEBUG
+ fprintf(stderr, "N = %zu r = %d p = %d\n",
+ (size_t)(1) << *logN, (int)(*r), (int)(*p));
+#endif
+
+ /* Success! */
+ return (0);
+}
+
+static int
+checkparams(size_t maxmem, double maxmemfrac, double maxtime,
+ int logN, uint32_t r, uint32_t p)
+{
+ size_t memlimit;
+ double opps;
+ double opslimit;
+ uint64_t N;
+ int rc;
+
+ /* Figure out the maximum amount of memory we can use. */
+ if (memtouse(maxmem, maxmemfrac, &memlimit))
+ return (1);
+
+ /* Figure out how fast the CPU is. */
+ if ((rc = scryptenc_cpuperf(&opps)) != 0)
+ return (rc);
+ opslimit = opps * maxtime;
+
+ /* Sanity-check values. */
+ if ((logN < 1) || (logN > 63))
+ return (7);
+ if ((uint64_t)(r) * (uint64_t)(p) >= 0x40000000)
+ return (7);
+
+ /* Check limits. */
+ N = (uint64_t)(1) << logN;
+ if ((memlimit / N) / r < 128)
+ return (9);
+ if ((opslimit / N) / (r * p) < 4)
+ return (10);
+
+ /* Success! */
+ return (0);
+}
+
+static int
+getsalt(uint8_t salt[32])
+{
+ int fd;
+ ssize_t lenread;
+ uint8_t * buf = salt;
+ size_t buflen = 32;
+
+ /* Open /dev/urandom. */
+ if ((fd = open("/dev/urandom", O_RDONLY)) == -1)
+ goto err0;
+
+ /* Read bytes until we have filled the buffer. */
+ while (buflen > 0) {
+ if ((lenread = read(fd, buf, buflen)) == -1)
+ goto err1;
+
+ /* The random device should never EOF. */
+ if (lenread == 0)
+ goto err1;
+
+ /* We're partly done. */
+ buf += lenread;
+ buflen -= lenread;
+ }
+
+ /* Close the device. */
+ while (close(fd) == -1) {
+ if (errno != EINTR)
+ goto err0;
+ }
+
+ /* Success! */
+ return (0);
+
+err1:
+ close(fd);
+err0:
+ /* Failure! */
+ return (4);
+}
+
+static int
+scryptenc_setup(uint8_t header[96], uint8_t dk[64],
+ const uint8_t * passwd, size_t passwdlen,
+ size_t maxmem, double maxmemfrac, double maxtime)
+{
+ uint8_t salt[32];
+ uint8_t hbuf[32];
+ int logN;
+ uint64_t N;
+ uint32_t r;
+ uint32_t p;
+ SHA256_CTX ctx;
+ uint8_t * key_hmac = &dk[32];
+ HMAC_SHA256_CTX hctx;
+ int rc;
+
+ /* Pick values for N, r, p. */
+ if ((rc = pickparams(maxmem, maxmemfrac, maxtime,
+ &logN, &r, &p)) != 0)
+ return (rc);
+ N = (uint64_t)(1) << logN;
+
+ /* Get some salt. */
+ if ((rc = getsalt(salt)) != 0)
+ return (rc);
+
+ /* Generate the derived keys. */
+ if (crypto_scrypt(passwd, passwdlen, salt, 32, N, r, p, dk, 64))
+ return (3);
+
+ /* Construct the file header. */
+ memcpy(header, "scrypt", 6);
+ header[6] = 0;
+ header[7] = logN;
+ be32enc(&header[8], r);
+ be32enc(&header[12], p);
+ memcpy(&header[16], salt, 32);
+
+ /* Add header checksum. */
+ SHA256_Init(&ctx);
+ SHA256_Update(&ctx, header, 48);
+ SHA256_Final(hbuf, &ctx);
+ memcpy(&header[48], hbuf, 16);
+
+ /* Add header signature (used for verifying password). */
+ HMAC_SHA256_Init(&hctx, key_hmac, 32);
+ HMAC_SHA256_Update(&hctx, header, 64);
+ HMAC_SHA256_Final(hbuf, &hctx);
+ memcpy(&header[64], hbuf, 32);
+
+ /* Success! */
+ return (0);
+}
+
+static int
+scryptdec_setup(const uint8_t header[96], uint8_t dk[64],
+ const uint8_t * passwd, size_t passwdlen,
+ size_t maxmem, double maxmemfrac, double maxtime)
+{
+ uint8_t salt[32];
+ uint8_t hbuf[32];
+ int logN;
+ uint32_t r;
+ uint32_t p;
+ uint64_t N;
+ SHA256_CTX ctx;
+ uint8_t * key_hmac = &dk[32];
+ HMAC_SHA256_CTX hctx;
+ int rc;
+
+ /* Parse N, r, p, salt. */
+ logN = header[7];
+ r = be32dec(&header[8]);
+ p = be32dec(&header[12]);
+ memcpy(salt, &header[16], 32);
+
+ /* Verify header checksum. */
+ SHA256_Init(&ctx);
+ SHA256_Update(&ctx, header, 48);
+ SHA256_Final(hbuf, &ctx);
+ if (memcmp(&header[48], hbuf, 16))
+ return (7);
+
+ /*
+ * Check whether the provided parameters are valid and whether the
+ * key derivation function can be computed within the allowed memory
+ * and CPU time.
+ */
+ if ((rc = checkparams(maxmem, maxmemfrac, maxtime, logN, r, p)) != 0)
+ return (rc);
+
+ /* Compute the derived keys. */
+ N = (uint64_t)(1) << logN;
+ if (crypto_scrypt(passwd, passwdlen, salt, 32, N, r, p, dk, 64))
+ return (3);
+
+ /* Check header signature (i.e., verify password). */
+ HMAC_SHA256_Init(&hctx, key_hmac, 32);
+ HMAC_SHA256_Update(&hctx, header, 64);
+ HMAC_SHA256_Final(hbuf, &hctx);
+ if (memcmp(hbuf, &header[64], 32))
+ return (11);
+
+ /* Success! */
+ return (0);
+}
+
+/**
+ * scryptenc_buf(inbuf, inbuflen, outbuf, passwd, passwdlen,
+ * maxmem, maxmemfrac, maxtime):
+ * Encrypt inbuflen bytes from inbuf, writing the resulting inbuflen + 128
+ * bytes to outbuf.
+ */
+int
+scryptenc_buf(const uint8_t * inbuf, size_t inbuflen, uint8_t * outbuf,
+ const uint8_t * passwd, size_t passwdlen,
+ size_t maxmem, double maxmemfrac, double maxtime)
+{
+ uint8_t dk[64];
+ uint8_t hbuf[32];
+ uint8_t header[96];
+ uint8_t * key_enc = dk;
+ uint8_t * key_hmac = &dk[32];
+ int rc;
+ HMAC_SHA256_CTX hctx;
+ AES_KEY key_enc_exp;
+ struct crypto_aesctr * AES;
+
+ /* Generate the header and derived key. */
+ if ((rc = scryptenc_setup(header, dk, passwd, passwdlen,
+ maxmem, maxmemfrac, maxtime)) != 0)
+ return (rc);
+
+ /* Copy header into output buffer. */
+ memcpy(outbuf, header, 96);
+
+ /* Encrypt data. */
+ if (AES_set_encrypt_key(key_enc, 256, &key_enc_exp))
+ return (5);
+ if ((AES = crypto_aesctr_init(&key_enc_exp, 0)) == NULL)
+ return (6);
+ crypto_aesctr_stream(AES, inbuf, &outbuf[96], inbuflen);
+ crypto_aesctr_free(AES);
+
+ /* Add signature. */
+ HMAC_SHA256_Init(&hctx, key_hmac, 32);
+ HMAC_SHA256_Update(&hctx, outbuf, 96 + inbuflen);
+ HMAC_SHA256_Final(hbuf, &hctx);
+ memcpy(&outbuf[96 + inbuflen], hbuf, 32);
+
+ /* Zero sensitive data. */
+ memset(dk, 0, 64);
+ memset(&key_enc_exp, 0, sizeof(AES_KEY));
+
+ /* Success! */
+ return (0);
+}
+
+/**
+ * scryptdec_buf(inbuf, inbuflen, outbuf, outlen, passwd, passwdlen,
+ * maxmem, maxmemfrac, maxtime):
+ * Decrypt inbuflen bytes fro inbuf, writing the result into outbuf and the
+ * decrypted data length to outlen. The allocated length of outbuf must
+ * be at least inbuflen.
+ */
+int
+scryptdec_buf(const uint8_t * inbuf, size_t inbuflen, uint8_t * outbuf,
+ size_t * outlen, const uint8_t * passwd, size_t passwdlen,
+ size_t maxmem, double maxmemfrac, double maxtime)
+{
+ uint8_t hbuf[32];
+ uint8_t dk[64];
+ uint8_t * key_enc = dk;
+ uint8_t * key_hmac = &dk[32];
+ int rc;
+ HMAC_SHA256_CTX hctx;
+ AES_KEY key_enc_exp;
+ struct crypto_aesctr * AES;
+
+ /*
+ * All versions of the scrypt format will start with "scrypt" and
+ * have at least 7 bytes of header.
+ */
+ if ((inbuflen < 7) || (memcmp(inbuf, "scrypt", 6) != 0))
+ return (7);
+
+ /* Check the format. */
+ if (inbuf[6] != 0)
+ return (8);
+
+ /* We must have at least 128 bytes. */
+ if (inbuflen < 128)
+ return (7);
+
+ /* Parse the header and generate derived keys. */
+ if ((rc = scryptdec_setup(inbuf, dk, passwd, passwdlen,
+ maxmem, maxmemfrac, maxtime)) != 0)
+ return (rc);
+
+ /* Decrypt data. */
+ if (AES_set_encrypt_key(key_enc, 256, &key_enc_exp))
+ return (5);
+ if ((AES = crypto_aesctr_init(&key_enc_exp, 0)) == NULL)
+ return (6);
+ crypto_aesctr_stream(AES, &inbuf[96], outbuf, inbuflen - 128);
+ crypto_aesctr_free(AES);
+ *outlen = inbuflen - 128;
+
+ /* Verify signature. */
+ HMAC_SHA256_Init(&hctx, key_hmac, 32);
+ HMAC_SHA256_Update(&hctx, inbuf, inbuflen - 32);
+ HMAC_SHA256_Final(hbuf, &hctx);
+ if (memcmp(hbuf, &inbuf[inbuflen - 32], 32))
+ return (7);
+
+ /* Zero sensitive data. */
+ memset(dk, 0, 64);
+ memset(&key_enc_exp, 0, sizeof(AES_KEY));
+
+ /* Success! */
+ return (0);
+}
+
+/**
+ * scryptenc_file(infile, outfile, passwd, passwdlen,
+ * maxmem, maxmemfrac, maxtime):
+ * Read a stream from infile and encrypt it, writing the resulting stream to
+ * outfile.
+ */
+int
+scryptenc_file(FILE * infile, FILE * outfile,
+ const uint8_t * passwd, size_t passwdlen,
+ size_t maxmem, double maxmemfrac, double maxtime)
+{
+ uint8_t buf[ENCBLOCK];
+ uint8_t dk[64];
+ uint8_t hbuf[32];
+ uint8_t header[96];
+ uint8_t * key_enc = dk;
+ uint8_t * key_hmac = &dk[32];
+ size_t readlen;
+ HMAC_SHA256_CTX hctx;
+ AES_KEY key_enc_exp;
+ struct crypto_aesctr * AES;
+ int rc;
+
+ /* Generate the header and derived key. */
+ if ((rc = scryptenc_setup(header, dk, passwd, passwdlen,
+ maxmem, maxmemfrac, maxtime)) != 0)
+ return (rc);
+
+ /* Hash and write the header. */
+ HMAC_SHA256_Init(&hctx, key_hmac, 32);
+ HMAC_SHA256_Update(&hctx, header, 96);
+ if (fwrite(header, 96, 1, outfile) != 1)
+ return (12);
+
+ /*
+ * Read blocks of data, encrypt them, and write them out; hash the
+ * data as it is produced.
+ */
+ if (AES_set_encrypt_key(key_enc, 256, &key_enc_exp))
+ return (5);
+ if ((AES = crypto_aesctr_init(&key_enc_exp, 0)) == NULL)
+ return (6);
+ do {
+ if ((readlen = fread(buf, 1, ENCBLOCK, infile)) == 0)
+ break;
+ crypto_aesctr_stream(AES, buf, buf, readlen);
+ HMAC_SHA256_Update(&hctx, buf, readlen);
+ if (fwrite(buf, 1, readlen, outfile) < readlen)
+ return (12);
+ } while (1);
+ crypto_aesctr_free(AES);
+
+ /* Did we exit the loop due to a read error? */
+ if (ferror(infile))
+ return (13);
+
+ /* Compute the final HMAC and output it. */
+ HMAC_SHA256_Final(hbuf, &hctx);
+ if (fwrite(hbuf, 32, 1, outfile) != 1)
+ return (12);
+
+ /* Zero sensitive data. */
+ memset(dk, 0, 64);
+ memset(&key_enc_exp, 0, sizeof(AES_KEY));
+
+ /* Success! */
+ return (0);
+}
+
+/**
+ * scryptdec_file(infile, outfile, passwd, passwdlen,
+ * maxmem, maxmemfrac, maxtime):
+ * Read a stream from infile and decrypt it, writing the resulting stream to
+ * outfile.
+ */
+int
+scryptdec_file(FILE * infile, FILE * outfile,
+ const uint8_t * passwd, size_t passwdlen,
+ size_t maxmem, double maxmemfrac, double maxtime)
+{
+ uint8_t buf[ENCBLOCK + 32];
+ uint8_t header[96];
+ uint8_t hbuf[32];
+ uint8_t dk[64];
+ uint8_t * key_enc = dk;
+ uint8_t * key_hmac = &dk[32];
+ size_t buflen = 0;
+ size_t readlen;
+ HMAC_SHA256_CTX hctx;
+ AES_KEY key_enc_exp;
+ struct crypto_aesctr * AES;
+ int rc;
+
+ /*
+ * Read the first 7 bytes of the file; all future version of scrypt
+ * are guaranteed to have at least 7 bytes of header.
+ */
+ if (fread(header, 7, 1, infile) < 1) {
+ if (ferror(infile))
+ return (13);
+ else
+ return (7);
+ }
+
+ /* Do we have the right magic? */
+ if (memcmp(header, "scrypt", 6))
+ return (7);
+ if (header[6] != 0)
+ return (8);
+
+ /*
+ * Read another 89 bytes of the file; version 0 of the srypt file
+ * format has a 96-byte header.
+ */
+ if (fread(&header[7], 89, 1, infile) < 1) {
+ if (ferror(infile))
+ return (13);
+ else
+ return (7);
+ }
+
+ /* Parse the header and generate derived keys. */
+ if ((rc = scryptdec_setup(header, dk, passwd, passwdlen,
+ maxmem, maxmemfrac, maxtime)) != 0)
+ return (rc);
+
+ /* Start hashing with the header. */
+ HMAC_SHA256_Init(&hctx, key_hmac, 32);
+ HMAC_SHA256_Update(&hctx, header, 96);
+
+ /*
+ * We don't know how long the encrypted data block is (we can't know,
+ * since data can be streamed into 'scrypt enc') so we need to read
+ * data and decrypt all of it except the final 32 bytes, then check
+ * if that final 32 bytes is the correct signature.
+ */
+ if (AES_set_encrypt_key(key_enc, 256, &key_enc_exp))
+ return (5);
+ if ((AES = crypto_aesctr_init(&key_enc_exp, 0)) == NULL)
+ return (6);
+ do {
+ /* Read data until we have more than 32 bytes of it. */
+ if ((readlen = fread(&buf[buflen], 1,
+ ENCBLOCK + 32 - buflen, infile)) == 0)
+ break;
+ buflen += readlen;
+ if (buflen <= 32)
+ continue;
+
+ /*
+ * Decrypt, hash, and output everything except the last 32
+ * bytes out of what we have in our buffer.
+ */
+ HMAC_SHA256_Update(&hctx, buf, buflen - 32);
+ crypto_aesctr_stream(AES, buf, buf, buflen - 32);
+ if (fwrite(buf, 1, buflen - 32, outfile) < buflen - 32)
+ return (12);
+
+ /* Move the last 32 bytes to the start of the buffer. */
+ memmove(buf, &buf[buflen - 32], 32);
+ buflen = 32;
+ } while (1);
+ crypto_aesctr_free(AES);
+
+ /* Did we exit the loop due to a read error? */
+ if (ferror(infile))
+ return (13);
+
+ /* Did we read enough data that we *might* have a valid signature? */
+ if (buflen < 32)
+ return (7);
+
+ /* Verify signature. */
+ HMAC_SHA256_Final(hbuf, &hctx);
+ if (memcmp(hbuf, buf, 32))
+ return (7);
+
+ /* Zero sensitive data. */
+ memset(dk, 0, 64);
+ memset(&key_enc_exp, 0, sizeof(AES_KEY));
+
+ return (0);
+}
diff --git a/lib/scryptenc/scryptenc.h b/lib/scryptenc/scryptenc.h
new file mode 100644
index 0000000..7dc3dd3
--- /dev/null
+++ b/lib/scryptenc/scryptenc.h
@@ -0,0 +1,112 @@
+/*-
+ * Copyright 2009 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file was originally written by Colin Percival as part of the Tarsnap
+ * online backup system.
+ */
+#ifndef _SCRYPTENC_H_
+#define _SCRYPTENC_H_
+
+#include <stdint.h>
+#include <stdio.h>
+
+/**
+ * The parameters maxmem, maxmemfrac, and maxtime used by all of these
+ * functions are defined as follows:
+ * maxmem - maximum number of bytes of storage to use for V array (which is
+ * by far the largest consumer of memory). If this value is set to 0, no
+ * maximum will be enforced; any other value less than 1 MiB will be
+ * treated as 1 MiB.
+ * maxmemfrac - maximum fraction of available storage to use for the V array,
+ * where "available storage" is defined as the minimum out of the
+ * RLIMIT_AS, RLIMIT_DATA. and RLIMIT_RSS resource limits (if any are
+ * set). If this value is set to 0 or more than 0.5 it will be treated
+ * as 0.5; and this value will never cause a limit of less than 1 MiB to
+ * be enforced.
+ * maxtime - maximum amount of CPU time to spend computing the derived keys,
+ * in seconds. This limit is only approximately enforced; the CPU
+ * performance is estimated and parameter limits are chosen accordingly.
+ * For the encryption functions, the parameters to the scrypt key derivation
+ * function are chosen to make the key as strong as possible subject to the
+ * specified limits; for the decryption functions, the parameters used are
+ * compared to the computed limits and an error is returned if decrypting
+ * the data would take too much memory or CPU time.
+ */
+/**
+ * Return codes from scrypt(enc|dec)_(buf|file):
+ * 0 success
+ * 1 getrlimit or sysctl(hw.usermem) failed
+ * 2 clock_getres or clock_gettime failed
+ * 3 error computing derived key
+ * 4 could not read salt from /dev/urandom
+ * 5 error in OpenSSL
+ * 6 malloc failed
+ * 7 data is not a valid scrypt-encrypted block
+ * 8 unrecognized scrypt format
+ * 9 decrypting file would take too much memory
+ * 10 decrypting file would take too long
+ * 11 password is incorrect
+ * 12 error writing output file
+ * 13 error reading input file
+ */
+
+/**
+ * scryptenc_buf(inbuf, inbuflen, outbuf, passwd, passwdlen,
+ * maxmem, maxmemfrac, maxtime):
+ * Encrypt inbuflen bytes from inbuf, writing the resulting inbuflen + 128
+ * bytes to outbuf.
+ */
+int scryptenc_buf(const uint8_t *, size_t, uint8_t *,
+ const uint8_t *, size_t, size_t, double, double);
+
+/**
+ * scryptdec_buf(inbuf, inbuflen, outbuf, outlen, passwd, passwdlen,
+ * maxmem, maxmemfrac, maxtime):
+ * Decrypt inbuflen bytes from inbuf, writing the result into outbuf and the
+ * decrypted data length to outlen. The allocated length of outbuf must
+ * be at least inbuflen.
+ */
+int scryptdec_buf(const uint8_t *, size_t, uint8_t *, size_t *,
+ const uint8_t *, size_t, size_t, double, double);
+
+/**
+ * scryptenc_file(infile, outfile, passwd, passwdlen,
+ * maxmem, maxmemfrac, maxtime):
+ * Read a stream from infile and encrypt it, writing the resulting stream to
+ * outfile.
+ */
+int scryptenc_file(FILE *, FILE *, const uint8_t *, size_t,
+ size_t, double, double);
+
+/**
+ * scryptdec_file(infile, outfile, passwd, passwdlen,
+ * maxmem, maxmemfrac, maxtime):
+ * Read a stream from infile and decrypt it, writing the resulting stream to
+ * outfile.
+ */
+int scryptdec_file(FILE *, FILE *, const uint8_t *, size_t,
+ size_t, double, double);
+
+#endif /* !_SCRYPTENC_H_ */
diff --git a/lib/scryptenc/scryptenc_cpuperf.c b/lib/scryptenc/scryptenc_cpuperf.c
new file mode 100644
index 0000000..aa2d503
--- /dev/null
+++ b/lib/scryptenc/scryptenc_cpuperf.c
@@ -0,0 +1,185 @@
+/*-
+ * Copyright 2009 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file was originally written by Colin Percival as part of the Tarsnap
+ * online backup system.
+ */
+#include "scrypt_platform.h"
+
+#include <sys/time.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <time.h>
+
+#include "crypto_scrypt.h"
+
+#include "scryptenc_cpuperf.h"
+
+#ifdef HAVE_CLOCK_GETTIME
+
+static clock_t clocktouse;
+
+static int
+getclockres(double * resd)
+{
+ struct timespec res;
+
+ /*
+ * Try clocks in order of preference until we find one which works.
+ * (We assume that if clock_getres works, clock_gettime will, too.)
+ * The use of if/else/if/else/if/else rather than if/elif/elif/else
+ * is ugly but legal, and allows us to #ifdef things appropriately.
+ */
+#ifdef CLOCK_VIRTUAL
+ if (clock_getres(CLOCK_VIRTUAL, &res) == 0)
+ clocktouse = CLOCK_VIRTUAL;
+ else
+#endif
+#ifdef CLOCK_MONOTONIC
+ if (clock_getres(CLOCK_MONOTONIC, &res) == 0)
+ clocktouse = CLOCK_MONOTONIC;
+ else
+#endif
+ if (clock_getres(CLOCK_REALTIME, &res) == 0)
+ clocktouse = CLOCK_REALTIME;
+ else
+ return (-1);
+
+ /* Convert clock resolution to a double. */
+ *resd = res.tv_sec + res.tv_nsec * 0.000000001;
+
+ return (0);
+}
+
+static int
+getclocktime(struct timespec * ts)
+{
+
+ if (clock_gettime(clocktouse, ts))
+ return (-1);
+
+ return (0);
+}
+
+#else
+static int
+getclockres(double * resd)
+{
+
+ *resd = 1.0 / CLOCKS_PER_SEC;
+
+ return (0);
+}
+
+static int
+getclocktime(struct timespec * ts)
+{
+ struct timeval tv;
+
+ if (gettimeofday(&tv, NULL))
+ return (-1);
+ ts->tv_sec = tv.tv_sec;
+ ts->tv_nsec = tv.tv_usec * 1000;
+
+ return (0);
+}
+#endif
+
+static int
+getclockdiff(struct timespec * st, double * diffd)
+{
+ struct timespec en;
+
+ if (getclocktime(&en))
+ return (1);
+ *diffd = (en.tv_nsec - st->tv_nsec) * 0.000000001 +
+ (en.tv_sec - st->tv_sec);
+
+ return (0);
+}
+
+/**
+ * scryptenc_cpuperf(opps):
+ * Estimate the number of salsa20/8 cores which can be executed per second,
+ * and return the value via opps.
+ */
+int
+scryptenc_cpuperf(double * opps)
+{
+ struct timespec st;
+ double resd, diffd;
+ uint64_t i = 0;
+
+ /* Get the clock resolution. */
+ if (getclockres(&resd))
+ return (2);
+
+#ifdef DEBUG
+ fprintf(stderr, "Clock resolution is %f\n", resd);
+#endif
+
+ /* Loop until the clock ticks. */
+ if (getclocktime(&st))
+ return (2);
+ do {
+ /* Do an scrypt. */
+ if (crypto_scrypt(NULL, 0, NULL, 0, 16, 1, 1, NULL, 0))
+ return (3);
+
+ /* Has the clock ticked? */
+ if (getclockdiff(&st, &diffd))
+ return (2);
+ if (diffd > 0)
+ break;
+ } while (1);
+
+ /* Could how many scryps we can do before the next tick. */
+ if (getclocktime(&st))
+ return (2);
+ do {
+ /* Do an scrypt. */
+ if (crypto_scrypt(NULL, 0, NULL, 0, 128, 1, 1, NULL, 0))
+ return (3);
+
+ /* We invoked the salsa20/8 core 512 times. */
+ i += 512;
+
+ /* Check if we have looped for long enough. */
+ if (getclockdiff(&st, &diffd))
+ return (2);
+ if (diffd > resd)
+ break;
+ } while (1);
+
+#ifdef DEBUG
+ fprintf(stderr, "%ju salsa20/8 cores performed in %f seconds\n",
+ (uintmax_t)i, diffd);
+#endif
+
+ /* We can do approximately i salsa20/8 cores per diffd seconds. */
+ *opps = i / diffd;
+ return (0);
+}
diff --git a/lib/scryptenc/scryptenc_cpuperf.h b/lib/scryptenc/scryptenc_cpuperf.h
new file mode 100644
index 0000000..e236fff
--- /dev/null
+++ b/lib/scryptenc/scryptenc_cpuperf.h
@@ -0,0 +1,39 @@
+/*-
+ * Copyright 2009 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file was originally written by Colin Percival as part of the Tarsnap
+ * online backup system.
+ */
+#ifndef _SCRYPTENC_CPUPERF_H_
+#define _SCRYPTENC_CPUPERF_H_
+
+/**
+ * scryptenc_cpuperf(opps):
+ * Estimate the number of salsa20/8 cores which can be executed per second,
+ * and return the value via opps.
+ */
+int scryptenc_cpuperf(double *);
+
+#endif /* !_SCRYPTENC_CPUPERF_H_ */
diff --git a/lib/util/memlimit.c b/lib/util/memlimit.c
new file mode 100644
index 0000000..8303f5c
--- /dev/null
+++ b/lib/util/memlimit.c
@@ -0,0 +1,302 @@
+/*-
+ * Copyright 2009 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file was originally written by Colin Percival as part of the Tarsnap
+ * online backup system.
+ */
+#include "scrypt_platform.h"
+
+#include <sys/types.h>
+#include <sys/resource.h>
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_SYSCTL_HW_USERMEM
+#include <sys/sysctl.h>
+#endif
+#ifdef HAVE_SYS_SYSINFO_H
+#include <sys/sysinfo.h>
+#endif
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+
+#include "memlimit.h"
+
+#ifdef HAVE_SYSCTL_HW_USERMEM
+static int
+memlimit_sysctl_hw_usermem(size_t * memlimit)
+{
+ int mib[2];
+ uint8_t usermembuf[8];
+ size_t usermemlen = 8;
+ uint64_t usermem;
+
+ /* Ask the kernel how much RAM we have. */
+ mib[0] = CTL_HW;
+ mib[1] = HW_USERMEM;
+ if (sysctl(mib, 2, usermembuf, &usermemlen, NULL, 0))
+ return (1);
+
+ /*
+ * Parse as either a uint64_t or a uint32_t based on the length of
+ * output the kernel reports having copied out. It appears that all
+ * systems providing a sysctl interface for reading integers copy
+ * them out as system-endian values, so we don't need to worry about
+ * parsing them.
+ */
+ if (usermemlen == sizeof(uint64_t))
+ usermem = *(uint64_t *)usermembuf;
+ else if (usermemlen == sizeof(uint32_t))
+ usermem = *(uint32_t *)usermembuf;
+ else
+ return (1);
+
+ /* Return the sysctl value, but clamp to SIZE_MAX if necessary. */
+#if UINT64_MAX > SIZE_MAX
+ if (usermem > SIZE_MAX)
+ *memlimit = SIZE_MAX;
+ else
+ *memlimit = usermem;
+#else
+ *memlimit = usermem;
+#endif
+
+ /* Success! */
+ return (0);
+}
+#endif
+
+/* If we don't HAVE_STRUCT_SYSINFO, we can't use sysinfo. */
+#ifndef HAVE_STRUCT_SYSINFO
+#undef HAVE_SYSINFO
+#endif
+
+/* If we don't HAVE_STRUCT_SYSINFO_TOTALRAM, we can't use sysinfo. */
+#ifndef HAVE_STRUCT_SYSINFO_TOTALRAM
+#undef HAVE_SYSINFO
+#endif
+
+#ifdef HAVE_SYSINFO
+static int
+memlimit_sysinfo(size_t * memlimit)
+{
+ struct sysinfo info;
+ uint64_t totalmem;
+
+ /* Get information from the kernel. */
+ if (sysinfo(&info))
+ return (1);
+ totalmem = info.totalram;
+
+ /* If we're on a modern kernel, adjust based on mem_unit. */
+#ifdef HAVE_STRUCT_SYSINFO_MEM_UNIT
+ totalmem = totalmem * info.mem_unit;
+#endif
+
+ /* Return the value, but clamp to SIZE_MAX if necessary. */
+#if UINT64_MAX > SIZE_MAX
+ if (totalmem > SIZE_MAX)
+ *memlimit = SIZE_MAX;
+ else
+ *memlimit = totalmem;
+#else
+ *memlimit = totalmem;
+#endif
+
+ /* Success! */
+ return (0);
+}
+#endif /* HAVE_SYSINFO */
+
+static int
+memlimit_rlimit(size_t * memlimit)
+{
+ struct rlimit rl;
+ uint64_t memrlimit;
+
+ /* Find the least of... */
+ memrlimit = (uint64_t)(-1);
+
+ /* ... RLIMIT_AS... */
+#ifdef RLIMIT_AS
+ if (getrlimit(RLIMIT_AS, &rl))
+ return (1);
+ if ((rl.rlim_cur != RLIM_INFINITY) &&
+ ((uint64_t)rl.rlim_cur < memrlimit))
+ memrlimit = rl.rlim_cur;
+#endif
+
+ /* ... RLIMIT_DATA... */
+ if (getrlimit(RLIMIT_DATA, &rl))
+ return (1);
+ if ((rl.rlim_cur != RLIM_INFINITY) &&
+ ((uint64_t)rl.rlim_cur < memrlimit))
+ memrlimit = rl.rlim_cur;
+
+ /* ... and RLIMIT_RSS. */
+#ifdef RLIMIT_RSS
+ if (getrlimit(RLIMIT_RSS, &rl))
+ return (1);
+ if ((rl.rlim_cur != RLIM_INFINITY) &&
+ ((uint64_t)rl.rlim_cur < memrlimit))
+ memrlimit = rl.rlim_cur;
+#endif
+
+ /* Return the value, but clamp to SIZE_MAX if necessary. */
+#if UINT64_MAX > SIZE_MAX
+ if (memrlimit > SIZE_MAX)
+ *memlimit = SIZE_MAX;
+ else
+ *memlimit = memrlimit;
+#else
+ *memlimit = memrlimit;
+#endif
+
+ /* Success! */
+ return (0);
+}
+
+#ifdef _SC_PHYS_PAGES
+
+/* Some systems define _SC_PAGESIZE instead of _SC_PAGE_SIZE. */
+#ifndef _SC_PAGE_SIZE
+#define _SC_PAGE_SIZE _SC_PAGESIZE
+#endif
+
+static int
+memlimit_sysconf(size_t * memlimit)
+{
+ long pagesize;
+ long physpages;
+ uint64_t totalmem;
+
+ /* Set errno to 0 in order to distinguish "no limit" from "error". */
+ errno = 0;
+
+ /* Read the two limits. */
+ if (((pagesize = sysconf(_SC_PAGE_SIZE)) == -1) ||
+ ((physpages = sysconf(_SC_PHYS_PAGES)) == -1)) {
+ /* Did an error occur? */
+ if (errno != 0)
+ return (1);
+
+ /* If not, there is no limit. */
+ totalmem = (uint64_t)(-1);
+ } else {
+ /* Compute the limit. */
+ totalmem = (uint64_t)(pagesize) * (uint64_t)(physpages);
+ }
+
+ /* Return the value, but clamp to SIZE_MAX if necessary. */
+#if UINT64_MAX > SIZE_MAX
+ if (totalmem > SIZE_MAX)
+ *memlimit = SIZE_MAX;
+ else
+ *memlimit = totalmem;
+#else
+ *memlimit = totalmem;
+#endif
+
+ /* Success! */
+ return (0);
+}
+#endif
+
+int
+memtouse(size_t maxmem, double maxmemfrac, size_t * memlimit)
+{
+ size_t sysctl_memlimit, sysinfo_memlimit, rlimit_memlimit;
+ size_t sysconf_memlimit;
+ size_t memlimit_min;
+ size_t memavail;
+
+ /* Get memory limits. */
+#ifdef HAVE_SYSCTL_HW_USERMEM
+ if (memlimit_sysctl_hw_usermem(&sysctl_memlimit))
+ return (1);
+#else
+ sysctl_memlimit = (size_t)(-1);
+#endif
+#ifdef HAVE_SYSINFO
+ if (memlimit_sysinfo(&sysinfo_memlimit))
+ return (1);
+#else
+ sysinfo_memlimit = (size_t)(-1);
+#endif
+ if (memlimit_rlimit(&rlimit_memlimit))
+ return (1);
+#ifdef _SC_PHYS_PAGES
+ if (memlimit_sysconf(&sysconf_memlimit))
+ return (1);
+#else
+ sysconf_memlimit = (size_t)(-1);
+#endif
+
+#ifdef DEBUG
+ fprintf(stderr, "Memory limits are %zu %zu %zu %zu\n",
+ sysctl_memlimit, sysinfo_memlimit, rlimit_memlimit,
+ sysconf_memlimit);
+#endif
+
+ /* Find the smallest of them. */
+ memlimit_min = (size_t)(-1);
+ if (memlimit_min > sysctl_memlimit)
+ memlimit_min = sysctl_memlimit;
+ if (memlimit_min > sysinfo_memlimit)
+ memlimit_min = sysinfo_memlimit;
+ if (memlimit_min > rlimit_memlimit)
+ memlimit_min = rlimit_memlimit;
+ if (memlimit_min > sysconf_memlimit)
+ memlimit_min = sysconf_memlimit;
+
+ /* Only use the specified fraction of the available memory. */
+ if ((maxmemfrac > 0.5) || (maxmemfrac == 0.0))
+ maxmemfrac = 0.5;
+ memavail = maxmemfrac * memlimit_min;
+
+ /* Don't use more than the specified maximum. */
+ if ((maxmem > 0) && (memavail > maxmem))
+ memavail = maxmem;
+
+ /* But always allow at least 1 MiB. */
+ if (memavail < 1048576)
+ memavail = 1048576;
+
+#ifdef DEBUG
+ fprintf(stderr, "Allowing up to %zu memory to be used\n", memavail);
+#endif
+
+ /* Return limit via the provided pointer. */
+ *memlimit = memavail;
+ return (0);
+}
diff --git a/lib/util/memlimit.h b/lib/util/memlimit.h
new file mode 100644
index 0000000..d3b4891
--- /dev/null
+++ b/lib/util/memlimit.h
@@ -0,0 +1,42 @@
+/*-
+ * Copyright 2009 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file was originally written by Colin Percival as part of the Tarsnap
+ * online backup system.
+ */
+#ifndef _MEMLIMIT_H_
+#define _MEMLIMIT_H_
+
+#include <stddef.h>
+
+/**
+ * memtouse(maxmem, maxmemfrac, memlimit):
+ * Examine the system and return via memlimit the amount of RAM which should
+ * be used -- the specified fraction of the available RAM, but no more than
+ * maxmem, and no less than 1MiB.
+ */
+int memtouse(size_t, double, size_t *);
+
+#endif /* !_MEMLIMIT_H_ */
diff --git a/lib/util/readpass.c b/lib/util/readpass.c
new file mode 100644
index 0000000..91f77e0
--- /dev/null
+++ b/lib/util/readpass.c
@@ -0,0 +1,143 @@
+/*-
+ * Copyright 2009 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include "scrypt_platform.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "warn.h"
+
+#include "readpass.h"
+
+#define MAXPASSLEN 2048
+
+/**
+ * tarsnap_getpass(passwd, prompt, confirmprompt, devtty)
+ * If ${devtty} is non-zero, read a password from /dev/tty if possible; if
+ * not, read from stdin. If reading from a tty (either /dev/tty or stdin),
+ * disable echo and prompt the user by printing ${prompt} to stderr. If
+ * ${confirmprompt} is non-NULL, read a second password (prompting if a
+ * terminal is being used) and repeat until the user enters the same password
+ * twice. Return the password as a malloced NUL-terminated string via
+ * ${passwd}. The obscure name is to avoid namespace collisions due to the
+ * getpass / readpass / readpassphrase / etc. functions in various libraries.
+ */
+int
+tarsnap_readpass(char ** passwd, const char * prompt,
+ const char * confirmprompt, int devtty)
+{
+ FILE * readfrom;
+ char passbuf[MAXPASSLEN];
+ char confpassbuf[MAXPASSLEN];
+ struct termios term, term_old;
+ int usingtty;
+
+ /*
+ * If devtty != 0, try to open /dev/tty; if that fails, or if devtty
+ * is zero, we'll read the password from stdin instead.
+ */
+ if ((devtty == 0) || ((readfrom = fopen("/dev/tty", "r")) == NULL))
+ readfrom = stdin;
+
+ /* If we're reading from a terminal, try to disable echo. */
+ if ((usingtty = isatty(fileno(readfrom))) != 0) {
+ if (tcgetattr(fileno(readfrom), &term_old)) {
+ warn("Cannot read terminal settings");
+ goto err1;
+ }
+ memcpy(&term, &term_old, sizeof(struct termios));
+ term.c_lflag = (term.c_lflag & ~ECHO) | ECHONL;
+ if (tcsetattr(fileno(readfrom), TCSANOW, &term)) {
+ warn("Cannot set terminal settings");
+ goto err1;
+ }
+ }
+
+retry:
+ /* If we have a terminal, prompt the user to enter the password. */
+ if (usingtty)
+ fprintf(stderr, "%s: ", prompt);
+
+ /* Read the password. */
+ if (fgets(passbuf, MAXPASSLEN, readfrom) == NULL) {
+ warn("Cannot read password");
+ goto err2;
+ }
+
+ /* Confirm the password if necessary. */
+ if (confirmprompt != NULL) {
+ if (usingtty)
+ fprintf(stderr, "%s: ", confirmprompt);
+ if (fgets(confpassbuf, MAXPASSLEN, readfrom) == NULL) {
+ warn("Cannot read password");
+ goto err2;
+ }
+ if (strcmp(passbuf, confpassbuf)) {
+ fprintf(stderr,
+ "Passwords mismatch, please try again\n");
+ goto retry;
+ }
+ }
+
+ /* Terminate the string at the first "\r" or "\n" (if any). */
+ passbuf[strcspn(passbuf, "\r\n")] = '\0';
+
+ /* If we changed terminal settings, reset them. */
+ if (usingtty)
+ tcsetattr(fileno(readfrom), TCSANOW, &term_old);
+
+ /* Close /dev/tty if we opened it. */
+ if (readfrom != stdin)
+ fclose(readfrom);
+
+ /* Copy the password out. */
+ if ((*passwd = strdup(passbuf)) == NULL) {
+ warn("Cannot allocate memory");
+ goto err1;
+ }
+
+ /* Zero any stored passwords. */
+ memset(passbuf, 0, MAXPASSLEN);
+ memset(confpassbuf, 0, MAXPASSLEN);
+
+ /* Success! */
+ return (0);
+
+err2:
+ /* Reset terminal settings if necessary. */
+ if (usingtty)
+ tcsetattr(fileno(readfrom), TCSAFLUSH, &term_old);
+err1:
+ /* Close /dev/tty if we opened it. */
+ if (readfrom != stdin)
+ fclose(readfrom);
+
+ /* Failure! */
+ return (-1);
+}
diff --git a/lib/util/readpass.h b/lib/util/readpass.h
new file mode 100644
index 0000000..da57278
--- /dev/null
+++ b/lib/util/readpass.h
@@ -0,0 +1,45 @@
+/*-
+ * Copyright 2009 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file was originally written by Colin Percival as part of the Tarsnap
+ * online backup system.
+ */
+#ifndef _READPASS_H_
+#define _READPASS_H_
+
+/**
+ * tarsnap_getpass(passwd, prompt, confirmprompt, devtty)
+ * If ${devtty} is non-zero, read a password from /dev/tty if possible; if
+ * not, read from stdin. If reading from a tty (either /dev/tty or stdin),
+ * disable echo and prompt the user by printing ${prompt} to stderr. If
+ * ${confirmprompt} is non-NULL, read a second password (prompting if a
+ * terminal is being used) and repeat until the user enters the same password
+ * twice. Return the password as a malloced NUL-terminated string via
+ * ${passwd}. The obscure name is to avoid namespace collisions due to the
+ * getpass / readpass / readpassphrase / etc. functions in various libraries.
+ */
+int tarsnap_readpass(char **, const char *, const char *, int);
+
+#endif /* !_READPASS_H_ */
diff --git a/lib/util/sysendian.h b/lib/util/sysendian.h
new file mode 100644
index 0000000..62ef31a
--- /dev/null
+++ b/lib/util/sysendian.h
@@ -0,0 +1,140 @@
+/*-
+ * Copyright 2007-2009 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file was originally written by Colin Percival as part of the Tarsnap
+ * online backup system.
+ */
+#ifndef _SYSENDIAN_H_
+#define _SYSENDIAN_H_
+
+#include "scrypt_platform.h"
+
+/* If we don't have be64enc, the <sys/endian.h> we have isn't usable. */
+#if !HAVE_DECL_BE64ENC
+#undef HAVE_SYS_ENDIAN_H
+#endif
+
+#ifdef HAVE_SYS_ENDIAN_H
+
+#include <sys/endian.h>
+
+#else
+
+#include <stdint.h>
+
+static inline uint32_t
+be32dec(const void *pp)
+{
+ const uint8_t *p = (uint8_t const *)pp;
+
+ return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) +
+ ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24));
+}
+
+static inline void
+be32enc(void *pp, uint32_t x)
+{
+ uint8_t * p = (uint8_t *)pp;
+
+ p[3] = x & 0xff;
+ p[2] = (x >> 8) & 0xff;
+ p[1] = (x >> 16) & 0xff;
+ p[0] = (x >> 24) & 0xff;
+}
+
+static inline uint64_t
+be64dec(const void *pp)
+{
+ const uint8_t *p = (uint8_t const *)pp;
+
+ return ((uint64_t)(p[7]) + ((uint64_t)(p[6]) << 8) +
+ ((uint64_t)(p[5]) << 16) + ((uint64_t)(p[4]) << 24) +
+ ((uint64_t)(p[3]) << 32) + ((uint64_t)(p[2]) << 40) +
+ ((uint64_t)(p[1]) << 48) + ((uint64_t)(p[0]) << 56));
+}
+
+static inline void
+be64enc(void *pp, uint64_t x)
+{
+ uint8_t * p = (uint8_t *)pp;
+
+ p[7] = x & 0xff;
+ p[6] = (x >> 8) & 0xff;
+ p[5] = (x >> 16) & 0xff;
+ p[4] = (x >> 24) & 0xff;
+ p[3] = (x >> 32) & 0xff;
+ p[2] = (x >> 40) & 0xff;
+ p[1] = (x >> 48) & 0xff;
+ p[0] = (x >> 56) & 0xff;
+}
+
+static inline uint32_t
+le32dec(const void *pp)
+{
+ const uint8_t *p = (uint8_t const *)pp;
+
+ return ((uint32_t)(p[0]) + ((uint32_t)(p[1]) << 8) +
+ ((uint32_t)(p[2]) << 16) + ((uint32_t)(p[3]) << 24));
+}
+
+static inline void
+le32enc(void *pp, uint32_t x)
+{
+ uint8_t * p = (uint8_t *)pp;
+
+ p[0] = x & 0xff;
+ p[1] = (x >> 8) & 0xff;
+ p[2] = (x >> 16) & 0xff;
+ p[3] = (x >> 24) & 0xff;
+}
+
+static inline uint64_t
+le64dec(const void *pp)
+{
+ const uint8_t *p = (uint8_t const *)pp;
+
+ return ((uint64_t)(p[0]) + ((uint64_t)(p[1]) << 8) +
+ ((uint64_t)(p[2]) << 16) + ((uint64_t)(p[3]) << 24) +
+ ((uint64_t)(p[4]) << 32) + ((uint64_t)(p[5]) << 40) +
+ ((uint64_t)(p[6]) << 48) + ((uint64_t)(p[7]) << 56));
+}
+
+static inline void
+le64enc(void *pp, uint64_t x)
+{
+ uint8_t * p = (uint8_t *)pp;
+
+ p[0] = x & 0xff;
+ p[1] = (x >> 8) & 0xff;
+ p[2] = (x >> 16) & 0xff;
+ p[3] = (x >> 24) & 0xff;
+ p[4] = (x >> 32) & 0xff;
+ p[5] = (x >> 40) & 0xff;
+ p[6] = (x >> 48) & 0xff;
+ p[7] = (x >> 56) & 0xff;
+}
+#endif /* !HAVE_SYS_ENDIAN_H */
+
+#endif /* !_SYSENDIAN_H_ */
diff --git a/lib/util/warn.c b/lib/util/warn.c
new file mode 100644
index 0000000..504f935
--- /dev/null
+++ b/lib/util/warn.c
@@ -0,0 +1,75 @@
+/*-
+ * Copyright 2009 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file was originally written by Colin Percival as part of the Tarsnap
+ * online backup system.
+ */
+#include "scrypt_platform.h"
+
+#ifdef HAVE_ERR_H
+/*
+ * Everything is provided through err.h and the associated library, so we
+ * don't need to do anything here.
+ */
+#else
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "warn.h"
+
+const char * warn_progname = "(null)";
+
+void
+warn(const char * fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ fprintf(stderr, "%s", warn_progname);
+ if (fmt != NULL) {
+ fprintf(stderr, ": ");
+ vfprintf(stderr, fmt, ap);
+ }
+ fprintf(stderr, ": %s\n", strerror(errno));
+ va_end(ap);
+}
+
+void
+warnx(const char * fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ fprintf(stderr, "%s", warn_progname);
+ if (fmt != NULL) {
+ fprintf(stderr, ": ");
+ vfprintf(stderr, fmt, ap);
+ }
+ fprintf(stderr, "\n");
+ va_end(ap);
+}
+#endif
diff --git a/lib/util/warn.h b/lib/util/warn.h
new file mode 100644
index 0000000..262d24b
--- /dev/null
+++ b/lib/util/warn.h
@@ -0,0 +1,13 @@
+#ifndef _WARN_H_
+#define _WARN_H_
+
+#ifdef HAVE_ERR_H
+#include <err.h>
+#else
+#define NEED_WARN_PROGNAME
+const char * warn_progname;
+void warn(const char *, ...);
+void warnx(const char *, ...);
+#endif
+
+#endif /* !_WARN_H_ */