Change default encryption key length to 256 bits.

Add optional ability to change key length at runtime via cli option.
Include key length property in archive header.
Fix header HMAC to include salt, nonce and key length properties.
Retain backward compatibility to handle older format archives.
Fix compilation of AES ASM code.
This commit is contained in:
Moinak Ghosh 2013-03-03 20:02:14 +05:30
parent 72b23dac1a
commit 7a29c7be1e
8 changed files with 132 additions and 58 deletions

View file

@ -287,7 +287,7 @@ $(CRYPTO_OBJS): $(CRYPTO_SRCS) $(CRYPTO_HDRS) $(CRYPTO_ASM_OBJS)
$(COMPILE) $(GEN_OPT) $(CRYPTO_CPPFLAGS) $(CPPFLAGS) $(@:.o=.c) -o $@ $(COMPILE) $(GEN_OPT) $(CRYPTO_CPPFLAGS) $(CPPFLAGS) $(@:.o=.c) -o $@
$(CRYPTO_ASM_OBJS): $(CRYPTO_ASM_SRCS) $(CRYPTO_ASM_HDRS) $(CRYPTO_ASM_OBJS): $(CRYPTO_ASM_SRCS) $(CRYPTO_ASM_HDRS)
$(YASM) -o $@ $(@:.o=.s) $(COMPILE) $(GEN_OPT) $(CRYPTO_CPPFLAGS) $(CPPFLAGS) -o $@ $(@:.o=.s)
$(CRYPTO_COMPAT_OBJS): $(CRYPTO_COMPAT_SRCS) $(CRYPTO_COMPAT_HDRS) $(CRYPTO_COMPAT_OBJS): $(CRYPTO_COMPAT_SRCS) $(CRYPTO_COMPAT_HDRS)
$(COMPILE) $(GEN_OPT) $(CRYPTO_CPPFLAGS) $(CPPFLAGS) $(@:.o=.c) -o $@ $(COMPILE) $(GEN_OPT) $(CRYPTO_CPPFLAGS) $(CPPFLAGS) $(@:.o=.c) -o $@

View file

