X-Git-Url: http://git.bytex64.net/?a=blobdiff_plain;f=builddeps%2Fscrypt-1.1.6%2Flib%2Fscryptenc%2Fscryptenc.c;fp=builddeps%2Fscrypt-1.1.6%2Flib%2Fscryptenc%2Fscryptenc.c;h=3b7fd0f3f0854b753929bdcd6e5d793c9b99067b;hb=46a8b671b3c707db689868d9b6544d272aa711a7;hp=0000000000000000000000000000000000000000;hpb=e35e2482b85c6e7bbac334a8496472a8b7b0d170;p=blerg.git diff --git a/builddeps/scrypt-1.1.6/lib/scryptenc/scryptenc.c b/builddeps/scrypt-1.1.6/lib/scryptenc/scryptenc.c new file mode 100644 index 0000000..3b7fd0f --- /dev/null +++ b/builddeps/scrypt-1.1.6/lib/scryptenc/scryptenc.c @@ -0,0 +1,606 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#include "scrypt_platform.h" + +#include +#include +#include +#include +#include +#include + +#include + +#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); +}