Skip to content

Commit 35c675a

Browse files
committed
Fortuna fixes. Marko Kreen
1 parent 2787db9 commit 35c675a

File tree

5 files changed

+193
-88
lines changed

5 files changed

+193
-88
lines changed

contrib/pgcrypto/fortuna.c

Lines changed: 108 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2727
* SUCH DAMAGE.
2828
*
29-
* $PostgreSQL: pgsql/contrib/pgcrypto/fortuna.c,v 1.3 2005/07/18 17:09:01 tgl Exp $
29+
* $PostgreSQL: pgsql/contrib/pgcrypto/fortuna.c,v 1.4 2005/07/18 17:12:54 tgl Exp $
3030
*/
3131

3232
#include "postgres.h"
@@ -94,14 +94,16 @@
9494
/* for one big request, reseed after this many bytes */
9595
#define RESEED_BYTES (1024*1024)
9696

97+
/*
98+
* Skip reseed if pool 0 has less than this many
99+
* bytes added since last reseed.
100+
*/
101+
#define POOL0_FILL (256/8)
97102

98103
/*
99104
* Algorithm constants
100105
*/
101106

102-
/* max sources */
103-
#define MAX_SOURCES 8
104-
105107
/* Both cipher key size and hash result size */
106108
#define BLOCK 32
107109

@@ -118,9 +120,11 @@ struct fortuna_state {
118120
uint8 key[BLOCK];
119121
MD_CTX pool[NUM_POOLS];
120122
CIPH_CTX ciph;
121-
unsigned source_pos[MAX_SOURCES];
122123
unsigned reseed_count;
123124
struct timeval last_reseed_time;
125+
unsigned pool0_bytes;
126+
unsigned rnd_pos;
127+
int counter_init;
124128
};
125129
typedef struct fortuna_state FState;
126130

@@ -161,7 +165,6 @@ static void md_result(MD_CTX *ctx, uint8 *dst)
161165
memset(&tmp, 0, sizeof(tmp));
162166
}
163167

164-
165168
/*
166169
* initialize state
167170
*/
@@ -173,6 +176,32 @@ static void init_state(FState *st)
173176
md_init(&st->pool[i]);
174177
}
175178

179+
/*
180+
* Endianess does not matter.
181+
* It just needs to change without repeating.
182+
*/
183+
static void inc_counter(FState *st)
184+
{
185+
uint32 *val = (uint32*)st->counter;
186+
if (++val[0])
187+
return;
188+
if (++val[1])
189+
return;
190+
if (++val[2])
191+
return;
192+
++val[3];
193+
}
194+
195+
/*
196+
* This is called 'cipher in counter mode'.
197+
*/
198+
static void encrypt_counter(FState *st, uint8 *dst)
199+
{
200+
ciph_encrypt(&st->ciph, st->counter, dst);
201+
inc_counter(st);
202+
}
203+
204+
176205
/*
177206
* The time between reseed must be at least RESEED_INTERVAL
178207
* microseconds.
@@ -207,9 +236,8 @@ static void reseed(FState *st)
207236
MD_CTX key_md;
208237
uint8 buf[BLOCK];
209238

210-
/* check frequency */
211-
if (too_often(st))
212-
return;
239+
/* set pool as empty */
240+
st->pool0_bytes = 0;
213241

214242
/*
215243
* Both #0 and #1 reseed would use only pool 0.
@@ -243,82 +271,99 @@ static void reseed(FState *st)
243271
memset(buf, 0, BLOCK);
244272
}
245273

274+
/*
275+
* Pick a random pool. This uses key bytes as random source.
276+
*/
277+
static unsigned get_rand_pool(FState *st)
278+
{
279+
unsigned rnd;
280+
281+
/*
282+
* This slightly prefers lower pools - thats OK.
283+
*/
284+
rnd = st->key[st->rnd_pos] % NUM_POOLS;
285+
286+
st->rnd_pos++;
287+
if (st->rnd_pos >= BLOCK)
288+
st->rnd_pos = 0;
289+
290+
return rnd;
291+
}
292+
246293
/*
247294
* update pools
248295
*/
249-
static void add_entropy(FState *st, unsigned src_id, const uint8 *data, unsigned len)
296+
static void add_entropy(FState *st, const uint8 *data, unsigned len)
250297
{
251298
unsigned pos;
252299
uint8 hash[BLOCK];
253300
MD_CTX md;
254301

255-
/* just in case there's a bug somewhere */
256-
if (src_id >= MAX_SOURCES)
257-
src_id = USER_ENTROPY;
258-
259302
/* hash given data */
260303
md_init(&md);
261304
md_update(&md, data, len);
262305
md_result(&md, hash);
263306

264-
/* update pools round-robin manner */
265-
pos = st->source_pos[src_id];
307+
/*
308+
* Make sure the pool 0 is initialized,
309+
* then update randomly.
310+
*/
311+
if (st->reseed_count == 0 && st->pool0_bytes < POOL0_FILL)
312+
pos = 0;
313+
else
314+
pos = get_rand_pool(st);
266315
md_update( &st->pool[pos], hash, BLOCK);
267316

268-
if (++pos >= NUM_POOLS)
269-
pos = 0;
270-
st->source_pos[src_id] = pos;
317+
if (pos == 0)
318+
st->pool0_bytes += len;
271319

272320
memset(hash, 0, BLOCK);
273321
memset(&md, 0, sizeof(md));
274322
}
275323

