Index: third_party/scrypt/lib/scryptenc/scryptenc.c |
=================================================================== |
--- third_party/scrypt/lib/scryptenc/scryptenc.c (revision 175254) |
+++ third_party/scrypt/lib/scryptenc/scryptenc.c (working copy) |
@@ -1,606 +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 "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); |
-} |