summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorslontis <shane.lontis@oracle.com>2023-08-31 17:51:46 +1000
committerPauli <pauli@openssl.org>2023-09-04 14:15:34 +1000
commite3994583a1e4bde9a589c379520d216bc0a0c515 (patch)
tree740416411fe5f6b4c6fbead6c06d03de556d17cc
parent9f679bdc71aac83e89cc5aacb42855f3657ace39 (diff)
Added 'saltlen' option to the OpenSSL enc command line app.
This allows PBKDF2 to change the saltlen to something other than the new default value of 16. Previously this app hardwired the salt length to a maximum of 8 bytes. Non PBKDF2 mode uses EVP_BytesToKey() internally, which is documented to only allow 8 bytes. Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Paul Dale <pauli@openssl.org> (Merged from https://github.com/openssl/openssl/pull/21858)
-rw-r--r--CHANGES.md3
-rw-r--r--apps/enc.c28
-rw-r--r--doc/man1/openssl-enc.pod.in17
-rw-r--r--test/recipes/20-test_enc.t20
-rw-r--r--test/recipes/25-test_pkcs8.t2
5 files changed, 58 insertions, 12 deletions
diff --git a/CHANGES.md b/CHANGES.md
index 8f1e757f8c..974e549486 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -32,6 +32,9 @@ OpenSSL 3.2
requires a salt length of 128 bits. This affects OpenSSL command line
applications such as "genrsa" and "pkcs8" and API's such as
PEM_write_bio_PrivateKey() that are reliant on the default value.
+ The additional commandline option 'saltlen' has been added to the
+ OpenSSL command line applications for "pkcs8" and "enc" to allow the
+ salt length to be set to a non default value.
*Shane Lontis*
diff --git a/apps/enc.c b/apps/enc.c
index 58994e1d3e..a3b17da08d 100644
--- a/apps/enc.c
+++ b/apps/enc.c
@@ -49,7 +49,7 @@ typedef enum OPTION_choice {
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_ITER, OPT_PBKDF2, OPT_CIPHER,
- OPT_R_ENUM, OPT_PROV_ENUM
+ OPT_SALTLEN, OPT_R_ENUM, OPT_PROV_ENUM
} OPTION_CHOICE;
const OPTIONS enc_options[] = {
@@ -100,6 +100,8 @@ const OPTIONS enc_options[] = {
{OPT_MORE_STR, 0, 0,
"Use -iter to change the iteration count from " STR(PBKDF2_ITER_DEFAULT)},
{"none", OPT_NONE, '-', "Don't encrypt"},
+ {"saltlen", OPT_SALTLEN, 'p', "Specify the PBKDF2 salt length (in bytes)"},
+ {OPT_MORE_STR, 0, 0, "Default: 16"},
#ifndef OPENSSL_NO_ZLIB
{"z", OPT_Z, '-', "Compress or decompress encrypted data using zlib"},
#endif
@@ -132,7 +134,8 @@ int enc_main(int argc, char **argv)
int base64 = 0, informat = FORMAT_BINARY, outformat = FORMAT_BINARY;
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];
+ unsigned char *buff = NULL, salt[EVP_MAX_IV_LENGTH];
+ int saltlen = 0;
int pbkdf2 = 0;
int iter = 0;
long n;
@@ -293,6 +296,12 @@ int enc_main(int argc, char **argv)
iter = opt_int_arg();
pbkdf2 = 1;
break;
+ case OPT_SALTLEN:
+ if (!opt_int(opt_arg(), &saltlen))
+ goto opthelp;
+ if (saltlen > (int)sizeof(salt))
+ saltlen = (int)sizeof(salt);
+ break;
case OPT_PBKDF2:
pbkdf2 = 1;
if (iter == 0) /* do not overwrite a chosen value */
@@ -317,6 +326,8 @@ int enc_main(int argc, char **argv)
goto opthelp;
if (!app_RAND_load())
goto end;
+ if (saltlen == 0 || pbkdf2 == 0)
+ saltlen = PKCS5_SALT_LEN;
/* Get the cipher name, either from progname (if set) or flag. */
if (!opt_cipher(ciphername, &cipher))
@@ -496,13 +507,13 @@ int enc_main(int argc, char **argv)
if (nosalt) {
sptr = NULL;
} else {
- if (hsalt != NULL && !set_hex(hsalt, salt, sizeof(salt))) {
+ if (hsalt != NULL && !set_hex(hsalt, salt, saltlen)) {
BIO_printf(bio_err, "invalid hex salt value\n");
goto end;
}
if (enc) { /* encryption */
if (hsalt == NULL) {
- if (RAND_bytes(salt, sizeof(salt)) <= 0) {
+ if (RAND_bytes(salt, saltlen) <= 0) {
BIO_printf(bio_err, "RAND_bytes failed\n");
goto end;
}
@@ -515,7 +526,7 @@ int enc_main(int argc, char **argv)
sizeof(magic) - 1) != sizeof(magic) - 1
|| BIO_write(wbio,
(char *)salt,
- sizeof(salt)) != sizeof(salt))) {
+ saltlen) != saltlen)) {
BIO_printf(bio_err, "error writing output file\n");
goto end;
}
@@ -528,7 +539,7 @@ int enc_main(int argc, char **argv)
}
if (memcmp(mbuf, magic, sizeof(mbuf)) == 0) { /* file IS salted */
if (BIO_read(rbio, salt,
- sizeof(salt)) != sizeof(salt)) {
+ saltlen) != saltlen) {
BIO_printf(bio_err, "error reading input file\n");
goto end;
}
@@ -550,7 +561,8 @@ int enc_main(int argc, char **argv)
int iklen = EVP_CIPHER_get_key_length(cipher);
int ivlen = EVP_CIPHER_get_iv_length(cipher);
/* not needed if HASH_UPDATE() is fixed : */
- int islen = (sptr != NULL ? sizeof(salt) : 0);
+ int islen = (sptr != NULL ? saltlen : 0);
+
if (!PKCS5_PBKDF2_HMAC(str, str_len, sptr, islen,
iter, dgst, iklen+ivlen, tmpkeyiv)) {
BIO_printf(bio_err, "PKCS5_PBKDF2_HMAC failed\n");
@@ -646,7 +658,7 @@ int enc_main(int argc, char **argv)
if (printkey) {
if (!nosalt) {
printf("salt=");
- for (i = 0; i < (int)sizeof(salt); i++)
+ for (i = 0; i < (int)saltlen; i++)
printf("%02X", salt[i]);
printf("\n");
}
diff --git a/doc/man1/openssl-enc.pod.in b/doc/man1/openssl-enc.pod.in
index 84d67361f8..14066a3185 100644
--- a/doc/man1/openssl-enc.pod.in
+++ b/doc/man1/openssl-enc.pod.in
@@ -31,6 +31,7 @@ B<openssl> B<enc>|I<cipher>
[B<-md> I<digest>]
[B<-iter> I<count>]
[B<-pbkdf2>]
+[B<-saltlen> I<size>]
[B<-p>]
[B<-P>]
[B<-bufsize> I<number>]
@@ -132,6 +133,15 @@ This option enables the use of PBKDF2 algorithm to derive the key.
Use PBKDF2 algorithm with a default iteration count of 10000
unless otherwise specified by the B<-iter> command line option.
+=item B<-saltlen>
+
+Set the salt length to use when using the B<-pbkdf2> option.
+For compatibility reasons, the default is 8 bytes.
+The maximum value is currently 16 bytes.
+If the B<-pbkdf2> option is not used, then this option is ignored
+and a fixed salt length of 8 is used. The salt length used when
+encrypting must also be used when decrypting.
+
=item B<-nosalt>
Don't use a salt in the key derivation routines. This option B<SHOULD NOT> be
@@ -147,7 +157,8 @@ encrypting, this is the default.
The actual salt to use: this must be represented as a string of hex digits.
If this option is used while encrypting, the same exact value will be needed
-again during decryption.
+again during decryption. This salt may be truncated or zero padded to
+match the salt length (See B<-saltlen>).
=item B<-K> I<key>
@@ -465,9 +476,11 @@ The B<-list> option was added in OpenSSL 1.1.1e.
The B<-ciphers> and B<-engine> options were deprecated in OpenSSL 3.0.
+The B<-saltlen> option was added in OpenSSL 3.2.
+
=head1 COPYRIGHT
-Copyright 2000-2022 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2000-2023 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the Apache License 2.0 (the "License"). You may not use
this file except in compliance with the License. You can obtain a copy
diff --git a/test/recipes/20-test_enc.t b/test/recipes/20-test_enc.t
index c5391d53f2..d16d73e64a 100644
--- a/test/recipes/20-test_enc.t
+++ b/test/recipes/20-test_enc.t
@@ -41,7 +41,7 @@ my @ciphers =
|rc2|rc4|seed)/x} @ciphers
if disabled("legacy");
-plan tests => 2 + (scalar @ciphers)*2;
+plan tests => 5 + (scalar @ciphers)*2;
SKIP: {
skip "Problems getting ciphers...", 1 + scalar(@ciphers)
@@ -72,4 +72,22 @@ plan tests => 2 + (scalar @ciphers)*2;
&& compare_text($test,$clearfile) == 0, $t);
}
}
+ ok(run(app([$cmd, "enc", "-in", $test, "-aes256", "-pbkdf2", "-out",
+ "salted_default.cipher", "-pass", "pass:password"]))
+ && run(app([$cmd, "enc", "-d", "-in", "salted_default.cipher", "-aes256", "-pbkdf2",
+ "-saltlen", "8", "-out", "salted_default.clear", "-pass", "pass:password"]))
+ && compare_text($test,"salted_default.clear") == 0,
+ "Check that the default salt length of 8 bytes is used for PKDF2");
+
+ ok(!run(app([$cmd, "enc", "-d", "-in", "salted_default.cipher", "-aes256", "-pbkdf2",
+ "-saltlen", "16", "-out", "salted_fail.clear", "-pass", "pass:password"])),
+ "Check the decrypt fails if the saltlen is incorrect");
+
+ ok(run(app([$cmd, "enc", "-in", $test, "-aes256", "-pbkdf2", "-saltlen", "16",
+ "-out", "salted.cipher", "-pass", "pass:password"]))
+ && run(app([$cmd, "enc", "-d", "-in", "salted.cipher", "-aes256", "-pbkdf2",
+ "-saltlen", "16", "-out", "salted.clear", "-pass", "pass:password"]))
+ && compare_text($test,"salted.clear") == 0,
+ "Check that we can still use a salt length of 16 bytes for PKDF2");
+
}
diff --git a/test/recipes/25-test_pkcs8.t b/test/recipes/25-test_pkcs8.t
index 2f7ea1e1ae..2db574bb69 100644
--- a/test/recipes/25-test_pkcs8.t
+++ b/test/recipes/25-test_pkcs8.t
@@ -81,7 +81,7 @@ SKIP: {
'-in', 'pbe1.pem',
'-offset', '19', '-length', '10']))),
"Check the default size of the PBE PARAM 'salt length' = 8");
-
+
ok(run(app(([ 'openssl', 'pkcs8', '-topk8',
'-in', srctop_file('test', 'certs', 'pc5-key.pem'),
'-v1', "PBE-MD5-DES",