276324
/*
277-
* Endianess does not matter.
278-
* It just needs to change without repeating.
325+
* Just take 2 next blocks as new key
279326
*/
280-
static void inc_counter(FState *st)
327+
static void rekey(FState *st)
281328
{
282-
uint32 *val = (uint32*)st->counter;
283-
if (++val[0])
284-
return;
285-
if (++val[1])
286-
return;
287-
if (++val[2])
288-
return;
289-
++val[3];
329+
encrypt_counter(st, st->key);
330+
encrypt_counter(st, st->key + CIPH_BLOCK);
331+
ciph_init(&st->ciph, st->key, BLOCK);
332+
}
333+
334+
/*
335+
* Fortuna relies on AES standing known-plaintext attack.
336+
* In case it does not, slow down the attacker by initialising
337+
* the couter to random value.
338+
*/
339+
static void init_counter(FState *st)
340+
{
341+
/* Use next block as counter. */
342+
encrypt_counter(st, st->counter);
343+
344+
/* Hide the key. */
345+
rekey(st);
346+
347+
/* The counter can be shuffled only once. */
348+
st->counter_init = 1;
290349
}
291350

292351
static void extract_data(FState *st, unsigned count, uint8 *dst)
293352
{
294353
unsigned n;
295354
unsigned block_nr = 0;
296355

297-
/*
298-
* Every request should be with different key,
299-
* if possible.
300-
*/
301-
reseed(st);
356+
/* Can we reseed? */
357+
if (st->pool0_bytes >= POOL0_FILL && !too_often(st))
358+
reseed(st);
302359

303-
/*
304-
* If the reseed didn't happen, don't use the old data
305-
* rather encrypt again.
306-
*/
360+
/* Is counter initialized? */
361+
if (!st->counter_init)
362+
init_counter(st);
307363

308364
while (count > 0) {
309-
/* must not give out too many bytes with one key */
310-
if (block_nr > (RESEED_BYTES / CIPH_BLOCK))
311-
{
312-
reseed(st);
313-
block_nr = 0;
314-
}
315-
316365
/* produce bytes */
317-
ciph_encrypt(&st->ciph, st->counter, st->result);
318-
block_nr++;
319-
320-
/* prepare for next time */
321-
inc_counter(st);
366+
encrypt_counter(st, st->result);
322367

323368
/* copy result */
324369
if (count > CIPH_BLOCK)
@@ -328,7 +373,17 @@ static void extract_data(FState *st, unsigned count, uint8 *dst)
328373
memcpy(dst, st->result, n);
329374
dst += n;
330375
count -= n;
376+
377+
/* must not give out too many bytes with one key */
378+
block_nr++;
379+
if (block_nr > (RESEED_BYTES / CIPH_BLOCK))
380+
{
381+
rekey(st);
382+
block_nr = 0;
383+
}
331384
}
385+
/* Set new key for next request. */
386+
rekey(st);
332387
}
333388

