diff --git a/Makefile.in b/Makefile.in index 4cbaf49..7300c39 100644 --- a/Makefile.in +++ b/Makefile.in @@ -26,9 +26,10 @@ MAINSRCS = main.c utils/utils.c allocator.c zlib_compress.c bzip2_compress.c \ lzma_compress.c ppmd_compress.c adaptive_compress.c lzfx_compress.c \ lz4_compress.c none_compress.c utils/xxhash.c utils/heapq.c utils/cpuid.c \ crypto/aes/crypto_aes.c crypto/scrypt/crypto_scrypt-nosse.c \ - crypto/scrypt/sha256.c crypto/scrypt/crypto_aesctr.c + crypto/scrypt/sha256.c crypto/scrypt/crypto_aesctr.c crypto/crypto_utils.c MAINHDRS = allocator.h pcompress.h utils/utils.h utils/xxhash.h utils/heapq.h \ - utils/cpuid.h + utils/cpuid.h crypto/crypto_utils.h crypto/scrypt/crypto_scrypt.h \ + crypto/scrypt/sha256.h crypto/scrypt/crypto_aesctr.h crypto/aes/crypto_aes.h MAINOBJS = $(MAINSRCS:.c=.o) RABINSRCS = rabin/rabin_dedup.c @@ -92,13 +93,13 @@ LIBBSCGEN_OPT = -fopenmp LIBBSCCPPFLAGS = -I$(LIBBSCDIR)/libbsc -DENABLE_PC_LIBBSC BAKFILES = *~ lzma/*~ lzfx/*~ lz4/*~ rabin/*~ bsdiff/*~ lzp/*~ utils/*~ crypto/sha2/*~ \ - crypto/sha2/intel/*~ crypto/aes/*~ crypto/scrypt/*~ + crypto/sha2/intel/*~ crypto/aes/*~ crypto/scrypt/*~ crypto/*~ RM = rm -f COMMON_CPPFLAGS = -I. -I./lzma -I./lzfx -I./lz4 -I./rabin -I./bsdiff -DNODEFAULT_PROPS \ -DFILE_OFFSET_BITS=64 -D_REENTRANT -D__USE_SSE_INTRIN__ -D_LZMA_PROB32 \ -I./lzp @LIBBSCCPPFLAGS@ -I./crypto/skein -I./utils -I@OPENSSL_INCDIR@ \ - -I./crypto/sha2 -I./crypto/scrypt -I./crypto/aes @KEYLEN@ + -I./crypto/sha2 -I./crypto/scrypt -I./crypto/aes -I./crypto @KEYLEN@ COMMON_VEC_FLAGS = -ftree-vectorize COMMON_LOOP_OPTFLAGS = $(VEC_FLAGS) -floop-interchange -floop-block LDLIBS = -ldl -lbz2 $(ZLIB_DIR) -lz -lm @LIBBSCLFLAGS@ -L@OPENSSL_LIBDIR@ -lcrypto -lrt diff --git a/crypto/aes/crypto_aes.c b/crypto/aes/crypto_aes.c index f16f806..109e549 100644 --- a/crypto/aes/crypto_aes.c +++ b/crypto/aes/crypto_aes.c @@ -107,11 +107,11 @@ aes_init(aes_ctx_t *ctx, uchar_t *salt, int saltlen, uchar_t *pwd, int pwd_len, uint64_t nonce, int enc) { int rv; - uchar_t key[KEYLEN]; struct timespec tp; uint64_t tv; uchar_t num[25]; uchar_t IV[32]; + uchar_t *key = ctx->pkey; #ifndef _USE_PBK int logN; @@ -153,8 +153,6 @@ aes_init(aes_ctx_t *ctx, uchar_t *salt, int saltlen, uchar_t *pwd, int pwd_len, ctx->nonce = nonce; AES_set_encrypt_key(key, (KEYLEN << 3), &(ctx->key)); } - - memset(key, 0, KEYLEN); return (0); } @@ -210,6 +208,12 @@ aes_nonce(aes_ctx_t *ctx) return (ctx->nonce); } +void +aes_clean_pkey(aes_ctx_t *ctx) +{ + memset(ctx->pkey, 0, KEYLEN); +} + void aes_cleanup(aes_ctx_t *ctx) { diff --git a/crypto/aes/crypto_aes.h b/crypto/aes/crypto_aes.h index 47e85b6..b947a11 100644 --- a/crypto/aes/crypto_aes.h +++ b/crypto/aes/crypto_aes.h @@ -43,6 +43,7 @@ extern "C" { typedef struct { uint64_t nonce; AES_KEY key; + uchar_t pkey[KEYLEN]; } aes_ctx_t; int aes_init(aes_ctx_t *ctx, uchar_t *salt, int saltlen, uchar_t *pwd, int pwd_len, @@ -50,6 +51,7 @@ int aes_init(aes_ctx_t *ctx, uchar_t *salt, int saltlen, uchar_t *pwd, int pwd_l int aes_encrypt(aes_ctx_t *ctx, uchar_t *plaintext, uchar_t *ciphertext, ssize_t len, uint64_t id); int aes_decrypt(aes_ctx_t *ctx, uchar_t *ciphertext, uchar_t *plaintext, ssize_t len, uint64_t id); uint64_t aes_nonce(aes_ctx_t *ctx); +void aes_clean_pkey(aes_ctx_t *ctx); void aes_cleanup(aes_ctx_t *ctx); #ifdef __cplusplus diff --git a/crypto/crypto_utils.c b/crypto/crypto_utils.c new file mode 100644 index 0000000..85b51ed --- /dev/null +++ b/crypto/crypto_utils.c @@ -0,0 +1,602 @@ +/* + * This file is a part of Pcompress, a chunked parallel multi- + * algorithm lossless compression and decompression program. + * + * Copyright (C) 2012 Moinak Ghosh. All rights reserved. + * Use is subject to license terms. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * moinakg@belenix.org, http://moinakg.wordpress.com/ + * + * This program includes partly-modified public domain source + * code from the LZMA SDK: http://www.7-zip.org/sdk.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "crypto_utils.h" +#include "cpuid.h" + +#define PROVIDER_OPENSSL 0 +#define PROVIDER_X64_OPT 1 + +static void init_sha256(void); +static int geturandom_bytes(uchar_t rbytes[32]); +/* + * Checksum properties + */ +typedef void (*ckinit_func_ptr)(void); +static struct { + char *name; + cksum_t cksum_id; + int bytes, mac_bytes; + ckinit_func_ptr init_func; +} cksum_props[] = { + {"CRC64", CKSUM_CRC64, 8, 32, NULL}, + {"SKEIN256", CKSUM_SKEIN256, 32, 32, NULL}, + {"SKEIN512", CKSUM_SKEIN512, 64, 64, NULL}, + {"SHA256", CKSUM_SHA256, 32, 32, init_sha256}, + {"SHA512", CKSUM_SHA512, 64, 64, NULL} +}; + +static int cksum_provider = PROVIDER_OPENSSL, ossl_inited = 0; + +extern uint64_t lzma_crc64(const uint8_t *buf, size_t size, uint64_t crc); +extern uint64_t lzma_crc64_8bchk(const uint8_t *buf, size_t size, + uint64_t crc, uint64_t *cnt); + +int +compute_checksum(uchar_t *cksum_buf, int cksum, uchar_t *buf, ssize_t bytes) +{ + if (cksum == CKSUM_CRC64) { + uint64_t *ck = (uint64_t *)cksum_buf; + *ck = lzma_crc64(buf, bytes, 0); + + } else if (cksum == CKSUM_SKEIN256) { + Skein_512_Ctxt_t ctx; + + Skein_512_Init(&ctx, 256); + Skein_512_Update(&ctx, buf, bytes); + Skein_512_Final(&ctx, cksum_buf); + + } else if (cksum == CKSUM_SKEIN512) { + Skein_512_Ctxt_t ctx; + + Skein_512_Init(&ctx, 512); + Skein_512_Update(&ctx, buf, bytes); + Skein_512_Final(&ctx, cksum_buf); + + } else if (cksum == CKSUM_SHA256) { + if (cksum_provider == PROVIDER_OPENSSL) { + SHA256_CTX ctx; + + SHA256_Init(&ctx); + SHA256_Update(&ctx, buf, bytes); + SHA256_Final(cksum_buf, &ctx); + } else { + SHA256_Context ctx; + + opt_SHA256_Init(&ctx); + opt_SHA256_Update(&ctx, buf, bytes); + opt_SHA256_Final(&ctx, cksum_buf); + } + } else if (cksum == CKSUM_SHA512) { + SHA512_CTX ctx; + + SHA512_Init(&ctx); + SHA512_Update(&ctx, buf, bytes); + SHA512_Final(cksum_buf, &ctx); + } else { + return (-1); + } + return (0); +} + +static void +init_sha256(void) +{ +#ifdef WORDS_BIGENDIAN + cksum_provider = PROVIDER_OPENSSL; +#else +#ifdef __x86_64__ + processor_info_t pc; + + cksum_provider = PROVIDER_OPENSSL; + cpuid_basic_identify(&pc); + if (pc.proc_type == PROC_X64_INTEL || pc.proc_type == PROC_X64_AMD) { + if (opt_Init_SHA(&pc) == 0) { + cksum_provider = PROVIDER_X64_OPT; + } + } +#endif +#endif +} + +/* + * Check is either the given checksum name or id is valid and + * return it's properties. + */ +int +get_checksum_props(char *name, int *cksum, int *cksum_bytes, int *mac_bytes) +{ + int i; + + for (i=0; i0; i--) { + buf[j] = checksum[i-1]; + j++; + } +} + +void +deserialize_checksum(uchar_t *checksum, uchar_t *buf, int cksum_bytes) +{ + int i,j; + + j = 0; + for (i=cksum_bytes; i>0; i--) { + checksum[i-1] = buf[j]; + j++; + } +} + +int +hmac_init(mac_ctx_t *mctx, int cksum, crypto_ctx_t *cctx) +{ + aes_ctx_t *actx = (aes_ctx_t *)(cctx->crypto_ctx); + mctx->mac_cksum = cksum; + + if (cksum == CKSUM_SKEIN256) { + Skein_512_Ctxt_t *ctx = malloc(sizeof (Skein_512_Ctxt_t)); + if (!ctx) return (-1); + Skein_512_InitExt(ctx, 256, SKEIN_CFG_TREE_INFO_SEQUENTIAL, + actx->pkey, KEYLEN); + mctx->mac_ctx = ctx; + ctx = malloc(sizeof (Skein_512_Ctxt_t)); + if (!ctx) { + free(mctx->mac_ctx); + return (-1); + } + memcpy(ctx, mctx->mac_ctx, sizeof (Skein_512_Ctxt_t)); + mctx->mac_ctx_reinit = ctx; + + } else if (cksum == CKSUM_SKEIN512) { + Skein_512_Ctxt_t *ctx = malloc(sizeof (Skein_512_Ctxt_t)); + if (!ctx) return (-1); + Skein_512_InitExt(ctx, 512, SKEIN_CFG_TREE_INFO_SEQUENTIAL, + actx->pkey, KEYLEN); + mctx->mac_ctx = ctx; + ctx = malloc(sizeof (Skein_512_Ctxt_t)); + if (!ctx) { + free(mctx->mac_ctx); + return (-1); + } + memcpy(ctx, mctx->mac_ctx, sizeof (Skein_512_Ctxt_t)); + mctx->mac_ctx_reinit = ctx; + + } else if (cksum == CKSUM_SHA256 || cksum == CKSUM_CRC64) { + if (cksum_provider == PROVIDER_OPENSSL) { + HMAC_CTX *ctx = malloc(sizeof (HMAC_CTX)); + if (!ctx) return (-1); + HMAC_CTX_init(ctx); + HMAC_Init_ex(ctx, actx->pkey, KEYLEN, EVP_sha256(), NULL); + mctx->mac_ctx = ctx; + + ctx = malloc(sizeof (HMAC_CTX)); + if (!ctx) { + free(mctx->mac_ctx); + return (-1); + } + if (!HMAC_CTX_copy(ctx, mctx->mac_ctx)) { + free(ctx); + free(mctx->mac_ctx); + return (-1); + } + mctx->mac_ctx_reinit = ctx; + } else { + HMAC_SHA256_Context *ctx = malloc(sizeof (HMAC_SHA256_Context)); + if (!ctx) return (-1); + opt_HMAC_SHA256_Init(ctx, actx->pkey, KEYLEN); + mctx->mac_ctx = ctx; + + ctx = malloc(sizeof (HMAC_SHA256_Context)); + if (!ctx) { + free(mctx->mac_ctx); + return (-1); + } + memcpy(ctx, mctx->mac_ctx, sizeof (HMAC_SHA256_Context)); + mctx->mac_ctx_reinit = ctx; + } + } else if (cksum == CKSUM_SHA512) { + HMAC_CTX *ctx = malloc(sizeof (HMAC_CTX)); + if (!ctx) return (-1); + HMAC_CTX_init(ctx); + HMAC_Init_ex(ctx, actx->pkey, KEYLEN, EVP_sha512(), NULL); + mctx->mac_ctx = ctx; + + ctx = malloc(sizeof (HMAC_CTX)); + if (!ctx) { + free(mctx->mac_ctx); + return (-1); + } + if (!HMAC_CTX_copy(ctx, mctx->mac_ctx)) { + free(ctx); + free(mctx->mac_ctx); + return (-1); + } + mctx->mac_ctx_reinit = ctx; + } else { + return (-1); + } + return (0); +} + +int +hmac_reinit(mac_ctx_t *mctx) +{ + int cksum = mctx->mac_cksum; + + if (cksum == CKSUM_SKEIN256 || cksum == CKSUM_SKEIN512) { + memcpy(mctx->mac_ctx, mctx->mac_ctx_reinit, sizeof (Skein_512_Ctxt_t)); + + } else if (cksum == CKSUM_SHA256 || cksum == CKSUM_CRC64) { + if (cksum_provider == PROVIDER_OPENSSL) { + HMAC_CTX_copy(mctx->mac_ctx, mctx->mac_ctx_reinit); + } else { + memcpy(mctx->mac_ctx, mctx->mac_ctx_reinit, sizeof (HMAC_SHA256_Context)); + } + } else if (cksum == CKSUM_SHA512) { + HMAC_CTX_copy(mctx->mac_ctx, mctx->mac_ctx_reinit); + } else { + return (-1); + } + return (0); +} + +int +hmac_update(mac_ctx_t *mctx, uchar_t *data, size_t len) +{ + int cksum = mctx->mac_cksum; + + if (cksum == CKSUM_SKEIN256 || cksum == CKSUM_SKEIN512) { + Skein_512_Update(mctx->mac_ctx, data, len); + + } else if (cksum == CKSUM_SHA256 || cksum == CKSUM_CRC64) { + if (cksum_provider == PROVIDER_OPENSSL) { + if (HMAC_Update(mctx->mac_ctx, data, len) == 0) + return (-1); + } else { + opt_HMAC_SHA256_Update(mctx->mac_ctx, data, len); + } + } else if (cksum == CKSUM_SHA512) { + if (HMAC_Update(mctx->mac_ctx, data, len) == 0) + return (-1); + } else { + return (-1); + } + return (0); +} + +int +hmac_final(mac_ctx_t *mctx, uchar_t *hash, unsigned int *len) +{ + int cksum = mctx->mac_cksum; + + if (cksum == CKSUM_SKEIN256) { + Skein_512_Final(mctx->mac_ctx, hash); + *len = 32; + + } else if (cksum == CKSUM_SKEIN512) { + Skein_512_Final(mctx->mac_ctx, hash); + *len = 64; + + } else if (cksum == CKSUM_SHA256 || cksum == CKSUM_CRC64) { + if (cksum_provider == PROVIDER_OPENSSL) { + HMAC_Final(mctx->mac_ctx, hash, len); + } else { + opt_HMAC_SHA256_Final(mctx->mac_ctx, hash); + *len = 32; + } + } else if (cksum == CKSUM_SHA512) { + HMAC_Final(mctx->mac_ctx, hash, len); + } else { + return (-1); + } + return (0); +} + +int +hmac_cleanup(mac_ctx_t *mctx) +{ + int cksum = mctx->mac_cksum; + + if (cksum == CKSUM_SKEIN256 || cksum == CKSUM_SKEIN512) { + memset(mctx->mac_ctx, 0, sizeof (Skein_512_Ctxt_t)); + memset(mctx->mac_ctx_reinit, 0, sizeof (Skein_512_Ctxt_t)); + + } else if (cksum == CKSUM_SHA256 || cksum == CKSUM_CRC64) { + if (cksum_provider == PROVIDER_OPENSSL) { + HMAC_CTX_cleanup(mctx->mac_ctx); + HMAC_CTX_cleanup(mctx->mac_ctx_reinit); + } else { + memset(mctx->mac_ctx, 0, sizeof (HMAC_SHA256_Context)); + memset(mctx->mac_ctx_reinit, 0, sizeof (HMAC_SHA256_Context)); + } + } else if (cksum == CKSUM_SHA512) { + HMAC_CTX_cleanup(mctx->mac_ctx); + HMAC_CTX_cleanup(mctx->mac_ctx_reinit); + } else { + return (-1); + } + mctx->mac_cksum = 0; + free(mctx->mac_ctx); + free(mctx->mac_ctx_reinit); + return (0); +} + +int +init_crypto(crypto_ctx_t *cctx, uchar_t *pwd, int pwd_len, int crypto_alg, + uchar_t *salt, int saltlen, uint64_t nonce, int enc_dec) +{ + if (crypto_alg == CRYPTO_ALG_AES) { + aes_ctx_t *actx = malloc(sizeof (aes_ctx_t)); + + if (enc_dec) { + /* + * Encryption init. + */ + cctx->salt = malloc(32); + salt = cctx->salt; + cctx->saltlen = 32; + if (RAND_status() != 1 || RAND_bytes(salt, 32) != 1) { + if (geturandom_bytes(salt) != 0) { + uchar_t sb[64]; + int b; + struct timespec tp; + + b = 0; + /* No good random pool is populated/available. What to do ? */ + if (clock_gettime(CLOCK_MONOTONIC, &tp) == -1) { + time((time_t *)&sb[b]); + b += 8; + } else { + uint64_t v; + v = tp.tv_sec * 1000UL + tp.tv_nsec; + *((uint64_t *)&sb[b]) = v; + b += 8; + } + *((uint32_t *)&sb[b]) = rand(); + b += 4; + *((uint32_t *)&sb[b]) = getpid(); + b += 4; + compute_checksum(&sb[b], CKSUM_SHA256, sb, b); + b = 8 + 4; + *((uint32_t *)&sb[b]) = rand(); + compute_checksum(salt, CKSUM_SHA256, &sb[b], 32 + 4); + } + } + + /* + * Zero nonce (arg #6) since it will be generated. + */ + if (aes_init(actx, salt, 32, pwd, pwd_len, 0, enc_dec) != 0) { + fprintf(stderr, "Failed to initialize AES context\n"); + return (-1); + } + } else { + /* + * Decryption init. + * Pass given nonce and salt. + */ + if (saltlen > MAX_SALTLEN) { + fprintf(stderr, "Salt too long. Max allowed length is %d\n", + MAX_SALTLEN); + return (-1); + } + cctx->salt = malloc(saltlen); + memcpy(cctx->salt, salt, saltlen); + + if (aes_init(actx, cctx->salt, saltlen, pwd, pwd_len, nonce, + enc_dec) != 0) { + fprintf(stderr, "Failed to initialize AES context\n"); + return (-1); + } + } + cctx->crypto_ctx = actx; + cctx->crypto_alg = crypto_alg; + cctx->enc_dec = enc_dec; + } else { + fprintf(stderr, "Unrecognized algorithm code: %d\n", crypto_alg); + return (-1); + } + return (0); +} + +int +crypto_buf(crypto_ctx_t *cctx, uchar_t *from, uchar_t *to, ssize_t bytes, uint64_t id) +{ + if (cctx->crypto_alg == CRYPTO_ALG_AES) { + if (cctx->enc_dec == ENCRYPT_FLAG) { + return (aes_encrypt(cctx->crypto_ctx, from, to, bytes, id)); + } else { + return (aes_decrypt(cctx->crypto_ctx, from, to, bytes, id)); + } + } else { + fprintf(stderr, "Unrecognized algorithm code: %d\n", cctx->crypto_alg); + return (-1); + } + return (0); +} + +uint64_t +crypto_nonce(crypto_ctx_t *cctx) +{ + return (aes_nonce(cctx->crypto_ctx)); +} + +void +crypto_clean_pkey(crypto_ctx_t *cctx) +{ + aes_clean_pkey(cctx->crypto_ctx); +} + +void +cleanup_crypto(crypto_ctx_t *cctx) +{ + aes_cleanup(cctx->crypto_ctx); + memset(cctx->salt, 0, 32); + free(cctx->salt); + free(cctx); +} + +static int +geturandom_bytes(uchar_t rbytes[32]) +{ + int fd; + ssize_t lenread; + uchar_t * buf = rbytes; + 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); +} + +int +get_pw_string(char pw[MAX_PW_LEN], char *prompt) +{ + int fd, len; + FILE *input, *strm; + struct termios oldt, newt; + uchar_t pw1[MAX_PW_LEN], pw2[MAX_PW_LEN], *s; + + // Try TTY first + fd = open("/dev/tty", O_RDWR | O_NOCTTY); + if (fd != -1) { + input = fdopen(fd, "w+"); + strm = input; + } else { + // Fall back to stdin + fd = STDIN_FILENO; + input = stdin; + strm = stderr; + } + tcgetattr(fd, &oldt); + newt = oldt; + newt.c_lflag &= ~ECHO; + tcsetattr(fd, TCSANOW, &newt); + + fprintf(stderr, "%s: ", prompt); + fflush(stderr); + s = fgets(pw1, MAX_PW_LEN, input); + fputs("\n", stderr); + + if (s == NULL) { + tcsetattr(fd, TCSANOW, &oldt); + fflush(strm); + return (-1); + } + + fprintf(stderr, "%s (once more): ", prompt); + fflush(stderr); + s = fgets(pw2, MAX_PW_LEN, input); + tcsetattr(fd, TCSANOW, &oldt); + fflush(strm); + fputs("\n", stderr); + + if (s == NULL) { + return (-1); + } + + if (strcmp(pw1, pw2) != 0) { + fprintf(stderr, "Passwords do not match!\n"); + memset(pw1, 0, MAX_PW_LEN); + memset(pw2, 0, MAX_PW_LEN); + return (-1); + } + + len = strlen(pw1); + pw1[len-1] = '\0'; + strcpy(pw, pw1); + memset(pw1, 0, MAX_PW_LEN); + memset(pw2, 0, MAX_PW_LEN); + return (len); +} diff --git a/crypto/crypto_utils.h b/crypto/crypto_utils.h new file mode 100644 index 0000000..2fc6133 --- /dev/null +++ b/crypto/crypto_utils.h @@ -0,0 +1,102 @@ +/* + * This file is a part of Pcompress, a chunked parallel multi- + * algorithm lossless compression and decompression program. + * + * Copyright (C) 2012 Moinak Ghosh. All rights reserved. + * Use is subject to license terms. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * moinakg@belenix.org, http://moinakg.wordpress.com/ + * + * This program includes partly-modified public domain source + * code from the LZMA SDK: http://www.7-zip.org/sdk.html + */ + +#ifndef _CRYPTO_UTILS_H +#define _CRYPTO_UTILS_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_PW_LEN 16 +#define CKSUM_MASK 0x700 +#define CKSUM_MAX_BYTES 64 +#define DEFAULT_CKSUM "SKEIN256" + +#define ENCRYPT_FLAG 1 +#define DECRYPT_FLAG 0 +#define CRYPTO_ALG_AES 0x10 +#define MAX_SALTLEN 64 + +/* + * Public checksum properties. CKSUM_MAX_BYTES must be updated if a + * newer larger checksum is added to the list. + */ +typedef enum { + CKSUM_CRC64 = 0x100, + CKSUM_SKEIN256 = 0x200, + CKSUM_SKEIN512 = 0x300, + CKSUM_SHA256 = 0x400, + CKSUM_SHA512 = 0x500 +} cksum_t; + +typedef struct { + void *crypto_ctx; + int crypto_alg; + int enc_dec; + uchar_t *salt; + int saltlen; +} crypto_ctx_t; + +typedef struct { + void *mac_ctx; + void *mac_ctx_reinit; + int mac_cksum; +} mac_ctx_t; + +/* + * Generic message digest functions. + */ +int compute_checksum(uchar_t *cksum_buf, int cksum, uchar_t *buf, ssize_t bytes); +int get_checksum_props(char *name, int *cksum, int *cksum_bytes, int *mac_bytes); +void serialize_checksum(uchar_t *checksum, uchar_t *buf, int cksum_bytes); +void deserialize_checksum(uchar_t *checksum, uchar_t *buf, int cksum_bytes); + +/* + * Encryption related functions. + */ +int init_crypto(crypto_ctx_t *cctx, uchar_t *pwd, int pwd_len, int crypto_alg, + uchar_t *salt, int saltlen, uint64_t nonce, int enc_dec); +int crypto_buf(crypto_ctx_t *cctx, uchar_t *from, uchar_t *to, ssize_t bytes, uint64_t id); +uint64_t crypto_nonce(crypto_ctx_t *cctx); +void crypto_clean_pkey(crypto_ctx_t *cctx); +void cleanup_crypto(crypto_ctx_t *cctx); +int get_pw_string(char pw[MAX_PW_LEN], char *prompt); + +/* + * HMAC functions. + */ +int hmac_init(mac_ctx_t *mctx, int cksum, crypto_ctx_t *cctx); +int hmac_reinit(mac_ctx_t *mctx); +int hmac_update(mac_ctx_t *mctx, uchar_t *data, size_t len); +int hmac_cleanup(mac_ctx_t *mctx); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/crypto/sha2/sha256.c b/crypto/sha2/sha256.c index 3a390d2..e0c3a99 100644 --- a/crypto/sha2/sha256.c +++ b/crypto/sha2/sha256.c @@ -105,7 +105,7 @@ static void _init (SHA256_Context *sc, const uint32_t iv[SHA256_HASH_WORDS]) { int i; - + /* * SHA256_HASH_WORDS is 8, must be 8, cannot be anything but 8! * So we unroll a loop here. @@ -118,7 +118,7 @@ _init (SHA256_Context *sc, const uint32_t iv[SHA256_HASH_WORDS]) sc->hash[5] = iv[5]; sc->hash[6] = iv[6]; sc->hash[7] = iv[7]; - + sc->totalLength = 0LL; sc->bufferLength = 0L; } @@ -130,26 +130,26 @@ APS_NAMESPACE(SHA256_Init) (SHA256_Context *sc) } void -APS_NAMESPACE(SHA256_Update) (SHA256_Context *sc, void *vdata, size_t len) +APS_NAMESPACE(SHA256_Update) (SHA256_Context *sc, const void *vdata, size_t len) { const uint8_t *data = vdata; uint32_t bufferBytesLeft; size_t bytesToCopy; int rem; - + if (sc->bufferLength) { do { bufferBytesLeft = 64L - sc->bufferLength; bytesToCopy = bufferBytesLeft; if (bytesToCopy > len) bytesToCopy = len; - + memcpy (&sc->buffer.bytes[sc->bufferLength], data, bytesToCopy); sc->totalLength += bytesToCopy * 8L; sc->bufferLength += bytesToCopy; data += bytesToCopy; len -= bytesToCopy; - + if (sc->bufferLength == 64L) { sc->blocks = 1; sha_update_func(sc->buffer.words, sc->hash, sc->blocks); @@ -160,12 +160,12 @@ APS_NAMESPACE(SHA256_Update) (SHA256_Context *sc, void *vdata, size_t len) } while (len > 0 && len <= 64L); if (!len) return; } - + sc->blocks = len >> 6; rem = len - (sc->blocks << 6); len = sc->blocks << 6; sc->totalLength += rem * 8L; - + if (len) { sc->totalLength += len * 8L; sha_update_func((uint32_t *)data, sc->hash, sc->blocks); @@ -182,16 +182,16 @@ _final (SHA256_Context *sc, uint8_t *hash, int hashWords) uint32_t bytesToPad; uint64_t lengthPad; int i; - + bytesToPad = 120L - sc->bufferLength; if (bytesToPad > 64L) bytesToPad -= 64L; - + lengthPad = BYTESWAP64(sc->totalLength); - + APS_NAMESPACE(SHA256_Update) (sc, padding, bytesToPad); APS_NAMESPACE(SHA256_Update) (sc, &lengthPad, 8L); - + if (hash) { for (i = 0; i < hashWords; i++) { hash[0] = (uint8_t) (sc->hash[i] >> 24); @@ -208,3 +208,66 @@ APS_NAMESPACE(SHA256_Final) (SHA256_Context *sc, uint8_t hash[SHA256_HASH_SIZE]) { _final (sc, hash, SHA256_HASH_WORDS); } + +/* Initialize an HMAC-SHA256 operation with the given key. */ +void +APS_NAMESPACE(HMAC_SHA256_Init) (HMAC_SHA256_Context * 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) { + APS_NAMESPACE(SHA256_Init)(&ctx->ictx); + APS_NAMESPACE(SHA256_Update)(&ctx->ictx, K, Klen); + APS_NAMESPACE(SHA256_Final)(&ctx->ictx, khash); + K = khash; + Klen = 32; + } + + /* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */ + APS_NAMESPACE(SHA256_Init)(&ctx->ictx); + memset(pad, 0x36, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + APS_NAMESPACE(SHA256_Update)(&ctx->ictx, pad, 64); + + /* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */ + APS_NAMESPACE(SHA256_Init)(&ctx->octx); + memset(pad, 0x5c, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + APS_NAMESPACE(SHA256_Update)(&ctx->octx, pad, 64); + + /* Clean the stack. */ + memset(khash, 0, 32); +} + +/* Add bytes to the HMAC-SHA256 operation. */ +void +APS_NAMESPACE(HMAC_SHA256_Update) (HMAC_SHA256_Context * ctx, const void *in, size_t len) +{ + /* Feed data to the inner SHA256 operation. */ + APS_NAMESPACE(SHA256_Update)(&ctx->ictx, in, len); +} + +/* Finish an HMAC-SHA256 operation. */ +void +APS_NAMESPACE(HMAC_SHA256_Final) (HMAC_SHA256_Context * ctx, unsigned char digest[32]) +{ + unsigned char ihash[32]; + + /* Finish the inner SHA256 operation. */ + APS_NAMESPACE(SHA256_Final)(&ctx->ictx, ihash); + + /* Feed the inner hash to the outer SHA256 operation. */ + APS_NAMESPACE(SHA256_Update)(&ctx->octx, ihash, 32); + + /* Finish the outer SHA256 operation. */ + APS_NAMESPACE(SHA256_Final)(&ctx->octx, digest); + + /* Clean the stack. */ + memset(ihash, 0, 32); +} diff --git a/crypto/sha2/sha256.h b/crypto/sha2/sha256.h index b6cd082..53ca362 100644 --- a/crypto/sha2/sha256.h +++ b/crypto/sha2/sha256.h @@ -53,6 +53,11 @@ typedef struct _SHA256_Context { } buffer; } SHA256_Context; +typedef struct HMAC_SHA256Context { + SHA256_Context ictx; + SHA256_Context octx; +} HMAC_SHA256_Context; + #ifdef __cplusplus extern "C" { #endif @@ -62,10 +67,14 @@ extern "C" { #endif /* !APS_NAMESPACE */ void APS_NAMESPACE(SHA256_Init) (SHA256_Context *sc); -void APS_NAMESPACE(SHA256_Update) (SHA256_Context *sc, void *data, size_t len); +void APS_NAMESPACE(SHA256_Update) (SHA256_Context *sc, const void *data, size_t len); void APS_NAMESPACE(SHA256_Final) (SHA256_Context *sc, uint8_t hash[SHA256_HASH_SIZE]); int APS_NAMESPACE(Init_SHA) (processor_info_t *pc); +void APS_NAMESPACE(HMAC_SHA256_Init) (HMAC_SHA256_Context * ctx, const void * _K, size_t Klen); +void APS_NAMESPACE(HMAC_SHA256_Update) (HMAC_SHA256_Context * ctx, const void *in, size_t len); +void APS_NAMESPACE(HMAC_SHA256_Final) (HMAC_SHA256_Context * ctx, unsigned char digest[32]); + /* * Intel's optimized SHA256 core routines. These routines are described in an * Intel White-Paper: diff --git a/main.c b/main.c index 6c805a4..f724bf9 100644 --- a/main.c +++ b/main.c @@ -51,6 +51,7 @@ * We use 5MB chunks by default. */ #define DEFAULT_CHUNKSIZE (5 * 1024 * 1024) +#define EIGHTY_PCT(x) ((x) - ((x)/5)) struct wdata { struct cmp_data **dary; @@ -88,7 +89,7 @@ static const char *exec_name; static const char *algo = NULL; static int do_compress = 0; static int do_uncompress = 0; -static int cksum_bytes; +static int cksum_bytes, mac_bytes; static int cksum = 0; static int rab_blk_size = 0; static dedupe_context_t *rctx; @@ -291,7 +292,7 @@ redo: goto cont; } - cseg = tdat->compressed_chunk + cksum_bytes; + cseg = tdat->compressed_chunk + cksum_bytes + mac_bytes; _chunksize = tdat->chunksize; deserialize_checksum(tdat->checksum, tdat->compressed_chunk, cksum_bytes); HDR = *cseg; @@ -309,6 +310,8 @@ redo: * Decrypt compressed data if necessary. */ if (encrypt_type) { + uchar_t hmac[CKSUM_MAX_BYTES]; + /* * Encryption algorithm should not change the size and * encryption is in-place. @@ -538,6 +541,25 @@ start_decompress(const char *filename, const char *to_filename) chunksize = ntohll(chunksize); level = ntohl(level); + /* + * Check for ridiculous values (malicious tampering or otherwise). + */ + if (version > VERSION) { + fprintf(stderr, "Cannot handle newer archive version %d, capability %d\n", + version, VERSION); + err = 1; + goto uncomp_done; + } + if (chunksize > EIGHTY_PCT(get_total_ram())) { + fprintf(stderr, "Chunk size must not exceed 80%% of total RAM.\n"); + err = 1; + goto uncomp_done; + } + if (level > MAX_LEVEL || level < 0) { + fprintf(stderr, "Invalid compression level in header: %d\n", level); + err = 1; + goto uncomp_done; + } if (version < VERSION-2) { fprintf(stderr, "Unsupported version: %d\n", version); err = 1; @@ -566,7 +588,7 @@ start_decompress(const char *filename, const char *to_filename) } cksum = flags & CKSUM_MASK; - if (get_checksum_props(NULL, &cksum, &cksum_bytes) == -1) { + if (get_checksum_props(NULL, &cksum, &cksum_bytes, &mac_bytes) == -1) { fprintf(stderr, "Invalid checksum algorithm code: %d. File corrupt ?\n", cksum); UNCOMP_BAIL; } @@ -580,7 +602,13 @@ start_decompress(const char *filename, const char *to_filename) uint64_t nonce; uchar_t pw[MAX_PW_LEN]; int pw_len; + mac_ctx_t hdr_mac; + uchar_t hdr_hash1[mac_bytes], hdr_hash2[mac_bytes]; + unsigned int hlen; + unsigned short d1; + unsigned int d2; + compressed_chunksize += mac_bytes; encrypt_type = flags & MASK_CRYPTO_ALG; if (Read(compfd, &saltlen, sizeof (saltlen)) < sizeof (saltlen)) { perror("Read: "); @@ -606,13 +634,21 @@ start_decompress(const char *filename, const char *to_filename) } nonce = ntohll(nonce); + if (Read(compfd, hdr_hash1, mac_bytes) < mac_bytes) { + memset(salt2, 0, saltlen); + free(salt2); + perror("Read: "); + UNCOMP_BAIL; + } + deserialize_checksum(hdr_hash2, hdr_hash1, mac_bytes); + if (!pwd_file) { pw_len = get_pw_string(pw, "Please enter encryption password"); if (pw_len == -1) { memset(salt2, 0, saltlen); free(salt2); - err_exit(1, "Failed to get password.\n"); + err_exit(0, "Failed to get password.\n"); } } else { int fd, len; @@ -644,21 +680,45 @@ start_decompress(const char *filename, const char *to_filename) perror(" "); memset(salt2, 0, saltlen); free(salt2); - err_exit(1, "Failed to get password.\n"); + err_exit(0, "Failed to get password.\n"); } close(fd); } + if (init_crypto(&crypto_ctx, pw, pw_len, encrypt_type, salt2, saltlen, nonce, DECRYPT_FLAG) == -1) { memset(salt2, 0, saltlen); free(salt2); memset(pw, 0, MAX_PW_LEN); - err_exit(1, "Failed to initialize crypto\n"); + err_exit(0, "Failed to initialize crypto\n"); } memset(salt2, 0, saltlen); free(salt2); nonce = 0; memset(pw, 0, MAX_PW_LEN); + + /* + * Verify header HMAC. + */ + if (hmac_init(&hdr_mac, cksum, &crypto_ctx) == -1) { + err_exit(0, "Cannot initialize header hmac.\n"); + } + hmac_update(&hdr_mac, (uchar_t *)algo, ALGO_SZ); + d1 = htons(version); + hmac_update(&hdr_mac, (uchar_t *)&d1, sizeof (version)); + d1 = htons(flags); + hmac_update(&hdr_mac, (uchar_t *)&d1, sizeof (version)); + nonce = htonll(chunksize); + hmac_update(&hdr_mac, (uchar_t *)&nonce, sizeof (nonce)); + d2 = htonl(level); + hmac_update(&hdr_mac, (uchar_t *)&d2, sizeof (level)); + hmac_final(&hdr_mac, hdr_hash1, &hlen); + hmac_cleanup(&hdr_mac); + if (memcmp(hdr_hash2, hdr_hash1, mac_bytes) != 0) { + err_exit(0, "Header verification failed! File tampered.\n"); + } + } else { + mac_bytes = 0; } nprocs = sysconf(_SC_NPROCESSORS_ONLN); @@ -758,6 +818,15 @@ start_decompress(const char *filename, const char *to_filename) } tdat->len_cmp = htonll(tdat->len_cmp); + /* + * Check for ridiculous length. + */ + if (tdat->len_cmp > chunksize + 256) { + fprintf(stderr, "Compressed length too big for chunk: %d\n", + chunk_num); + UNCOMP_BAIL; + } + /* * Zero compressed len means end of file. */ @@ -799,9 +868,9 @@ start_decompress(const char *filename, const char *to_filename) * Now read compressed chunk including the checksum. */ tdat->rbytes = Read(compfd, tdat->compressed_chunk, - tdat->len_cmp + cksum_bytes + CHUNK_FLAG_SZ); + tdat->len_cmp + cksum_bytes + mac_bytes + CHUNK_FLAG_SZ); if (main_cancel) break; - if (tdat->rbytes < tdat->len_cmp + cksum_bytes + CHUNK_FLAG_SZ) { + if (tdat->rbytes < tdat->len_cmp + cksum_bytes + mac_bytes + CHUNK_FLAG_SZ) { if (tdat->rbytes < 0) { perror("Read: "); UNCOMP_BAIL; @@ -978,6 +1047,7 @@ plain_compress: compressed_chunk, &_chunksize, tdat->level, 0, tdat->data); } } + /* * Sanity check to ensure compressed data is lesser than original. * If at all compression expands/does not shrink data then the chunk @@ -1030,7 +1100,7 @@ plain_compress: serialize_checksum(tdat->checksum, tdat->cmp_seg + sizeof (tdat->len_cmp), cksum_bytes); tdat->len_cmp += CHUNK_FLAG_SZ; tdat->len_cmp += sizeof (len_cmp); - tdat->len_cmp += cksum_bytes; + tdat->len_cmp += (cksum_bytes + mac_bytes); if (adapt_mode) type |= (rv << 4); @@ -1159,6 +1229,7 @@ start_compress(const char *filename, uint64_t chunksize, int level) uchar_t pw[MAX_PW_LEN]; int pw_len; + compressed_chunksize += mac_bytes; if (!pwd_file) { pw_len = get_pw_string(pw, "Please enter encryption password"); @@ -1379,16 +1450,31 @@ start_compress(const char *filename, uint64_t chunksize, int level) } /* - * If encryption is enabled, write the salt and nonce. + * If encryption is enabled, compute header HMAC. Then + * write the salt, nonce and header hmac in that order. */ - pos = cread_buf; if (encrypt_type) { + mac_ctx_t hdr_mac; + uchar_t hdr_hash[mac_bytes]; + unsigned int hlen; + + if (hmac_init(&hdr_mac, cksum, &crypto_ctx) == -1) { + fprintf(stderr, "Cannot initialize header hmac.\n"); + COMP_BAIL; + } + hmac_update(&hdr_mac, cread_buf, pos - cread_buf); + hmac_final(&hdr_mac, hdr_hash, &hlen); + hmac_cleanup(&hdr_mac); + + pos = cread_buf; *((int *)pos) = htonl(crypto_ctx.saltlen); pos += sizeof (int); serialize_checksum(crypto_ctx.salt, pos, crypto_ctx.saltlen); pos += crypto_ctx.saltlen; *((uint64_t *)pos) = htonll(crypto_nonce(&crypto_ctx)); pos += 8; + serialize_checksum(hdr_hash, pos, hlen); + pos += hlen; if (Write(compfd, cread_buf, pos - cread_buf) != pos - cread_buf) { perror("Write "); COMP_BAIL; @@ -1455,7 +1541,8 @@ start_compress(const char *filename, uint64_t chunksize, int level) tdat->cmp_seg = (uchar_t *)slab_alloc(NULL, compressed_chunksize); } - tdat->compressed_chunk = tdat->cmp_seg + COMPRESSED_CHUNKSZ + cksum_bytes; + tdat->compressed_chunk = tdat->cmp_seg + COMPRESSED_CHUNKSZ + + cksum_bytes + mac_bytes; if (!tdat->cmp_seg || !tdat->uncompressed_chunk) { fprintf(stderr, "Out of memory\n"); COMP_BAIL; @@ -1477,7 +1564,8 @@ start_compress(const char *filename, uint64_t chunksize, int level) tmp = tdat->cmp_seg; tdat->cmp_seg = cread_buf; cread_buf = tmp; - tdat->compressed_chunk = tdat->cmp_seg + COMPRESSED_CHUNKSZ + cksum_bytes; + tdat->compressed_chunk = tdat->cmp_seg + COMPRESSED_CHUNKSZ + + cksum_bytes + mac_bytes; /* * If there is data after the last rabin boundary in the chunk, then @@ -1763,11 +1851,14 @@ main(int argc, char *argv[]) if (chunksize < MIN_CHUNK) { err_exit(0, "Minimum chunk size is %ld\n", MIN_CHUNK); } + if (chunksize > EIGHTY_PCT(get_total_ram())) { + err_exit(0, "Chunk size must not exceed 80%% of total RAM.\n"); + } break; case 'l': level = atoi(optarg); - if (level < 0 || level > 14) + if (level < 0 || level > MAX_LEVEL) err_exit(0, "Compression level should be in range 0 - 14\n"); break; @@ -1829,7 +1920,7 @@ main(int argc, char *argv[]) break; case 'S': - if (get_checksum_props(optarg, &cksum, &cksum_bytes) == -1) { + if (get_checksum_props(optarg, &cksum, &cksum_bytes, &mac_bytes) == -1) { err_exit(0, "Invalid checksum type %s", optarg); } break; @@ -1873,6 +1964,7 @@ main(int argc, char *argv[]) if (!do_compress && encrypt_type) { fprintf(stderr, "Encryption only makes sense when compressing!\n"); exit(1); + } else if (pipe_mode && !pwd_file) { fprintf(stderr, "Pipe mode requires password to be provided in a file.\n"); exit(1); @@ -1922,8 +2014,10 @@ main(int argc, char *argv[]) main_cancel = 0; if (cksum == 0) - get_checksum_props(DEFAULT_CKSUM, &cksum, &cksum_bytes); + get_checksum_props(DEFAULT_CKSUM, &cksum, &cksum_bytes, &mac_bytes); + if (!encrypt_type) + mac_bytes = 0; /* * Start the main routines. */ diff --git a/pcompress.h b/pcompress.h index e825ec3..96e76fd 100644 --- a/pcompress.h +++ b/pcompress.h @@ -33,6 +33,7 @@ extern "C" { #endif #include +#include #define CHUNK_FLAG_SZ 1 #define ALGO_SZ 8 @@ -43,6 +44,7 @@ extern "C" { #define FLAG_SINGLE_CHUNK 4 #define UTILITY_VERSION "0.8.6" #define MASK_CRYPTO_ALG 0x30 +#define MAX_LEVEL 14 #define COMPRESSED 1 #define UNCOMPRESSED 0 diff --git a/utils/utils.c b/utils/utils.c index c175547..e39760d 100644 --- a/utils/utils.c +++ b/utils/utils.c @@ -35,44 +35,8 @@ #include #include #include -#include -#include -#include -#include -#include -#include #include "utils.h" -#include "cpuid.h" - -#define PROVIDER_OPENSSL 0 -#define PROVIDER_X64_OPT 1 - -static void init_sha256(void); -static int geturandom_bytes(uchar_t rbytes[32]); -/* - * Checksum properties - */ -typedef void (*ckinit_func_ptr)(void); -static struct { - char *name; - cksum_t cksum_id; - int bytes; - ckinit_func_ptr init_func; -} cksum_props[] = { - {"CRC64", CKSUM_CRC64, 8, NULL}, - {"SKEIN256", CKSUM_SKEIN256, 32, NULL}, - {"SKEIN512", CKSUM_SKEIN512, 64, NULL}, - {"SHA256", CKSUM_SHA256, 32, init_sha256}, - {"SHA512", CKSUM_SHA512, 64, NULL} -}; - - -static int cksum_provider = PROVIDER_OPENSSL, ossl_inited = 0; - -extern uint64_t lzma_crc64(const uint8_t *buf, size_t size, uint64_t crc); -extern uint64_t lzma_crc64_8bchk(const uint8_t *buf, size_t size, - uint64_t crc, uint64_t *cnt); void err_exit(int show_errno, const char *format, ...) @@ -335,332 +299,12 @@ set_threadcounts(algo_props_t *props, int *nthreads, int nprocs, algo_threads_ty } } -int -compute_checksum(uchar_t *cksum_buf, int cksum, uchar_t *buf, ssize_t bytes) -{ - if (cksum == CKSUM_CRC64) { - uint64_t *ck = (uint64_t *)cksum_buf; - *ck = lzma_crc64(buf, bytes, 0); - - } else if (cksum == CKSUM_SKEIN256) { - Skein_512_Ctxt_t ctx; - - Skein_512_Init(&ctx, 256); - Skein_512_Update(&ctx, buf, bytes); - Skein_512_Final(&ctx, cksum_buf); - - } else if (cksum == CKSUM_SKEIN512) { - Skein_512_Ctxt_t ctx; - - Skein_512_Init(&ctx, 512); - Skein_512_Update(&ctx, buf, bytes); - Skein_512_Final(&ctx, cksum_buf); - - } else if (cksum == CKSUM_SHA256) { - if (cksum_provider == PROVIDER_OPENSSL) { - SHA256_CTX ctx; - - SHA256_Init(&ctx); - SHA256_Update(&ctx, buf, bytes); - SHA256_Final(cksum_buf, &ctx); - } else { - SHA256_Context ctx; - - opt_SHA256_Init(&ctx); - opt_SHA256_Update(&ctx, buf, bytes); - opt_SHA256_Final(&ctx, cksum_buf); - } - } else if (cksum == CKSUM_SHA512) { - SHA512_CTX ctx; - - SHA512_Init(&ctx); - SHA512_Update(&ctx, buf, bytes); - SHA512_Final(cksum_buf, &ctx); - } else { - return (-1); - } - return (0); -} - -static void -init_sha256(void) -{ -#ifdef WORDS_BIGENDIAN - cksum_provider = PROVIDER_OPENSSL; -#else -#ifdef __x86_64__ - processor_info_t pc; - - cksum_provider = PROVIDER_OPENSSL; - cpuid_basic_identify(&pc); - if (pc.proc_type == PROC_X64_INTEL || pc.proc_type == PROC_X64_AMD) { - if (opt_Init_SHA(&pc) == 0) { - cksum_provider = PROVIDER_X64_OPT; - } - } -#endif -#endif -} - -/* - * Check is either the given checksum name or id is valid and - * return it's properties. - */ -int -get_checksum_props(char *name, int *cksum, int *cksum_bytes) -{ - int i; - - for (i=0; i0; i--) { - buf[j] = checksum[i-1]; - j++; - } -} - -void -deserialize_checksum(uchar_t *checksum, uchar_t *buf, int cksum_bytes) -{ - int i,j; - - j = 0; - for (i=cksum_bytes; i>0; i--) { - checksum[i-1] = buf[j]; - j++; - } -} - -int -init_crypto(crypto_ctx_t *cctx, uchar_t *pwd, int pwd_len, int crypto_alg, - uchar_t *salt, int saltlen, uint64_t nonce, int enc_dec) -{ - if (crypto_alg == CRYPTO_ALG_AES) { - aes_ctx_t *actx = malloc(sizeof (aes_ctx_t)); - - if (enc_dec) { - /* - * Encryption init. - */ - cctx->salt = malloc(32); - salt = cctx->salt; - cctx->saltlen = 32; - if (RAND_status() != 1 || RAND_bytes(salt, 32) != 1) { - if (geturandom_bytes(salt) != 0) { - uchar_t sb[64]; - int b; - struct timespec tp; - - b = 0; - /* No good random pool is populated/available. What to do ? */ - if (clock_gettime(CLOCK_MONOTONIC, &tp) == -1) { - time((time_t *)&sb[b]); - b += 8; - } else { - uint64_t v; - v = tp.tv_sec * 1000UL + tp.tv_nsec; - *((uint64_t *)&sb[b]) = v; - b += 8; - } - *((uint32_t *)&sb[b]) = rand(); - b += 4; - *((uint32_t *)&sb[b]) = getpid(); - b += 4; - compute_checksum(&sb[b], CKSUM_SHA256, sb, b); - b = 8 + 4; - *((uint32_t *)&sb[b]) = rand(); - compute_checksum(salt, CKSUM_SHA256, &sb[b], 32 + 4); - } - } - - /* - * Zero nonce (arg #6) since it will be generated. - */ - if (aes_init(actx, salt, 32, pwd, pwd_len, 0, enc_dec) != 0) { - fprintf(stderr, "Failed to initialize AES context\n"); - return (-1); - } - } else { - /* - * Decryption init. - * Pass given nonce and salt. - */ - if (saltlen > MAX_SALTLEN) { - fprintf(stderr, "Salt too long. Max allowed length is %d\n", - MAX_SALTLEN); - return (-1); - } - cctx->salt = malloc(saltlen); - memcpy(cctx->salt, salt, saltlen); - - if (aes_init(actx, cctx->salt, saltlen, pwd, pwd_len, nonce, - enc_dec) != 0) { - fprintf(stderr, "Failed to initialize AES context\n"); - return (-1); - } - } - cctx->crypto_ctx = actx; - cctx->crypto_alg = crypto_alg; - cctx->enc_dec = enc_dec; - } else { - fprintf(stderr, "Unrecognized algorithm code: %d\n", crypto_alg); - return (-1); - } - return (0); -} - -int -crypto_buf(crypto_ctx_t *cctx, uchar_t *from, uchar_t *to, ssize_t bytes, uint64_t id) -{ - if (cctx->crypto_alg == CRYPTO_ALG_AES) { - if (cctx->enc_dec == ENCRYPT_FLAG) { - return (aes_encrypt(cctx->crypto_ctx, from, to, bytes, id)); - } else { - return (aes_decrypt(cctx->crypto_ctx, from, to, bytes, id)); - } - } else { - fprintf(stderr, "Unrecognized algorithm code: %d\n", cctx->crypto_alg); - return (-1); - } - return (0); -} - uint64_t -crypto_nonce(crypto_ctx_t *cctx) +get_total_ram() { - return (aes_nonce(cctx->crypto_ctx)); -} - -void -cleanup_crypto(crypto_ctx_t *cctx) -{ - aes_cleanup(cctx->crypto_ctx); - memset(cctx->salt, 0, 32); - free(cctx->salt); - free(cctx); -} - -static int -geturandom_bytes(uchar_t rbytes[32]) -{ - int fd; - ssize_t lenread; - uchar_t * buf = rbytes; - 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); -} - -int -get_pw_string(char pw[MAX_PW_LEN], char *prompt) -{ - int fd, len; - FILE *input, *strm; - struct termios oldt, newt; - uchar_t pw1[MAX_PW_LEN], pw2[MAX_PW_LEN], *s; - - // Try TTY first - fd = open("/dev/tty", O_RDWR | O_NOCTTY); - if (fd != -1) { - input = fdopen(fd, "w+"); - strm = input; - } else { - // Fall back to stdin - fd = STDIN_FILENO; - input = stdin; - strm = stderr; - } - tcgetattr(fd, &oldt); - newt = oldt; - newt.c_lflag &= ~ECHO; - tcsetattr(fd, TCSANOW, &newt); - - fprintf(stderr, "%s: ", prompt); - fflush(stderr); - s = fgets(pw1, MAX_PW_LEN, input); - fputs("\n", stderr); - - if (s == NULL) { - tcsetattr(fd, TCSANOW, &oldt); - fflush(strm); - return (-1); - } - - fprintf(stderr, "%s (once more): ", prompt); - fflush(stderr); - s = fgets(pw2, MAX_PW_LEN, input); - tcsetattr(fd, TCSANOW, &oldt); - fflush(strm); - fputs("\n", stderr); - - if (s == NULL) { - return (-1); - } - - if (strcmp(pw1, pw2) != 0) { - fprintf(stderr, "Passwords do not match!\n"); - memset(pw1, 0, MAX_PW_LEN); - memset(pw2, 0, MAX_PW_LEN); - return (-1); - } - - len = strlen(pw1); - pw1[len-1] = '\0'; - strcpy(pw, pw1); - memset(pw1, 0, MAX_PW_LEN); - memset(pw2, 0, MAX_PW_LEN); - return (len); + uint64_t phys_pages, page_size; + + page_size = sysconf(_SC_PAGESIZE); + phys_pages = sysconf(_SC_PHYS_PAGES); + return (phys_pages * page_size); } diff --git a/utils/utils.h b/utils/utils.h index c6c0a61..b9dff98 100644 --- a/utils/utils.h +++ b/utils/utils.h @@ -34,7 +34,6 @@ extern "C" { #define DATA_TEXT 1 #define DATA_BINARY 2 -#define MAX_PW_LEN 16 #if !defined(sun) && !defined(__sun) #define uchar_t u_char @@ -102,22 +101,6 @@ typedef ssize_t bsize_t; #define DEBUG_STAT_EN(...) #endif -/* - * Public checksum properties. CKSUM_MAX_BYTES must be updated if a - * newer larger checksum is added to the list. - */ -typedef enum { - CKSUM_CRC64 = 0x100, - CKSUM_SKEIN256 = 0x200, - CKSUM_SKEIN512 = 0x300, - CKSUM_SHA256 = 0x400, - CKSUM_SHA512 = 0x500 -} cksum_t; - -#define CKSUM_MASK 0x700 -#define CKSUM_MAX_BYTES 64 -#define DEFAULT_CKSUM "SKEIN256" - typedef struct { uint32_t buf_extra; int compress_mt_capable; @@ -147,19 +130,6 @@ typedef struct { proc_type_t proc_type; } processor_info_t; -#define ENCRYPT_FLAG 1 -#define DECRYPT_FLAG 0 -#define CRYPTO_ALG_AES 0x10 -#define MAX_SALTLEN 64 - -typedef struct { - void *crypto_ctx; - int crypto_alg; - int enc_dec; - uchar_t *salt; - int saltlen; -} crypto_ctx_t; - extern void err_exit(int show_errno, const char *format, ...); extern const char *get_execname(const char *); extern int parse_numeric(ssize_t *val, const char *str); @@ -170,16 +140,7 @@ extern ssize_t Read_Adjusted(int fd, uchar_t *buf, size_t count, extern ssize_t Write(int fd, const void *buf, size_t count); extern void set_threadcounts(algo_props_t *props, int *nthreads, int nprocs, algo_threads_type_t typ); -extern int compute_checksum(uchar_t *cksum_buf, int cksum, uchar_t *buf, ssize_t bytes); -extern int get_checksum_props(char *name, int *cksum, int *cksum_bytes); -extern void serialize_checksum(uchar_t *checksum, uchar_t *buf, int cksum_bytes); -extern void deserialize_checksum(uchar_t *checksum, uchar_t *buf, int cksum_bytes); -extern int init_crypto(crypto_ctx_t *cctx, uchar_t *pwd, int pwd_len, int crypto_alg, - uchar_t *salt, int saltlen, uint64_t nonce, int enc_dec); -extern int crypto_buf(crypto_ctx_t *cctx, uchar_t *from, uchar_t *to, ssize_t bytes, uint64_t id); -extern uint64_t crypto_nonce(crypto_ctx_t *cctx); -extern void cleanup_crypto(crypto_ctx_t *cctx); -extern int get_pw_string(char pw[MAX_PW_LEN], char *prompt); +extern uint64_t get_total_ram(); /* Pointer type for compress and decompress functions. */ typedef int (*compress_func_ptr)(void *src, size_t srclen, void *dst,