diff --git a/contrib/pgcrypto/expected/pgp-encrypt.out b/contrib/pgcrypto/expected/pgp-encrypt.out index b35de79afa..8fc558c402 100644 --- a/contrib/pgcrypto/expected/pgp-encrypt.out +++ b/contrib/pgcrypto/expected/pgp-encrypt.out @@ -103,6 +103,25 @@ select pgp_sym_decrypt( Secret. (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 select pgp_sym_decrypt( pgp_sym_encrypt('Secret.', 'key', 's2k-digest-algo=md5'), diff --git a/contrib/pgcrypto/pgp-decrypt.c b/contrib/pgcrypto/pgp-decrypt.c index 5c69745156..9ea60c4c47 100644 --- a/contrib/pgcrypto/pgp-decrypt.c +++ b/contrib/pgcrypto/pgp-decrypt.c @@ -643,6 +643,7 @@ parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src) if (res < 0) return res; ctx->s2k_mode = ctx->s2k.mode; + ctx->s2k_count = s2k_decode_count(ctx->s2k.iter); ctx->s2k_digest_algo = ctx->s2k.digest_algo; /* diff --git a/contrib/pgcrypto/pgp-encrypt.c b/contrib/pgcrypto/pgp-encrypt.c index 2320c7574b..c9148fd2fc 100644 --- a/contrib/pgcrypto/pgp-encrypt.c +++ b/contrib/pgcrypto/pgp-encrypt.c @@ -567,7 +567,7 @@ init_s2k_key(PGP_Context *ctx) if (ctx->s2k_cipher_algo < 0) 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) return res; diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c index 1842985e53..1f65b667ca 100644 --- a/contrib/pgcrypto/pgp-pgsql.c +++ b/contrib/pgcrypto/pgp-pgsql.c @@ -181,6 +181,7 @@ struct debug_expect int expect; int cipher_algo; int s2k_mode; + int s2k_count; int s2k_cipher_algo; int s2k_digest_algo; int compress_algo; @@ -196,6 +197,7 @@ fill_expect(struct debug_expect * ex, int text_mode) ex->expect = 0; ex->cipher_algo = -1; ex->s2k_mode = -1; + ex->s2k_count = -1; ex->s2k_cipher_algo = -1; ex->s2k_digest_algo = -1; ex->compress_algo = -1; @@ -218,6 +220,7 @@ check_expect(PGP_Context *ctx, struct debug_expect * ex) { EX_CHECK(cipher_algo); EX_CHECK(s2k_mode); + EX_CHECK(s2k_count); EX_CHECK(s2k_digest_algo); EX_CHECK(use_sess_key); if (ctx->use_sess_key) @@ -247,6 +250,8 @@ set_arg(PGP_Context *ctx, char *key, char *val, res = pgp_set_sess_key(ctx, atoi(val)); else if (strcmp(key, "s2k-mode") == 0) 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) res = pgp_set_s2k_digest_algo(ctx, val); else if (strcmp(key, "s2k-cipher-algo") == 0) @@ -286,6 +291,11 @@ set_arg(PGP_Context *ctx, char *key, char *val, ex->expect = 1; 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) { ex->expect = 1; diff --git a/contrib/pgcrypto/pgp-s2k.c b/contrib/pgcrypto/pgp-s2k.c index 193dd95173..9937d154f2 100644 --- a/contrib/pgcrypto/pgp-s2k.c +++ b/contrib/pgcrypto/pgp-s2k.c @@ -132,12 +132,10 @@ calc_s2k_iter_salted(PGP_S2K *s2k, PX_MD *md, const uint8 *key, unsigned preload = 0; unsigned remain, c, - cval, curcnt, count; - cval = s2k->iter; - count = ((unsigned) 16 + (cval & 15)) << ((cval >> 4) + 6); + count = s2k_decode_count(s2k->iter); md_rlen = px_md_result_size(md); @@ -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 big: slow * 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 -decide_count(unsigned rand_byte) +static uint8 +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 -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; uint8 tmp; @@ -219,19 +230,19 @@ pgp_s2k_fill(PGP_S2K *s2k, int mode, int digest_algo) switch (s2k->mode) { - case 0: + case PGP_S2K_SIMPLE: break; - case 1: + case PGP_S2K_SALTED: res = px_get_pseudo_random_bytes(s2k->salt, PGP_S2K_SALT); break; - case 3: + case PGP_S2K_ISALTED: res = px_get_pseudo_random_bytes(s2k->salt, PGP_S2K_SALT); if (res < 0) break; res = px_get_pseudo_random_bytes(&tmp, 1); if (res < 0) break; - s2k->iter = decide_count(tmp); + s2k->iter = decide_s2k_iter(tmp, count); break; default: res = PXE_PGP_BAD_S2K_MODE; diff --git a/contrib/pgcrypto/pgp.c b/contrib/pgcrypto/pgp.c index 03fe48fb64..0800fc325d 100644 --- a/contrib/pgcrypto/pgp.c +++ b/contrib/pgcrypto/pgp.c @@ -40,6 +40,7 @@ static int def_cipher_algo = PGP_SYM_AES_128; static int def_s2k_cipher_algo = -1; 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_compress_algo = PGP_COMPR_NONE; static int def_compress_level = 6; @@ -206,6 +207,7 @@ pgp_init(PGP_Context **ctx_p) ctx->cipher_algo = def_cipher_algo; ctx->s2k_cipher_algo = def_s2k_cipher_algo; ctx->s2k_mode = def_s2k_mode; + ctx->s2k_count = def_s2k_count; ctx->s2k_digest_algo = def_s2k_digest_algo; ctx->compress_algo = def_compress_algo; ctx->compress_level = def_compress_level; @@ -269,6 +271,17 @@ pgp_set_s2k_mode(PGP_Context *ctx, int mode) 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 pgp_set_compress_algo(PGP_Context *ctx, int algo) { diff --git a/contrib/pgcrypto/pgp.h b/contrib/pgcrypto/pgp.h index 62b8517c27..88f7f8dc48 100644 --- a/contrib/pgcrypto/pgp.h +++ b/contrib/pgcrypto/pgp.h @@ -124,7 +124,7 @@ struct PGP_S2K uint8 mode; uint8 digest_algo; uint8 salt[8]; - uint8 iter; + uint8 iter; /* encoded (one-octet) count */ /* calculated: */ uint8 key[PGP_MAX_KEY]; uint8 key_len; @@ -138,6 +138,7 @@ struct PGP_Context */ PGP_S2K s2k; int s2k_mode; + int s2k_count; /* 4-byte decoded count */ int s2k_digest_algo; int s2k_cipher_algo; int cipher_algo; @@ -171,6 +172,10 @@ struct PGP_Context 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 { uint8 *data; @@ -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_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_digest_algo(PGP_Context *ctx, const char *name); int pgp_set_convert_crlf(PGP_Context *ctx, int doit); @@ -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_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_process(PGP_S2K *s2k, int cipher, const uint8 *key, int klen); diff --git a/contrib/pgcrypto/sql/pgp-encrypt.sql b/contrib/pgcrypto/sql/pgp-encrypt.sql index a9ac0b924b..ed9d2c8127 100644 --- a/contrib/pgcrypto/sql/pgp-encrypt.sql +++ b/contrib/pgcrypto/sql/pgp-encrypt.sql @@ -55,6 +55,15 @@ select pgp_sym_decrypt( pgp_sym_encrypt('Secret.', 'key', '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 select pgp_sym_decrypt( pgp_sym_encrypt('Secret.', 'key', 's2k-digest-algo=md5'), diff --git a/doc/src/sgml/pgcrypto.sgml b/doc/src/sgml/pgcrypto.sgml index bfcbe02f85..21a884bf20 100644 --- a/doc/src/sgml/pgcrypto.sgml +++ b/doc/src/sgml/pgcrypto.sgml @@ -858,6 +858,19 @@ Applies to: pgp_sym_encrypt + + s2k-count + + + The number of iterations of the S2K algorithm to use. It must + be a value between 1024 and 65011712, inclusive. + + +Default: A random value bewteen 65536 and 253952 +Applies to: pgp_sym_encrypt, only with s2k-mode=3 + + + s2k-digest-algo