334389
/*
@@ -338,7 +393,7 @@ static void extract_data(FState *st, unsigned count, uint8 *dst)
338393
static FState main_state;
339394
static int init_done = 0;
340395

341-
void fortuna_add_entropy(unsigned src_id, const uint8 *data, unsigned len)
396+
void fortuna_add_entropy(const uint8 *data, unsigned len)
342397
{
343398
if (!init_done)
344399
{
@@ -347,7 +402,7 @@ void fortuna_add_entropy(unsigned src_id, const uint8 *data, unsigned len)
347402
}
348403
if (!data || !len)
349404
return;
350-
add_entropy(&main_state, src_id, data, len);
405+
add_entropy(&main_state, data, len);
351406
}
352407

353408
void fortuna_get_bytes(unsigned len, uint8 *dst)

contrib/pgcrypto/fortuna.h

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,14 @@
2626
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2727
* SUCH DAMAGE.
2828
*
29-
* $PostgreSQL: pgsql/contrib/pgcrypto/fortuna.h,v 1.1 2005/07/10 13:46:28 momjian Exp $
29+
* $PostgreSQL: pgsql/contrib/pgcrypto/fortuna.h,v 1.2 2005/07/18 17:12:54 tgl Exp $
3030
*/
3131

3232
#ifndef __FORTUNA_H
3333
#define __FORTUNA_H
3434

35-
/*
36-
* Event source ID's
37-
*/
38-
#define SYSTEM_ENTROPY 0
39-
#define USER_ENTROPY 1
40-
4135
void fortuna_get_bytes(unsigned len, uint8 *dst);
42-
void fortuna_add_entropy(unsigned src_id, const uint8 *data, unsigned len);
36+
void fortuna_add_entropy(const uint8 *data, unsigned len);
4337

4438
#endif
4539

contrib/pgcrypto/internal.c

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2727
* SUCH DAMAGE.
2828
*
29-
* $PostgreSQL: pgsql/contrib/pgcrypto/internal.c,v 1.21 2005/07/18 17:09:01 tgl Exp $
29+
* $PostgreSQL: pgsql/contrib/pgcrypto/internal.c,v 1.22 2005/07/18 17:12:54 tgl Exp $
3030
*/
3131

3232
#include "postgres.h"
@@ -42,9 +42,22 @@
4242
#include "fortuna.h"
4343

4444
/*
45-
* How often to try to acquire system entropy. (In seconds)
45+
* System reseeds should be separated at least this much.
4646
*/
47-
#define SYSTEM_RESEED_FREQ (3*60*60)
47+
#define SYSTEM_RESEED_MIN (20*60) /* 20 min */
48+
/*
49+
* How often to roll dice.
50+
*/
51+
#define SYSTEM_RESEED_CHECK_TIME (10*60) /* 10 min */
52+
/*
53+
* The chance is x/256 that the reseed happens.
54+
*/
55+
#define SYSTEM_RESEED_CHANCE (4) /* 256/4 * 10min ~ 10h */
56+
57+
/*
58+
* If this much time has passed, force reseed.
59+
*/
60+
#define SYSTEM_RESEED_MAX (12*60*60) /* 12h */
4861

4962

5063
#ifndef MD5_DIGEST_LENGTH
@@ -823,20 +836,40 @@ px_get_pseudo_random_bytes(uint8 *dst, unsigned count)
823836
}
824837

825838
static time_t seed_time = 0;
839+
static time_t check_time = 0;
826840

827841
static void system_reseed(void)
828842
{
829843
uint8 buf[1024];
830844
int n;
831845
time_t t;
846+
int skip = 1;
832847

833848
t = time(NULL);
834-
if (seed_time && (t - seed_time) < SYSTEM_RESEED_FREQ)
849+
850+
if (seed_time == 0)
851+
skip = 0;
852+
else if ((t - seed_time) < SYSTEM_RESEED_MIN)
853+
skip = 1;
854+
else if ((t - seed_time) > SYSTEM_RESEED_MAX)
855+
skip = 0;
856+
else if (!check_time || (t - check_time) > SYSTEM_RESEED_CHECK_TIME)
857+
{
858+
check_time = t;
859+
860+
/* roll dice */
861+
px_get_random_bytes(buf, 1);
862+
skip = buf[0] >= SYSTEM_RESEED_CHANCE;
863+
}
864+
/* clear 1 byte */
865+
memset(buf, 0, sizeof(buf));
866+
867+
if (skip)
835868
return;
836869

837870
n = px_acquire_system_randomness(buf);
838871
if (n > 0)
839-
fortuna_add_entropy(SYSTEM_ENTROPY, buf, n);
872+
fortuna_add_entropy(buf, n);
840873

841874
seed_time = t;
842875
memset(buf, 0, sizeof(buf));
@@ -854,7 +887,7 @@ int
854887
px_add_entropy(const uint8 *data, unsigned count)
855888
{
856889
system_reseed();
857-
fortuna_add_entropy(USER_ENTROPY, data, count);
890+
fortuna_add_entropy(data, count);
858891
return 0;
859892
}
860893

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