Commit 188f359d authored by Alvaro Herrera's avatar Alvaro Herrera

pgcrypto: support changing S2K iteration count

pgcrypto already supports key-stretching during symmetric encryption,
including the salted-and-iterated method; but the number of iterations
was not configurable.  This commit implements a new s2k-count parameter
to pgp_sym_encrypt() which permits selecting a larger number of
iterations.

Author: Jeff Janes
parent b6fb6471
...@@ -103,6 +103,25 @@ select pgp_sym_decrypt( ...@@ -103,6 +103,25 @@ select pgp_sym_decrypt(
Secret. Secret.
(1 row) (1 row)
-- s2k count change
select pgp_sym_decrypt(
pgp_sym_encrypt('Secret.', 'key', 's2k-count=1024'),
'key', 'expect-s2k-count=1024');
pgp_sym_decrypt
-----------------
Secret.
(1 row)
-- s2k_count rounds up
select pgp_sym_decrypt(
pgp_sym_encrypt('Secret.', 'key', 's2k-count=65000000'),
'key', 'expect-s2k-count=65000000');
NOTICE: pgp_decrypt: unexpected s2k_count: expected 65000000 got 65011712
pgp_sym_decrypt
-----------------
Secret.
(1 row)
-- s2k digest change -- s2k digest change
select pgp_sym_decrypt( select pgp_sym_decrypt(
pgp_sym_encrypt('Secret.', 'key', 's2k-digest-algo=md5'), pgp_sym_encrypt('Secret.', 'key', 's2k-digest-algo=md5'),
......
...@@ -643,6 +643,7 @@ parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src) ...@@ -643,6 +643,7 @@ parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src)
if (res < 0) if (res < 0)
return res; return res;
ctx->s2k_mode = ctx->s2k.mode; ctx->s2k_mode = ctx->s2k.mode;
ctx->s2k_count = s2k_decode_count(ctx->s2k.iter);
ctx->s2k_digest_algo = ctx->s2k.digest_algo; ctx->s2k_digest_algo = ctx->s2k.digest_algo;
/* /*
......
...@@ -567,7 +567,7 @@ init_s2k_key(PGP_Context *ctx) ...@@ -567,7 +567,7 @@ init_s2k_key(PGP_Context *ctx)
if (ctx->s2k_cipher_algo < 0) if (ctx->s2k_cipher_algo < 0)
ctx->s2k_cipher_algo = ctx->cipher_algo; ctx->s2k_cipher_algo = ctx->cipher_algo;
res = pgp_s2k_fill(&ctx->s2k, ctx->s2k_mode, ctx->s2k_digest_algo); res = pgp_s2k_fill(&ctx->s2k, ctx->s2k_mode, ctx->s2k_digest_algo, ctx->s2k_count);
if (res < 0) if (res < 0)
return res; return res;
......
...@@ -181,6 +181,7 @@ struct debug_expect ...@@ -181,6 +181,7 @@ struct debug_expect
int expect; int expect;
int cipher_algo; int cipher_algo;
int s2k_mode; int s2k_mode;
int s2k_count;
int s2k_cipher_algo; int s2k_cipher_algo;
int s2k_digest_algo; int s2k_digest_algo;
int compress_algo; int compress_algo;
...@@ -196,6 +197,7 @@ fill_expect(struct debug_expect * ex, int text_mode) ...@@ -196,6 +197,7 @@ fill_expect(struct debug_expect * ex, int text_mode)
ex->expect = 0; ex->expect = 0;
ex->cipher_algo = -1; ex->cipher_algo = -1;
ex->s2k_mode = -1; ex->s2k_mode = -1;
ex->s2k_count = -1;
ex->s2k_cipher_algo = -1; ex->s2k_cipher_algo = -1;
ex->s2k_digest_algo = -1; ex->s2k_digest_algo = -1;
ex->compress_algo = -1; ex->compress_algo = -1;
...@@ -218,6 +220,7 @@ check_expect(PGP_Context *ctx, struct debug_expect * ex) ...@@ -218,6 +220,7 @@ check_expect(PGP_Context *ctx, struct debug_expect * ex)
{ {
EX_CHECK(cipher_algo); EX_CHECK(cipher_algo);
EX_CHECK(s2k_mode); EX_CHECK(s2k_mode);
EX_CHECK(s2k_count);
EX_CHECK(s2k_digest_algo); EX_CHECK(s2k_digest_algo);
EX_CHECK(use_sess_key); EX_CHECK(use_sess_key);
if (ctx->use_sess_key) if (ctx->use_sess_key)
...@@ -247,6 +250,8 @@ set_arg(PGP_Context *ctx, char *key, char *val, ...@@ -247,6 +250,8 @@ set_arg(PGP_Context *ctx, char *key, char *val,
res = pgp_set_sess_key(ctx, atoi(val)); res = pgp_set_sess_key(ctx, atoi(val));
else if (strcmp(key, "s2k-mode") == 0) else if (strcmp(key, "s2k-mode") == 0)
res = pgp_set_s2k_mode(ctx, atoi(val)); res = pgp_set_s2k_mode(ctx, atoi(val));
else if (strcmp(key, "s2k-count") == 0)
res = pgp_set_s2k_count(ctx, atoi(val));
else if (strcmp(key, "s2k-digest-algo") == 0) else if (strcmp(key, "s2k-digest-algo") == 0)
res = pgp_set_s2k_digest_algo(ctx, val); res = pgp_set_s2k_digest_algo(ctx, val);
else if (strcmp(key, "s2k-cipher-algo") == 0) else if (strcmp(key, "s2k-cipher-algo") == 0)
...@@ -286,6 +291,11 @@ set_arg(PGP_Context *ctx, char *key, char *val, ...@@ -286,6 +291,11 @@ set_arg(PGP_Context *ctx, char *key, char *val,
ex->expect = 1; ex->expect = 1;
ex->s2k_mode = atoi(val); ex->s2k_mode = atoi(val);
} }
else if (ex != NULL && strcmp(key, "expect-s2k-count") == 0)
{
ex->expect = 1;
ex->s2k_count = atoi(val);
}
else if (ex != NULL && strcmp(key, "expect-s2k-digest-algo") == 0) else if (ex != NULL && strcmp(key, "expect-s2k-digest-algo") == 0)
{ {
ex->expect = 1; ex->expect = 1;
......
...@@ -132,12 +132,10 @@ calc_s2k_iter_salted(PGP_S2K *s2k, PX_MD *md, const uint8 *key, ...@@ -132,12 +132,10 @@ calc_s2k_iter_salted(PGP_S2K *s2k, PX_MD *md, const uint8 *key,
unsigned preload = 0; unsigned preload = 0;
unsigned remain, unsigned remain,
c, c,
cval,
curcnt, curcnt,
count; count;
cval = s2k->iter; count = s2k_decode_count(s2k->iter);
count = ((unsigned) 16 + (cval & 15)) << ((cval >> 4) + 6);
md_rlen = px_md_result_size(md); md_rlen = px_md_result_size(md);
...@@ -195,21 +193,34 @@ calc_s2k_iter_salted(PGP_S2K *s2k, PX_MD *md, const uint8 *key, ...@@ -195,21 +193,34 @@ calc_s2k_iter_salted(PGP_S2K *s2k, PX_MD *md, const uint8 *key,
} }
/* /*
* Decide S2K_ISALTED iteration count * Decide PGP_S2K_ISALTED iteration count (in OpenPGP one-byte representation)
* *
* Too small: weak * Too small: weak
* Too big: slow * Too big: slow
* gpg defaults to 96 => 65536 iters * gpg defaults to 96 => 65536 iters
* let it float a bit: 96 + 32 => 262144 iters *
* For our default (count=-1) we let it float a bit: 96 + 32 => between 65536
* and 262144 iterations.
*
* Otherwise, find the smallest number which provides at least the specified
* iteration count.
*/ */
static int static uint8
decide_count(unsigned rand_byte) decide_s2k_iter(unsigned rand_byte, int count)
{ {
return 96 + (rand_byte & 0x1F); int iter;
if (count == -1)
return 96 + (rand_byte & 0x1F);
/* this is a bit brute-force, but should be quick enough */
for (iter = 0; iter <= 255; iter++)
if (s2k_decode_count(iter) >= count)
return iter;
return 255;
} }
int int
pgp_s2k_fill(PGP_S2K *s2k, int mode, int digest_algo) pgp_s2k_fill(PGP_S2K *s2k, int mode, int digest_algo, int count)
{ {
int res = 0; int res = 0;
uint8 tmp; uint8 tmp;
...@@ -219,19 +230,19 @@ pgp_s2k_fill(PGP_S2K *s2k, int mode, int digest_algo) ...@@ -219,19 +230,19 @@ pgp_s2k_fill(PGP_S2K *s2k, int mode, int digest_algo)
switch (s2k->mode) switch (s2k->mode)
{ {
case 0: case PGP_S2K_SIMPLE:
break; break;
case 1: case PGP_S2K_SALTED:
res = px_get_pseudo_random_bytes(s2k->salt, PGP_S2K_SALT); res = px_get_pseudo_random_bytes(s2k->salt, PGP_S2K_SALT);
break; break;
case 3: case PGP_S2K_ISALTED:
res = px_get_pseudo_random_bytes(s2k->salt, PGP_S2K_SALT); res = px_get_pseudo_random_bytes(s2k->salt, PGP_S2K_SALT);
if (res < 0) if (res < 0)
break; break;
res = px_get_pseudo_random_bytes(&tmp, 1); res = px_get_pseudo_random_bytes(&tmp, 1);
if (res < 0) if (res < 0)
break; break;
s2k->iter = decide_count(tmp); s2k->iter = decide_s2k_iter(tmp, count);
break; break;
default: default:
res = PXE_PGP_BAD_S2K_MODE; res = PXE_PGP_BAD_S2K_MODE;
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
static int def_cipher_algo = PGP_SYM_AES_128; static int def_cipher_algo = PGP_SYM_AES_128;
static int def_s2k_cipher_algo = -1; static int def_s2k_cipher_algo = -1;
static int def_s2k_mode = PGP_S2K_ISALTED; static int def_s2k_mode = PGP_S2K_ISALTED;
static int def_s2k_count = -1;
static int def_s2k_digest_algo = PGP_DIGEST_SHA1; static int def_s2k_digest_algo = PGP_DIGEST_SHA1;
static int def_compress_algo = PGP_COMPR_NONE; static int def_compress_algo = PGP_COMPR_NONE;
static int def_compress_level = 6; static int def_compress_level = 6;
...@@ -206,6 +207,7 @@ pgp_init(PGP_Context **ctx_p) ...@@ -206,6 +207,7 @@ pgp_init(PGP_Context **ctx_p)
ctx->cipher_algo = def_cipher_algo; ctx->cipher_algo = def_cipher_algo;
ctx->s2k_cipher_algo = def_s2k_cipher_algo; ctx->s2k_cipher_algo = def_s2k_cipher_algo;
ctx->s2k_mode = def_s2k_mode; ctx->s2k_mode = def_s2k_mode;
ctx->s2k_count = def_s2k_count;
ctx->s2k_digest_algo = def_s2k_digest_algo; ctx->s2k_digest_algo = def_s2k_digest_algo;
ctx->compress_algo = def_compress_algo; ctx->compress_algo = def_compress_algo;
ctx->compress_level = def_compress_level; ctx->compress_level = def_compress_level;
...@@ -269,6 +271,17 @@ pgp_set_s2k_mode(PGP_Context *ctx, int mode) ...@@ -269,6 +271,17 @@ pgp_set_s2k_mode(PGP_Context *ctx, int mode)
return err; return err;
} }
int
pgp_set_s2k_count(PGP_Context *ctx, int count)
{
if (ctx->s2k_mode == PGP_S2K_ISALTED && count >= 1024 && count <= 65011712)
{
ctx->s2k_count = count;
return PXE_OK;
}
return PXE_ARGUMENT_ERROR;
}
int int
pgp_set_compress_algo(PGP_Context *ctx, int algo) pgp_set_compress_algo(PGP_Context *ctx, int algo)
{ {
......
...@@ -124,7 +124,7 @@ struct PGP_S2K ...@@ -124,7 +124,7 @@ struct PGP_S2K
uint8 mode; uint8 mode;
uint8 digest_algo; uint8 digest_algo;
uint8 salt[8]; uint8 salt[8];
uint8 iter; uint8 iter; /* encoded (one-octet) count */
/* calculated: */ /* calculated: */
uint8 key[PGP_MAX_KEY]; uint8 key[PGP_MAX_KEY];
uint8 key_len; uint8 key_len;
...@@ -138,6 +138,7 @@ struct PGP_Context ...@@ -138,6 +138,7 @@ struct PGP_Context
*/ */
PGP_S2K s2k; PGP_S2K s2k;
int s2k_mode; int s2k_mode;
int s2k_count; /* 4-byte decoded count */
int s2k_digest_algo; int s2k_digest_algo;
int s2k_cipher_algo; int s2k_cipher_algo;
int cipher_algo; int cipher_algo;
...@@ -171,6 +172,10 @@ struct PGP_Context ...@@ -171,6 +172,10 @@ struct PGP_Context
unsigned sess_key_len; unsigned sess_key_len;
}; };
/* from RFC 4880 3.7.1.3 */
#define s2k_decode_count(cval) \
(((unsigned) 16 + (cval & 15)) << ((cval >> 4) + 6))
struct PGP_MPI struct PGP_MPI
{ {
uint8 *data; uint8 *data;
...@@ -243,6 +248,7 @@ const char *pgp_get_cipher_name(int code); ...@@ -243,6 +248,7 @@ const char *pgp_get_cipher_name(int code);
int pgp_set_cipher_algo(PGP_Context *ctx, const char *name); int pgp_set_cipher_algo(PGP_Context *ctx, const char *name);
int pgp_set_s2k_mode(PGP_Context *ctx, int type); int pgp_set_s2k_mode(PGP_Context *ctx, int type);
int pgp_set_s2k_count(PGP_Context *ctx, int count);
int pgp_set_s2k_cipher_algo(PGP_Context *ctx, const char *name); int pgp_set_s2k_cipher_algo(PGP_Context *ctx, const char *name);
int pgp_set_s2k_digest_algo(PGP_Context *ctx, const char *name); int pgp_set_s2k_digest_algo(PGP_Context *ctx, const char *name);
int pgp_set_convert_crlf(PGP_Context *ctx, int doit); int pgp_set_convert_crlf(PGP_Context *ctx, int doit);
...@@ -267,7 +273,7 @@ int pgp_load_cipher(int c, PX_Cipher **res); ...@@ -267,7 +273,7 @@ int pgp_load_cipher(int c, PX_Cipher **res);
int pgp_get_cipher_key_size(int c); int pgp_get_cipher_key_size(int c);
int pgp_get_cipher_block_size(int c); int pgp_get_cipher_block_size(int c);
int pgp_s2k_fill(PGP_S2K *s2k, int mode, int digest_algo); int pgp_s2k_fill(PGP_S2K *s2k, int mode, int digest_algo, int count);
int pgp_s2k_read(PullFilter *src, PGP_S2K *s2k); int pgp_s2k_read(PullFilter *src, PGP_S2K *s2k);
int pgp_s2k_process(PGP_S2K *s2k, int cipher, const uint8 *key, int klen); int pgp_s2k_process(PGP_S2K *s2k, int cipher, const uint8 *key, int klen);
......
...@@ -55,6 +55,15 @@ select pgp_sym_decrypt( ...@@ -55,6 +55,15 @@ select pgp_sym_decrypt(
pgp_sym_encrypt('Secret.', 'key', 's2k-mode=3'), pgp_sym_encrypt('Secret.', 'key', 's2k-mode=3'),
'key', 'expect-s2k-mode=3'); 'key', 'expect-s2k-mode=3');
-- s2k count change
select pgp_sym_decrypt(
pgp_sym_encrypt('Secret.', 'key', 's2k-count=1024'),
'key', 'expect-s2k-count=1024');
-- s2k_count rounds up
select pgp_sym_decrypt(
pgp_sym_encrypt('Secret.', 'key', 's2k-count=65000000'),
'key', 'expect-s2k-count=65000000');
-- s2k digest change -- s2k digest change
select pgp_sym_decrypt( select pgp_sym_decrypt(
pgp_sym_encrypt('Secret.', 'key', 's2k-digest-algo=md5'), pgp_sym_encrypt('Secret.', 'key', 's2k-digest-algo=md5'),
......
...@@ -858,6 +858,19 @@ Applies to: pgp_sym_encrypt ...@@ -858,6 +858,19 @@ Applies to: pgp_sym_encrypt
</literallayout> </literallayout>
</sect4> </sect4>
<sect4>
<title>s2k-count</title>
<para>
The number of iterations of the S2K algorithm to use. It must
be a value between 1024 and 65011712, inclusive.
</para>
<literallayout>
Default: A random value bewteen 65536 and 253952
Applies to: pgp_sym_encrypt, only with s2k-mode=3
</literallayout>
</sect4>
<sect4> <sect4>
<title>s2k-digest-algo</title> <title>s2k-digest-algo</title>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment