From 405988f2cca816fdfdf8ad62b1285dcf06822e85 Mon Sep 17 00:00:00 2001 From: EasySec Date: Wed, 14 Dec 2016 16:29:06 +0100 Subject: [PATCH] Add support for PBKDF2 for enc command Reviewed-by: Tim Hudson Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/2083) --- apps/enc.c | 58 +++++++++++++++++++++++++++++++++++++++--------- doc/man1/enc.pod | 14 ++++++++++-- 2 files changed, 60 insertions(+), 12 deletions(-) diff --git a/apps/enc.c b/apps/enc.c index 0081ef5b5f..8e5a57d3e5 100644 --- a/apps/enc.c +++ b/apps/enc.c @@ -44,7 +44,7 @@ typedef enum OPTION_choice { OPT_E, OPT_IN, OPT_OUT, OPT_PASS, OPT_ENGINE, OPT_D, OPT_P, OPT_V, OPT_NOPAD, OPT_SALT, OPT_NOSALT, OPT_DEBUG, OPT_UPPER_P, OPT_UPPER_A, OPT_A, OPT_Z, OPT_BUFSIZE, OPT_K, OPT_KFILE, OPT_UPPER_K, OPT_NONE, - OPT_UPPER_S, OPT_IV, OPT_MD, OPT_CIPHER, + OPT_UPPER_S, OPT_IV, OPT_MD, OPT_ITER, OPT_PBKDF2, OPT_CIPHER, OPT_R_ENUM } OPTION_CHOICE; @@ -74,6 +74,8 @@ const OPTIONS enc_options[] = { {"S", OPT_UPPER_S, 's', "Salt, in hex"}, {"iv", OPT_IV, 's', "IV in hex"}, {"md", OPT_MD, 's', "Use specified digest to create a key from the passphrase"}, + {"iter", OPT_ITER, 'p', "Specify the iteration count and force use of PBKDF2"}, + {"pbkdf2", OPT_PBKDF2, '-', "Use password-based key derivation function 2"}, {"none", OPT_NONE, '-', "Don't encrypt"}, {"", OPT_CIPHER, '-', "Any supported cipher"}, OPT_R_OPTIONS, @@ -107,6 +109,8 @@ int enc_main(int argc, char **argv) int ret = 1, inl, nopad = 0; unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH]; unsigned char *buff = NULL, salt[PKCS5_SALT_LEN]; + int pbkdf2 = 0; + int iter = 0; long n; struct doall_enc_ciphers dec; #ifdef ZLIB @@ -255,6 +259,16 @@ int enc_main(int argc, char **argv) goto opthelp; cipher = c; break; + case OPT_ITER: + if (!opt_int(opt_arg(), &iter)) + goto opthelp; + pbkdf2 = 1; + break; + case OPT_PBKDF2: + pbkdf2 = 1; + if (iter == 0) /* do not overwrite a chosen value */ + iter = 10000; + break; case OPT_NONE: cipher = NULL; break; @@ -282,6 +296,9 @@ int enc_main(int argc, char **argv) if (dgst == NULL) dgst = EVP_sha256(); + if (iter == 0) + iter = 1; + /* It must be large enough for a base64 encoded line */ if (base64 && bsize < 80) bsize = 80; @@ -439,15 +456,37 @@ int enc_main(int argc, char **argv) BIO_printf(bio_err, "bad magic number\n"); goto end; } - sptr = salt; } - if (!EVP_BytesToKey(cipher, dgst, sptr, - (unsigned char *)str, - str_len, 1, key, iv)) { - BIO_printf(bio_err, "EVP_BytesToKey failed\n"); - goto end; + if (pbkdf2 == 1) { + /* + * derive key and default iv + * concatenated into a temporary buffer + */ + unsigned char tmpkeyiv[EVP_MAX_KEY_LENGTH + EVP_MAX_IV_LENGTH]; + int iklen = EVP_CIPHER_key_length(cipher); + int ivlen = EVP_CIPHER_iv_length(cipher); + /* not needed if HASH_UPDATE() is fixed : */ + int islen = (sptr != NULL ? sizeof(salt) : 0); + if (!PKCS5_PBKDF2_HMAC(str, str_len, sptr, islen, + iter, dgst, iklen+ivlen, tmpkeyiv)) { + BIO_printf(bio_err, "PKCS5_PBKDF2_HMAC failed\n"); + goto end; + } + /* split and move data back to global buffer */ + memcpy(key, tmpkeyiv, iklen); + memcpy(iv, tmpkeyiv+iklen, ivlen); + } else { + BIO_printf(bio_err, "*** WARNING : " + "deprecated key derivation used.\n" + "Using -iter or -pbkdf2 would be better.\n"); + if (!EVP_BytesToKey(cipher, dgst, sptr, + (unsigned char *)str, str_len, + 1, key, iv)) { + BIO_printf(bio_err, "EVP_BytesToKey failed\n"); + goto end; + } } /* * zero the complete buffer or the string passed from the command @@ -470,9 +509,8 @@ int enc_main(int argc, char **argv) if ((hiv == NULL) && (str == NULL) && EVP_CIPHER_iv_length(cipher) != 0) { /* - * No IV was explicitly set and no IV was generated during - * EVP_BytesToKey. Hence the IV is undefined, making correct - * decryption impossible. + * No IV was explicitly set and no IV was generated. + * Hence the IV is undefined, making correct decryption impossible. */ BIO_printf(bio_err, "iv undefined\n"); goto end; diff --git a/doc/man1/enc.pod b/doc/man1/enc.pod index cbf5cb2361..01cca4ea93 100644 --- a/doc/man1/enc.pod +++ b/doc/man1/enc.pod @@ -27,6 +27,8 @@ B> [B<-nosalt>] [B<-z>] [B<-md digest>] +[B<-iter count>] +[B<-pbkdf2>] [B<-p>] [B<-P>] [B<-bufsize number>] @@ -109,6 +111,16 @@ the B<-pass> argument. Use the specified digest to create the key from the passphrase. The default algorithm is sha-256. +=item B<-iter count> + +Use a given number of iterations on the password in deriving the encryption key. +High values increase the time required to brute-force the resulting file. +This option enables the use of PBKDF2 algorithm to derive the key. + +=item B<-pbkdf2> + +Use PBKDF2 algorithm with default iteration count unless otherwise specified. + =item B<-nosalt> Don't use a salt in the key derivation routines. This option B be @@ -375,8 +387,6 @@ Decrypt some data using a supplied 40 bit RC4 key: The B<-A> option when used with large files doesn't work properly. -There should be an option to allow an iteration count to be included. - The B program only supports a fixed number of algorithms with certain parameters. So if, for example, you want to use RC2 with a 76 bit key or RC4 with an 84 bit key you can't use this program. -- 2.25.1