summaryrefslogtreecommitdiff
path: root/lib/scryptenc/scryptenc.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/scryptenc/scryptenc.c')
-rw-r--r--lib/scryptenc/scryptenc.c605
1 files changed, 0 insertions, 605 deletions
diff --git a/lib/scryptenc/scryptenc.c b/lib/scryptenc/scryptenc.c
deleted file mode 100644
index cf091bf..0000000
--- a/lib/scryptenc/scryptenc.c
+++ /dev/null
@@ -1,605 +0,0 @@
-/*-
- * 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 <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);
-}