@ -131,13 +131,11 @@ NOTE: The option "libbsc" uses Ilya Grebnov's block sorting compression library
'-C' - Display compression statistics '-C' - Display compression statistics
Encryption flags: Encryption flags:
'-e' Encrypt chunks with AES. The password can be prompted from the user '-e' Encrypt chunks with AES-CTR. The password can be prompted from the user
or read from a file. Whether 128-Bit or 256-Bit keys are used depends or read from a file. Unique keys are generated every time pcompress is
on how the pcompress binary was built. Default build uses 128-Bit keys. run even when giving the same password. Of course enough info is stored\
Unique keys are generated every time pcompress is run even when giving in the compresse file so that the key used for the file can be
the same password. Of course enough info is stored in the compressed re-created given the correct password.
file so that the key used for the file can be re-created given the
correct password.
The Scrypt algorithm from Tarsnap is used The Scrypt algorithm from Tarsnap is used
(See: http://www.tarsnap.com/scrypt.html) for generating keys from (See: http://www.tarsnap.com/scrypt.html) for generating keys from
@ -148,6 +146,10 @@ NOTE: The option "libbsc" uses Ilya Grebnov's block sorting compression library
be readable and writable since it is zeroed out after the password is be readable and writable since it is zeroed out after the password is
read. read.
'-k <key length>'
Specify the key length. Can be 16 for 128 bit keys or 32 for 256 bit
keys. Default value is 23 for 256 bit keys.
NOTE: When using pipe-mode via -p the only way to provide a password is to use '-w'. NOTE: When using pipe-mode via -p the only way to provide a password is to use '-w'.
Environment Variables Environment Variables

21
config
View file

@ -13,20 +13,21 @@ ${prog} [<options>]
--enable-debug-stats Enable printing of some verbose debug info (default: disabled). --enable-debug-stats Enable printing of some verbose debug info (default: disabled).
--with-libbsc=<path to libbsc source> --with-libbsc=<path to libbsc source>
Enable support for libbsc (See: libbsc.com). Full path to the libbsc Enable support for libbsc (See: libbsc.com). Full path to the libbsc
source tree must be provided. It links the library statically. source tree must be provided. It links the library statically.
--with-openssl=<path to OpenSSL installation tree> (Default: System) --with-openssl=<path to OpenSSL installation tree> (Default: System)
This defaults to the system's OpenSSL library. You can use this option This defaults to the system's OpenSSL library. You can use this option
if you want to use an alternate OpenSSL installation. if you want to use an alternate OpenSSL installation.
--with-zlib=<path to zlib installation tree> (Default: System) --with-zlib=<path to zlib installation tree> (Default: System)
Enable building against an alternate Zlib installation. Enable building against an alternate Zlib installation.
--with-bzlib=<path to Bzip2 library installation tree> (Default: System) --with-bzlib=<path to Bzip2 library installation tree> (Default: System)
Enable building against an alternate Bzip2 and library installation. Enable building against an alternate Bzip2 and library installation.
--no-sse-detect Do NOT attempt to probe the system's SSE/AVX capability for build flags. --no-sse-detect Do NOT attempt to probe the system's SSE/AVX capability for build flags.
--no-1.3-archive-compat Disable compatibility with compressed archives created with Pcompress --no-1.3-archive-compat Disable compatibility with compressed archives created with Pcompress
version 1.3 (default: retain compatibility). Hash formats changed from version 1.3 (default: retain compatibility). Hash formats changed from
version 1.3 to 1.4 so this option is required if files created using version 1.3 to 1.4 so this option is required if files created using
1.3 need to be decompressed by version 1.4 onwards. 1.3 need to be decompressed by version 1.4 onwards.
--use-key256 Use 256-bit encryption keys. Default key length is 128-bit. --limit-key128 Limit key length to 128-bit encryption keys. Otherwise the default is to
use 256-bit keys changeable at runtime via the '-k <keylen>' option.
--help Display this help message. --help Display this help message.
_EOF _EOF
@ -145,7 +146,7 @@ do
bzlib_prefix=`echo ${arg1} | cut -f2 -d"="` bzlib_prefix=`echo ${arg1} | cut -f2 -d"="`
;; ;;
--use-key256) --use-key256)
keylen='-DKEYLEN=32' keylen='-DDEFAULT_KEYLEN=16'
;; ;;
--no-sse-detect) --no-sse-detect)
sse_detect=0 sse_detect=0

View file

