Import scrypt-1.1.6.tgz with SHA-256

dfd0d1a544439265bbb9b58043ad3c8ce50a3987b44a61b1d39fd7a3ed5b7fb8
This commit is contained in:
Chris Oei 2012-09-02 11:29:39 -07:00
parent b490e825f3
commit 1acdffde66
30 changed files with 13307 additions and 0 deletions

6
lib/README Normal file
View file

@ -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.

124
lib/crypto/crypto_aesctr.c Normal file
View file

@ -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);
}

View file

@ -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_ */

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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_ */

412
lib/crypto/sha256.c Normal file
View file

@ -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));
}

62
lib/crypto/sha256.h Normal file
View file

@ -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_ */

606
lib/scryptenc/scryptenc.c Normal file
View file

@ -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);
}

112
lib/scryptenc/scryptenc.h Normal file
View file

@ -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_ */

View file

@ -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);
}

View file

@ -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_ */

302
lib/util/memlimit.c Normal file
View file

@ -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);
}

42
lib/util/memlimit.h Normal file
View file

@ -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_ */

143
lib/util/readpass.c Normal file
View file

@ -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);
}

45
lib/util/readpass.h Normal file
View file

@ -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_ */

140
lib/util/sysendian.h Normal file
View file

@ -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_ */

75
lib/util/warn.c Normal file
View file

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

13
lib/util/warn.h Normal file
View file

@ -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_ */