Import scrypt-1.1.6.tgz with SHA-256
dfd0d1a544439265bbb9b58043ad3c8ce50a3987b44a61b1d39fd7a3ed5b7fb8
This commit is contained in:
parent
b490e825f3
commit
1acdffde66
30 changed files with 13307 additions and 0 deletions
6
lib/README
Normal file
6
lib/README
Normal 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
124
lib/crypto/crypto_aesctr.c
Normal 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);
|
||||
}
|
59
lib/crypto/crypto_aesctr.h
Normal file
59
lib/crypto/crypto_aesctr.h
Normal 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_ */
|
338
lib/crypto/crypto_scrypt-nosse.c
Normal file
338
lib/crypto/crypto_scrypt-nosse.c
Normal 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);
|
||||
}
|
284
lib/crypto/crypto_scrypt-ref.c
Normal file
284
lib/crypto/crypto_scrypt-ref.c
Normal 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);
|
||||
}
|
366
lib/crypto/crypto_scrypt-sse.c
Normal file
366
lib/crypto/crypto_scrypt-sse.c
Normal 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);
|
||||
}
|
46
lib/crypto/crypto_scrypt.h
Normal file
46
lib/crypto/crypto_scrypt.h
Normal 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
412
lib/crypto/sha256.c
Normal 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
62
lib/crypto/sha256.h
Normal 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
606
lib/scryptenc/scryptenc.c
Normal 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
112
lib/scryptenc/scryptenc.h
Normal 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_ */
|
185
lib/scryptenc/scryptenc_cpuperf.c
Normal file
185
lib/scryptenc/scryptenc_cpuperf.c
Normal 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);
|
||||
}
|
39
lib/scryptenc/scryptenc_cpuperf.h
Normal file
39
lib/scryptenc/scryptenc_cpuperf.h
Normal 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
302
lib/util/memlimit.c
Normal 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
42
lib/util/memlimit.h
Normal 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
143
lib/util/readpass.c
Normal 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
45
lib/util/readpass.h
Normal 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
140
lib/util/sysendian.h
Normal 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
75
lib/util/warn.c
Normal 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
13
lib/util/warn.h
Normal 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_ */
|
Reference in a new issue