@ -149,21 +149,21 @@ aes_init(aes_ctx_t *ctx, uchar_t *salt, int saltlen, uchar_t *pwd, int pwd_len,
pickparams(&logN, &r, &p); pickparams(&logN, &r, &p);
N = (uint64_t)(1) << logN; N = (uint64_t)(1) << logN;
if (crypto_scrypt(pwd, pwd_len, salt, saltlen, N, r, p, key, KEYLEN)) { if (crypto_scrypt(pwd, pwd_len, salt, saltlen, N, r, p, key, ctx->keylen)) {
fprintf(stderr, "Scrypt failed\n"); fprintf(stderr, "Scrypt failed\n");
return (-1); return (-1);
} }
#else #else
rv = PKCS5_PBKDF2_HMAC(pwd, pwd_len, salt, saltlen, PBE_ROUNDS, EVP_sha256(), rv = PKCS5_PBKDF2_HMAC(pwd, pwd_len, salt, saltlen, PBE_ROUNDS, EVP_sha256(),
KEYLEN, key); ctx->keylen, key);
if (rv != KEYLEN) { if (rv != ctx->keylen) {
fprintf(stderr, "Key size is %d bytes - should be %d bits\n", i, KEYLEN); fprintf(stderr, "Key size is %d bytes - should be %d bits\n", i, ctx->keylen);
return (-1); return (-1);
} }
#endif #endif
if (enc) { if (enc) {
enc_setkey(key, (KEYLEN << 3), &(ctx->key)); enc_setkey(key, (ctx->keylen << 3), &(ctx->key));
// Derive nonce from salt // Derive nonce from salt
if (clock_gettime(CLOCK_MONOTONIC, &tp) == -1) { if (clock_gettime(CLOCK_MONOTONIC, &tp) == -1) {
time((time_t *)&tv); time((time_t *)&tv);
@ -181,7 +181,7 @@ aes_init(aes_ctx_t *ctx, uchar_t *salt, int saltlen, uchar_t *pwd, int pwd_len,
tv = 0; tv = 0;
} else { } else {
ctx->nonce = nonce; ctx->nonce = nonce;
enc_setkey(key, (KEYLEN << 3), &(ctx->key)); enc_setkey(key, (ctx->keylen << 3), &(ctx->key));
} }
return (0); return (0);
} }
@ -243,7 +243,7 @@ aes_nonce(aes_ctx_t *ctx)
void void
aes_clean_pkey(aes_ctx_t *ctx) aes_clean_pkey(aes_ctx_t *ctx)
{ {
memset(ctx->pkey, 0, KEYLEN); memset(ctx->pkey, 0, ctx->keylen);
} }
void void

View file

@ -30,20 +30,19 @@
#include <openssl/evp.h> #include <openssl/evp.h>
#endif #endif
#include <openssl/opensslv.h> #include <openssl/opensslv.h>
#include <crypto_utils.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#ifndef KEYLEN
#define KEYLEN 16
#endif
#define PBE_ROUNDS 1000 #define PBE_ROUNDS 1000
typedef struct { typedef struct {
uint64_t nonce; uint64_t nonce;
AES_KEY key; AES_KEY key;
uchar_t pkey[KEYLEN]; int keylen;
uchar_t pkey[MAX_KEYLEN];
} aes_ctx_t; } aes_ctx_t;
int aes_init(aes_ctx_t *ctx, uchar_t *salt, int saltlen, uchar_t *pwd, int pwd_len, int aes_init(aes_ctx_t *ctx, uchar_t *salt, int saltlen, uchar_t *pwd, int pwd_len,

View file

@ -407,7 +407,7 @@ hmac_init(mac_ctx_t *mctx, int cksum, crypto_ctx_t *cctx)
if (cksum == CKSUM_BLAKE256) { if (cksum == CKSUM_BLAKE256) {
blake2b_state *ctx = (blake2b_state *)malloc(sizeof (blake2b_state)); blake2b_state *ctx = (blake2b_state *)malloc(sizeof (blake2b_state));
if (!ctx) return (-1); if (!ctx) return (-1);
if (bdsp.blake2b_init_key(ctx, 32, actx->pkey, KEYLEN) != 0) if (bdsp.blake2b_init_key(ctx, 32, actx->pkey, cctx->keylen) != 0)
return (-1); return (-1);
mctx->mac_ctx = ctx; mctx->mac_ctx = ctx;
ctx = (blake2b_state *)malloc(sizeof (blake2b_state)); ctx = (blake2b_state *)malloc(sizeof (blake2b_state));
@ -421,7 +421,7 @@ hmac_init(mac_ctx_t *mctx, int cksum, crypto_ctx_t *cctx)
} else if (cksum == CKSUM_BLAKE512) { } else if (cksum == CKSUM_BLAKE512) {
blake2b_state *ctx = (blake2b_state *)malloc(sizeof (blake2b_state)); blake2b_state *ctx = (blake2b_state *)malloc(sizeof (blake2b_state));
if (!ctx) return (-1); if (!ctx) return (-1);
if (bdsp.blake2b_init_key(ctx, 64, actx->pkey, KEYLEN) != 0) if (bdsp.blake2b_init_key(ctx, 64, actx->pkey, cctx->keylen) != 0)
return (-1); return (-1);
mctx->mac_ctx = ctx; mctx->mac_ctx = ctx;
ctx = (blake2b_state *)malloc(sizeof (blake2b_state)); ctx = (blake2b_state *)malloc(sizeof (blake2b_state));
@ -436,7 +436,7 @@ hmac_init(mac_ctx_t *mctx, int cksum, crypto_ctx_t *cctx)
Skein_512_Ctxt_t *ctx = (Skein_512_Ctxt_t *)malloc(sizeof (Skein_512_Ctxt_t)); Skein_512_Ctxt_t *ctx = (Skein_512_Ctxt_t *)malloc(sizeof (Skein_512_Ctxt_t));
if (!ctx) return (-1); if (!ctx) return (-1);
Skein_512_InitExt(ctx, 256, SKEIN_CFG_TREE_INFO_SEQUENTIAL, Skein_512_InitExt(ctx, 256, SKEIN_CFG_TREE_INFO_SEQUENTIAL,
actx->pkey, KEYLEN); actx->pkey, cctx->keylen);
mctx->mac_ctx = ctx; mctx->mac_ctx = ctx;
ctx = (Skein_512_Ctxt_t *)malloc(sizeof (Skein_512_Ctxt_t)); ctx = (Skein_512_Ctxt_t *)malloc(sizeof (Skein_512_Ctxt_t));
if (!ctx) { if (!ctx) {
@ -450,7 +450,7 @@ hmac_init(mac_ctx_t *mctx, int cksum, crypto_ctx_t *cctx)
Skein_512_Ctxt_t *ctx = (Skein_512_Ctxt_t *)malloc(sizeof (Skein_512_Ctxt_t)); Skein_512_Ctxt_t *ctx = (Skein_512_Ctxt_t *)malloc(sizeof (Skein_512_Ctxt_t));
if (!ctx) return (-1); if (!ctx) return (-1);
Skein_512_InitExt(ctx, 512, SKEIN_CFG_TREE_INFO_SEQUENTIAL, Skein_512_InitExt(ctx, 512, SKEIN_CFG_TREE_INFO_SEQUENTIAL,
actx->pkey, KEYLEN); actx->pkey, cctx->keylen);
mctx->mac_ctx = ctx; mctx->mac_ctx = ctx;
ctx = (Skein_512_Ctxt_t *)malloc(sizeof (Skein_512_Ctxt_t)); ctx = (Skein_512_Ctxt_t *)malloc(sizeof (Skein_512_Ctxt_t));
if (!ctx) { if (!ctx) {
@ -465,7 +465,7 @@ hmac_init(mac_ctx_t *mctx, int cksum, crypto_ctx_t *cctx)
HMAC_CTX *ctx = (HMAC_CTX *)malloc(sizeof (HMAC_CTX)); HMAC_CTX *ctx = (HMAC_CTX *)malloc(sizeof (HMAC_CTX));
if (!ctx) return (-1); if (!ctx) return (-1);
HMAC_CTX_init(ctx); HMAC_CTX_init(ctx);
HMAC_Init_ex(ctx, actx->pkey, KEYLEN, EVP_sha256(), NULL); HMAC_Init_ex(ctx, actx->pkey, cctx->keylen, EVP_sha256(), NULL);
mctx->mac_ctx = ctx; mctx->mac_ctx = ctx;
ctx = (HMAC_CTX *)malloc(sizeof (HMAC_CTX)); ctx = (HMAC_CTX *)malloc(sizeof (HMAC_CTX));
@ -482,7 +482,7 @@ hmac_init(mac_ctx_t *mctx, int cksum, crypto_ctx_t *cctx)
} else { } else {
HMAC_SHA512_Context *ctx = (HMAC_SHA512_Context *)malloc(sizeof (HMAC_SHA512_Context)); HMAC_SHA512_Context *ctx = (HMAC_SHA512_Context *)malloc(sizeof (HMAC_SHA512_Context));
if (!ctx) return (-1); if (!ctx) return (-1);
opt_HMAC_SHA512t256_Init(ctx, actx->pkey, KEYLEN); opt_HMAC_SHA512t256_Init(ctx, actx->pkey, cctx->keylen);
mctx->mac_ctx = ctx; mctx->mac_ctx = ctx;
ctx = (HMAC_SHA512_Context *)malloc(sizeof (HMAC_SHA512_Context)); ctx = (HMAC_SHA512_Context *)malloc(sizeof (HMAC_SHA512_Context));
@ -498,7 +498,7 @@ hmac_init(mac_ctx_t *mctx, int cksum, crypto_ctx_t *cctx)
HMAC_CTX *ctx = (HMAC_CTX *)malloc(sizeof (HMAC_CTX)); HMAC_CTX *ctx = (HMAC_CTX *)malloc(sizeof (HMAC_CTX));
if (!ctx) return (-1); if (!ctx) return (-1);
HMAC_CTX_init(ctx); HMAC_CTX_init(ctx);
HMAC_Init_ex(ctx, actx->pkey, KEYLEN, EVP_sha512(), NULL); HMAC_Init_ex(ctx, actx->pkey, cctx->keylen, EVP_sha512(), NULL);
mctx->mac_ctx = ctx; mctx->mac_ctx = ctx;
ctx = (HMAC_CTX *)malloc(sizeof (HMAC_CTX)); ctx = (HMAC_CTX *)malloc(sizeof (HMAC_CTX));
@ -515,7 +515,7 @@ hmac_init(mac_ctx_t *mctx, int cksum, crypto_ctx_t *cctx)
} else { } else {
HMAC_SHA512_Context *ctx = (HMAC_SHA512_Context *)malloc(sizeof (HMAC_SHA512_Context)); HMAC_SHA512_Context *ctx = (HMAC_SHA512_Context *)malloc(sizeof (HMAC_SHA512_Context));
if (!ctx) return (-1); if (!ctx) return (-1);
opt_HMAC_SHA512_Init(ctx, actx->pkey, KEYLEN); opt_HMAC_SHA512_Init(ctx, actx->pkey, cctx->keylen);
mctx->mac_ctx = ctx; mctx->mac_ctx = ctx;
ctx = (HMAC_SHA512_Context *)malloc(sizeof (HMAC_SHA512_Context)); ctx = (HMAC_SHA512_Context *)malloc(sizeof (HMAC_SHA512_Context));
@ -538,7 +538,7 @@ hmac_init(mac_ctx_t *mctx, int cksum, crypto_ctx_t *cctx)
if (Keccak_Init(ctx, 512) != 0) if (Keccak_Init(ctx, 512) != 0)
return (-1); return (-1);
} }
if (Keccak_Update(ctx, actx->pkey, KEYLEN << 3) != 0) if (Keccak_Update(ctx, actx->pkey, cctx->keylen << 3) != 0)
return (-1); return (-1);
mctx->mac_ctx = ctx; mctx->mac_ctx = ctx;
@ -719,11 +719,13 @@ hmac_cleanup(mac_ctx_t *mctx)
*/ */
int int
init_crypto(crypto_ctx_t *cctx, uchar_t *pwd, int pwd_len, int crypto_alg, 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) uchar_t *salt, int saltlen, int keylen, uint64_t nonce, int enc_dec)
{ {
if (crypto_alg == CRYPTO_ALG_AES) { if (crypto_alg == CRYPTO_ALG_AES) {
aes_ctx_t *actx = (aes_ctx_t *)malloc(sizeof (aes_ctx_t)); aes_ctx_t *actx = (aes_ctx_t *)malloc(sizeof (aes_ctx_t));
aes_module_init(&proc_info); aes_module_init(&proc_info);
cctx->keylen = keylen;
actx->keylen = keylen;
if (enc_dec) { if (enc_dec) {
/* /*

View file

@ -37,6 +37,16 @@ extern "C" {
#define CKSUM_MAX_BYTES 64 #define CKSUM_MAX_BYTES 64
#define DEFAULT_CKSUM "BLAKE256" #define DEFAULT_CKSUM "BLAKE256"
/*
* Default key length for Encryption and Decryption
*/
#ifndef DEFAULT_KEYLEN
#define DEFAULT_KEYLEN 32
#define MAX_KEYLEN 32
#else
#define MAX_KEYLEN DEFAULT_KEYLEN
#endif
#define ENCRYPT_FLAG 1 #define ENCRYPT_FLAG 1
#define DECRYPT_FLAG 0 #define DECRYPT_FLAG 0
#define CRYPTO_ALG_AES 0x10 #define CRYPTO_ALG_AES 0x10
@ -71,6 +81,7 @@ typedef struct {
int enc_dec; int enc_dec;
uchar_t *salt; uchar_t *salt;
int saltlen; int saltlen;
int keylen;
} crypto_ctx_t; } crypto_ctx_t;
typedef struct { typedef struct {
@ -93,7 +104,7 @@ void deserialize_checksum(uchar_t *checksum, uchar_t *buf, int cksum_bytes);
* Encryption related functions. * Encryption related functions.
*/ */
int init_crypto(crypto_ctx_t *cctx, uchar_t *pwd, int pwd_len, int crypto_alg, 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); uchar_t *salt, int saltlen, int keylen, uint64_t nonce, int enc_dec);
int crypto_buf(crypto_ctx_t *cctx, uchar_t *from, uchar_t *to, uint64_t bytes, uint64_t id); int crypto_buf(crypto_ctx_t *cctx, uchar_t *from, uchar_t *to, uint64_t bytes, uint64_t id);
uint64_t crypto_nonce(crypto_ctx_t *cctx); uint64_t crypto_nonce(crypto_ctx_t *cctx);
void crypto_clean_pkey(crypto_ctx_t *cctx); void crypto_clean_pkey(crypto_ctx_t *cctx);

95
main.c
View file

@ -98,7 +98,7 @@ static int do_compress = 0;
static int do_uncompress = 0; static int do_uncompress = 0;
static int cksum_bytes, mac_bytes; static int cksum_bytes, mac_bytes;
static int cksum = 0, t_errored = 0; static int cksum = 0, t_errored = 0;
static int rab_blk_size = 0; static int rab_blk_size = 0, keylen;
static crypto_ctx_t crypto_ctx; static crypto_ctx_t crypto_ctx;
static char *pwd_file = NULL, *f_name = NULL; static char *pwd_file = NULL, *f_name = NULL;
@ -169,6 +169,18 @@ usage(void)
" - Specify an average Dedupe block size. 1 - 4K, 2 - 8K ... 5 - 64K.\n" " - Specify an average Dedupe block size. 1 - 4K, 2 - 8K ... 5 - 64K.\n"
" '-M' - Display memory allocator statistics\n" " '-M' - Display memory allocator statistics\n"
" '-C' - Display compression statistics\n\n"); " '-C' - Display compression statistics\n\n");
fprintf(stderr, "\n"
"8) Encryption flags:\n"
" '-e' - Encrypt chunks with AES-CTR. The password can be prompted from the\n"
" user or read from a file. Unique keys are generated every time\n"
" pcompress is run even when giving the same password.\n"
" '-w <pathname>'\n"
" - Provide a file which contains the encryption password. This file must\n"
" be readable and writable since it is zeroed out after the password is\n"
" read.\n"
" '-k <key length>\n"
" - Specify key length. Can be 16 for 128 bit or 32 for 256 bit. Default\n"
" is 32 for 256 bit keys.\n\n");
} }
void void
@ -787,7 +799,7 @@ start_decompress(const char *filename, const char *to_filename)
if (flags & MASK_CRYPTO_ALG) { if (flags & MASK_CRYPTO_ALG) {
int saltlen; int saltlen;
uchar_t *salt1, *salt2; uchar_t *salt1, *salt2;
uint64_t nonce; uint64_t nonce, d3;
uchar_t pw[MAX_PW_LEN]; uchar_t pw[MAX_PW_LEN];
int pw_len; int pw_len;
mac_ctx_t hdr_mac; mac_ctx_t hdr_mac;
@ -817,20 +829,34 @@ start_decompress(const char *filename, const char *to_filename)
UNCOMP_BAIL; UNCOMP_BAIL;
} }
deserialize_checksum(salt2, salt1, saltlen); deserialize_checksum(salt2, salt1, saltlen);
memset(salt1, 0, saltlen);
free(salt1);
if (Read(compfd, &nonce, sizeof (nonce)) < sizeof (nonce)) { if (Read(compfd, &nonce, sizeof (nonce)) < sizeof (nonce)) {
memset(salt2, 0, saltlen); memset(salt2, 0, saltlen);
free(salt2); free(salt2);
memset(salt1, 0, saltlen);
free(salt1);
perror("Read: "); perror("Read: ");
UNCOMP_BAIL; UNCOMP_BAIL;
} }
nonce = ntohll(nonce); nonce = ntohll(nonce);
if (version > 6) {
if (Read(compfd, &keylen, sizeof (keylen)) < sizeof (keylen)) {
memset(salt2, 0, saltlen);
free(salt2);
memset(salt1, 0, saltlen);
free(salt1);
perror("Read: ");
UNCOMP_BAIL;
}
keylen = ntohl(keylen);
}
if (Read(compfd, hdr_hash1, mac_bytes) < mac_bytes) { if (Read(compfd, hdr_hash1, mac_bytes) < mac_bytes) {
memset(salt2, 0, saltlen); memset(salt2, 0, saltlen);
free(salt2); free(salt2);
memset(salt1, 0, saltlen);
free(salt1);
perror("Read: "); perror("Read: ");
UNCOMP_BAIL; UNCOMP_BAIL;
} }
@ -842,6 +868,8 @@ start_decompress(const char *filename, const char *to_filename)
if (pw_len == -1) { if (pw_len == -1) {
memset(salt2, 0, saltlen); memset(salt2, 0, saltlen);
free(salt2); free(salt2);
memset(salt1, 0, saltlen);
free(salt1);
err_exit(0, "Failed to get password.\n"); err_exit(0, "Failed to get password.\n");
} }
} else { } else {
@ -874,6 +902,8 @@ start_decompress(const char *filename, const char *to_filename)
perror(" "); perror(" ");
memset(salt2, 0, saltlen); memset(salt2, 0, saltlen);
free(salt2); free(salt2);
memset(salt1, 0, saltlen);
free(salt1);
close(uncompfd); unlink(to_filename); close(uncompfd); unlink(to_filename);
err_exit(0, "Failed to get password.\n"); err_exit(0, "Failed to get password.\n");
} }
@ -881,16 +911,17 @@ start_decompress(const char *filename, const char *to_filename)
} }
if (init_crypto(&crypto_ctx, pw, pw_len, encrypt_type, salt2, if (init_crypto(&crypto_ctx, pw, pw_len, encrypt_type, salt2,
saltlen, nonce, DECRYPT_FLAG) == -1) { saltlen, keylen, nonce, DECRYPT_FLAG) == -1) {
memset(salt2, 0, saltlen); memset(salt2, 0, saltlen);
free(salt2); free(salt2);
memset(salt1, 0, saltlen);
free(salt1);
memset(pw, 0, MAX_PW_LEN); memset(pw, 0, MAX_PW_LEN);
close(uncompfd); unlink(to_filename); close(uncompfd); unlink(to_filename);
err_exit(0, "Failed to initialize crypto\n"); err_exit(0, "Failed to initialize crypto\n");
} }
memset(salt2, 0, saltlen); memset(salt2, 0, saltlen);
free(salt2); free(salt2);
nonce = 0;
memset(pw, 0, MAX_PW_LEN); memset(pw, 0, MAX_PW_LEN);
/* /*
@ -905,12 +936,24 @@ start_decompress(const char *filename, const char *to_filename)
hmac_update(&hdr_mac, (uchar_t *)&d1, sizeof (version)); hmac_update(&hdr_mac, (uchar_t *)&d1, sizeof (version));
d1 = htons(flags); d1 = htons(flags);
hmac_update(&hdr_mac, (uchar_t *)&d1, sizeof (flags)); hmac_update(&hdr_mac, (uchar_t *)&d1, sizeof (flags));
nonce = htonll(chunksize); d3 = htonll(chunksize);
hmac_update(&hdr_mac, (uchar_t *)&nonce, sizeof (nonce)); hmac_update(&hdr_mac, (uchar_t *)&d3, sizeof (nonce));
d2 = htonl(level); d2 = htonl(level);
hmac_update(&hdr_mac, (uchar_t *)&d2, sizeof (level)); hmac_update(&hdr_mac, (uchar_t *)&d2, sizeof (level));
if (version > 6) {
d2 = htonl(saltlen);
hmac_update(&hdr_mac, (uchar_t *)&d2, sizeof (saltlen));
hmac_update(&hdr_mac, salt1, saltlen);
nonce = htonll(nonce);
hmac_update(&hdr_mac, (uchar_t *)&nonce, sizeof (nonce));
d2 = htonl(keylen);
hmac_update(&hdr_mac, (uchar_t *)&d2, sizeof (keylen));
}
hmac_final(&hdr_mac, hdr_hash1, &hlen); hmac_final(&hdr_mac, hdr_hash1, &hlen);
hmac_cleanup(&hdr_mac); hmac_cleanup(&hdr_mac);
memset(salt1, 0, saltlen);
free(salt1);
nonce = 0;
if (memcmp(hdr_hash2, hdr_hash1, mac_bytes) != 0) { if (memcmp(hdr_hash2, hdr_hash1, mac_bytes) != 0) {
close(uncompfd); unlink(to_filename); close(uncompfd); unlink(to_filename);
err_exit(0, "Header verification failed! File tampered or wrong password.\n"); err_exit(0, "Header verification failed! File tampered or wrong password.\n");
@ -1600,7 +1643,7 @@ start_compress(const char *filename, uint64_t chunksize, int level)
close(fd); close(fd);
} }
if (init_crypto(&crypto_ctx, pw, pw_len, encrypt_type, NULL, if (init_crypto(&crypto_ctx, pw, pw_len, encrypt_type, NULL,
0, 0, ENCRYPT_FLAG) == -1) { 0, keylen, 0, ENCRYPT_FLAG) == -1) {
memset(pw, 0, MAX_PW_LEN); memset(pw, 0, MAX_PW_LEN);
err_exit(0, "Failed to initialize crypto\n"); err_exit(0, "Failed to initialize crypto\n");
} }
@ -1791,14 +1834,28 @@ start_compress(const char *filename, uint64_t chunksize, int level)
pos += sizeof (n_chunksize); pos += sizeof (n_chunksize);
memcpy(pos, &level, sizeof (level)); memcpy(pos, &level, sizeof (level));
pos += sizeof (level); pos += sizeof (level);
/*
* If encryption is enabled, include salt, nonce and keylen in the header
* to be HMAC-ed (archive version 7 and greater).
*/
if (encrypt_type) {
*((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;
*((int *)pos) = htonl(keylen);
pos += sizeof (int);
}
if (Write(compfd, cread_buf, pos - cread_buf) != pos - cread_buf) { if (Write(compfd, cread_buf, pos - cread_buf) != pos - cread_buf) {
perror("Write "); perror("Write ");
COMP_BAIL; COMP_BAIL;
} }
/* /*
* If encryption is enabled, compute header HMAC. Then * If encryption is enabled, compute header HMAC and write it.
* write the salt, nonce and header hmac in that order.
*/ */
if (encrypt_type) { if (encrypt_type) {
mac_ctx_t hdr_mac; mac_ctx_t hdr_mac;
@ -1817,12 +1874,6 @@ start_compress(const char *filename, uint64_t chunksize, int level)
crypto_clean_pkey(&crypto_ctx); crypto_clean_pkey(&crypto_ctx);
pos = cread_buf; 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); serialize_checksum(hdr_hash, pos, hlen);
pos += hlen; pos += hlen;
if (Write(compfd, cread_buf, pos - cread_buf) != pos - cread_buf) { if (Write(compfd, cread_buf, pos - cread_buf) != pos - cread_buf) {
@ -2196,10 +2247,11 @@ main(int argc, char *argv[])
exec_name = get_execname(argv[0]); exec_name = get_execname(argv[0]);
level = 6; level = 6;
err = 0; err = 0;
keylen = DEFAULT_KEYLEN;
slab_init(); slab_init();
init_pcompress(); init_pcompress();
while ((opt = getopt(argc, argv, "dc:s:l:pt:MCDEew:rLPS:B:F")) != -1) { while ((opt = getopt(argc, argv, "dc:s:l:pt:MCDEew:rLPS:B:Fk:")) != -1) {
int ovr; int ovr;
switch (opt) { switch (opt) {
@ -2297,6 +2349,13 @@ main(int argc, char *argv[])
enable_rabin_split = 0; enable_rabin_split = 0;
break; break;
case 'k':
keylen = atoi(optarg);
if ((keylen != 16 && keylen != 32) || keylen > MAX_KEYLEN) {
err_exit(0, "Encryption KEY length should be 16 or 32.\n", optarg);
}
break;
case 'S': case 'S':
if (get_checksum_props(optarg, &cksum, &cksum_bytes, &mac_bytes, 0) == -1) { if (get_checksum_props(optarg, &cksum, &cksum_bytes, &mac_bytes, 0) == -1) {
err_exit(0, "Invalid checksum type %s\n", optarg); err_exit(0, "Invalid checksum type %s\n", optarg);