Skip to content

Commit 188f359

Browse files
committed
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
1 parent b6fb647 commit 188f359

File tree

9 files changed

+98
-16
lines changed

9 files changed

+98
-16
lines changed

contrib/pgcrypto/expected/pgp-encrypt.out

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,25 @@ select pgp_sym_decrypt(
103103
Secret.
104104
(1 row)
105105

106+
-- s2k count change
107+
select pgp_sym_decrypt(
108+
pgp_sym_encrypt('Secret.', 'key', 's2k-count=1024'),
109+
'key', 'expect-s2k-count=1024');
110+
pgp_sym_decrypt
111+
-----------------
112+
Secret.
113+
(1 row)
114+
115+
-- s2k_count rounds up
116+
select pgp_sym_decrypt(
117+
pgp_sym_encrypt('Secret.', 'key', 's2k-count=65000000'),
118+
'key', 'expect-s2k-count=65000000');
119+
NOTICE: pgp_decrypt: unexpected s2k_count: expected 65000000 got 65011712
120+
pgp_sym_decrypt
121+
-----------------
122+
Secret.
123+
(1 row)
124+
106125
-- s2k digest change
107126
select pgp_sym_decrypt(
108127
pgp_sym_encrypt('Secret.', 'key', 's2k-digest-algo=md5'),

contrib/pgcrypto/pgp-decrypt.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,7 @@ parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src)
643643
if (res < 0)
644644
return res;
645645
ctx->s2k_mode = ctx->s2k.mode;
646+
ctx->s2k_count = s2k_decode_count(ctx->s2k.iter);
646647
ctx->s2k_digest_algo = ctx->s2k.digest_algo;
647648

648649
/*

contrib/pgcrypto/pgp-encrypt.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,7 @@ init_s2k_key(PGP_Context *ctx)
567567
if (ctx->s2k_cipher_algo < 0)
568568
ctx->s2k_cipher_algo = ctx->cipher_algo;
569569

570-
res = pgp_s2k_fill(&ctx->s2k, ctx->s2k_mode, ctx->s2k_digest_algo);
570+
res = pgp_s2k_fill(&ctx->s2k, ctx->s2k_mode, ctx->s2k_digest_algo, ctx->s2k_count);
571571
if (res < 0)
572572
return res;
573573

contrib/pgcrypto/pgp-pgsql.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ struct debug_expect
181181
int expect;
182182
int cipher_algo;
183183
int s2k_mode;
184+
int s2k_count;
184185
int s2k_cipher_algo;
185186
int s2k_digest_algo;
186187
int compress_algo;
@@ -196,6 +197,7 @@ fill_expect(struct debug_expect * ex, int text_mode)
196197
ex->expect = 0;
197198
ex->cipher_algo = -1;
198199
ex->s2k_mode = -1;
200+
ex->s2k_count = -1;
199201
ex->s2k_cipher_algo = -1;
200202
ex->s2k_digest_algo = -1;
201203
ex->compress_algo = -1;
@@ -218,6 +220,7 @@ check_expect(PGP_Context *ctx, struct debug_expect * ex)
218220
{
219221
EX_CHECK(cipher_algo);
220222
EX_CHECK(s2k_mode);
223+
EX_CHECK(s2k_count);
221224
EX_CHECK(s2k_digest_algo);
222225
EX_CHECK(use_sess_key);
223226
if (ctx->use_sess_key)
@@ -247,6 +250,8 @@ set_arg(PGP_Context *ctx, char *key, char *val,
247250
res = pgp_set_sess_key(ctx, atoi(val));
248251
else if (strcmp(key, "s2k-mode") == 0)
249252
res = pgp_set_s2k_mode(ctx, atoi(val));
253+
else if (strcmp(key, "s2k-count") == 0)
254+
res = pgp_set_s2k_count(ctx, atoi(val));
250255
else if (strcmp(key, "s2k-digest-algo") == 0)
251256
res = pgp_set_s2k_digest_algo(ctx, val);
252257
else if (strcmp(key, "s2k-cipher-algo") == 0)
@@ -286,6 +291,11 @@ set_arg(PGP_Context *ctx, char *key, char *val,
286291
ex->expect = 1;
287292
ex->s2k_mode = atoi(val);
288293
}
294+
else if (ex != NULL && strcmp(key, "expect-s2k-count") == 0)
295+
{
296+
ex->expect = 1;
297+
ex->s2k_count = atoi(val);
298+
}
289299
else if (ex != NULL && strcmp(key, "expect-s2k-digest-algo") == 0)
290300
{
291301
ex->expect = 1;

contrib/pgcrypto/pgp-s2k.c

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -132,12 +132,10 @@ calc_s2k_iter_salted(PGP_S2K *s2k, PX_MD *md, const uint8 *key,
132132
unsigned preload = 0;
133133
unsigned remain,
134134
c,
135-
cval,
136135
curcnt,
137136
count;
138137

139-
cval = s2k->iter;
140-
count = ((unsigned) 16 + (cval & 15)) << ((cval >> 4) + 6);
138+
count = s2k_decode_count(s2k->iter);
141139

142140
md_rlen = px_md_result_size(md);
143141

@@ -195,21 +193,34 @@ calc_s2k_iter_salted(PGP_S2K *s2k, PX_MD *md, const uint8 *key,
195193
}
196194

197195
/*
198-
* Decide S2K_ISALTED iteration count
196+
* Decide PGP_S2K_ISALTED iteration count (in OpenPGP one-byte representation)
199197
*
200198
* Too small: weak
201199
* Too big: slow
202200
* gpg defaults to 96 => 65536 iters
203-
* let it float a bit: 96 + 32 => 262144 iters
201+
*
202+
* For our default (count=-1) we let it float a bit: 96 + 32 => between 65536
203+
* and 262144 iterations.
204+
*
205+
* Otherwise, find the smallest number which provides at least the specified
206+
* iteration count.
204207
*/
205-
static int
206-
decide_count(unsigned rand_byte)
208+
static uint8
209+
decide_s2k_iter(unsigned rand_byte, int count)
207210
{
208-
return 96 + (rand_byte & 0x1F);
211+
int iter;
212+
213+
if (count == -1)
214+
return 96 + (rand_byte & 0x1F);
215+
/* this is a bit brute-force, but should be quick enough */
216+
for (iter = 0; iter <= 255; iter++)
217+
if (s2k_decode_count(iter) >= count)
218+
return iter;
219+
return 255;
209220
}
210221

211222
int
212-
pgp_s2k_fill(PGP_S2K *s2k, int mode, int digest_algo)
223+
pgp_s2k_fill(PGP_S2K *s2k, int mode, int digest_algo, int count)
213224
{
214225
int res = 0;
215226
uint8 tmp;
@@ -219,19 +230,19 @@ pgp_s2k_fill(PGP_S2K *s2k, int mode, int digest_algo)
219230

220231
switch (s2k->mode)
221232
{
222-
case 0:
233+
case PGP_S2K_SIMPLE:
223234
break;
224-
case 1:
235+
case PGP_S2K_SALTED:
225236
res = px_get_pseudo_random_bytes(s2k->salt, PGP_S2K_SALT);
226237
break;
227-
case 3:
238+
case PGP_S2K_ISALTED:
228239
res = px_get_pseudo_random_bytes(s2k->salt, PGP_S2K_SALT);
229240
if (res < 0)
230241
break;
231242
res = px_get_pseudo_random_bytes(&tmp, 1);
232243
if (res < 0)
233244
break;
234-
s2k->iter = decide_count(tmp);
245+
s2k->iter = decide_s2k_iter(tmp, count);
235246
break;
236247
default:
237248
res = PXE_PGP_BAD_S2K_MODE;

contrib/pgcrypto/pgp.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
static int def_cipher_algo = PGP_SYM_AES_128;
4141
static int def_s2k_cipher_algo = -1;
4242
static int def_s2k_mode = PGP_S2K_ISALTED;
43+
static int def_s2k_count = -1;
4344
static int def_s2k_digest_algo = PGP_DIGEST_SHA1;
4445
static int def_compress_algo = PGP_COMPR_NONE;
4546
static int def_compress_level = 6;
@@ -206,6 +207,7 @@ pgp_init(PGP_Context **ctx_p)
206207
ctx->cipher_algo = def_cipher_algo;
207208
ctx->s2k_cipher_algo = def_s2k_cipher_algo;
208209
ctx->s2k_mode = def_s2k_mode;
210+
ctx->s2k_count = def_s2k_count;
209211
ctx->s2k_digest_algo = def_s2k_digest_algo;
210212
ctx->compress_algo = def_compress_algo;
211213
ctx->compress_level = def_compress_level;
@@ -269,6 +271,17 @@ pgp_set_s2k_mode(PGP_Context *ctx, int mode)
269271
return err;
270272
}
271273

274+
int
275+
pgp_set_s2k_count(PGP_Context *ctx, int count)
276+
{
277+
if (ctx->s2k_mode == PGP_S2K_ISALTED && count >= 1024 && count <= 65011712)
278+
{
279+
ctx->s2k_count = count;
280+
return PXE_OK;
281+
}
282+
return PXE_ARGUMENT_ERROR;
283+
}
284+
272285
int
273286
pgp_set_compress_algo(PGP_Context *ctx, int algo)
274287
{

contrib/pgcrypto/pgp.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ struct PGP_S2K
124124
uint8 mode;
125125
uint8 digest_algo;
126126
uint8 salt[8];
127-
uint8 iter;
127+
uint8 iter; /* encoded (one-octet) count */
128128
/* calculated: */
129129
uint8 key[PGP_MAX_KEY];
130130
uint8 key_len;
@@ -138,6 +138,7 @@ struct PGP_Context
138138
*/
139139
PGP_S2K s2k;
140140
int s2k_mode;
141+
int s2k_count; /* 4-byte decoded count */
141142
int s2k_digest_algo;
142143
int s2k_cipher_algo;
143144
int cipher_algo;
@@ -171,6 +172,10 @@ struct PGP_Context
171172
unsigned sess_key_len;
172173
};
173174

175+
/* from RFC 4880 3.7.1.3 */
176+
#define s2k_decode_count(cval) \
177+
(((unsigned) 16 + (cval & 15)) << ((cval >> 4) + 6))
178+
174179
struct PGP_MPI
175180
{
176181
uint8 *data;
@@ -243,6 +248,7 @@ const char *pgp_get_cipher_name(int code);
243248

244249
int pgp_set_cipher_algo(PGP_Context *ctx, const char *name);
245250
int pgp_set_s2k_mode(PGP_Context *ctx, int type);
251+
int pgp_set_s2k_count(PGP_Context *ctx, int count);
246252
int pgp_set_s2k_cipher_algo(PGP_Context *ctx, const char *name);
247253
int pgp_set_s2k_digest_algo(PGP_Context *ctx, const char *name);
248254
int pgp_set_convert_crlf(PGP_Context *ctx, int doit);
@@ -267,7 +273,7 @@ int pgp_load_cipher(int c, PX_Cipher **res);
267273
int pgp_get_cipher_key_size(int c);
268274
int pgp_get_cipher_block_size(int c);
269275

270-
int pgp_s2k_fill(PGP_S2K *s2k, int mode, int digest_algo);
276+
int pgp_s2k_fill(PGP_S2K *s2k, int mode, int digest_algo, int count);
271277
int pgp_s2k_read(PullFilter *src, PGP_S2K *s2k);
272278
int pgp_s2k_process(PGP_S2K *s2k, int cipher, const uint8 *key, int klen);
273279

contrib/pgcrypto/sql/pgp-encrypt.sql

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,15 @@ select pgp_sym_decrypt(
5555
pgp_sym_encrypt('Secret.', 'key', 's2k-mode=3'),
5656
'key', 'expect-s2k-mode=3');
5757

58+
-- s2k count change
59+
select pgp_sym_decrypt(
60+
pgp_sym_encrypt('Secret.', 'key', 's2k-count=1024'),
61+
'key', 'expect-s2k-count=1024');
62+
-- s2k_count rounds up
63+
select pgp_sym_decrypt(
64+
pgp_sym_encrypt('Secret.', 'key', 's2k-count=65000000'),
65+
'key', 'expect-s2k-count=65000000');
66+
5867
-- s2k digest change
5968
select pgp_sym_decrypt(
6069
pgp_sym_encrypt('Secret.', 'key', 's2k-digest-algo=md5'),

doc/src/sgml/pgcrypto.sgml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,19 @@ Applies to: pgp_sym_encrypt
858858
</literallayout>
859859
</sect4>
860860

861+
<sect4>
862+
<title>s2k-count</title>
863+
864+
<para>
865+
The number of iterations of the S2K algorithm to use. It must
866+
be a value between 1024 and 65011712, inclusive.
867+
</para>
868+
<literallayout>
869+
Default: A random value bewteen 65536 and 253952
870+
Applies to: pgp_sym_encrypt, only with s2k-mode=3
871+
</literallayout>
872+
</sect4>
873+
861874
<sect4>
862875
<title>s2k-digest-algo</title>
863876

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy