Mention battery-backed cache under hardware selection options.
[PostgreSQL.git] / contrib / pgcrypto / internal.c
blob2d6efb255882d3eaeac3ecd89e1ecfbde456972f
1 /*
2 * internal.c
3 * Wrapper for builtin functions
5 * Copyright (c) 2001 Marko Kreen
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
29 * $PostgreSQL$
32 #include "postgres.h"
34 #include <time.h>
36 #include "px.h"
37 #include "md5.h"
38 #include "sha1.h"
39 #include "sha2.h"
40 #include "blf.h"
41 #include "rijndael.h"
42 #include "fortuna.h"
45 * System reseeds should be separated at least this much.
47 #define SYSTEM_RESEED_MIN (20*60) /* 20 min */
49 * How often to roll dice.
51 #define SYSTEM_RESEED_CHECK_TIME (10*60) /* 10 min */
53 * The chance is x/256 that the reseed happens.
55 #define SYSTEM_RESEED_CHANCE (4) /* 256/4 * 10min ~ 10h */
58 * If this much time has passed, force reseed.
60 #define SYSTEM_RESEED_MAX (12*60*60) /* 12h */
63 #ifndef MD5_DIGEST_LENGTH
64 #define MD5_DIGEST_LENGTH 16
65 #endif
67 #ifndef SHA1_DIGEST_LENGTH
68 #ifdef SHA1_RESULTLEN
69 #define SHA1_DIGEST_LENGTH SHA1_RESULTLEN
70 #else
71 #define SHA1_DIGEST_LENGTH 20
72 #endif
73 #endif
75 #define SHA1_BLOCK_SIZE 64
76 #define MD5_BLOCK_SIZE 64
78 static void init_md5(PX_MD * h);
79 static void init_sha1(PX_MD * h);
81 void init_sha224(PX_MD * h);
82 void init_sha256(PX_MD * h);
83 void init_sha384(PX_MD * h);
84 void init_sha512(PX_MD * h);
86 struct int_digest
88 char *name;
89 void (*init) (PX_MD * h);
92 static const struct int_digest
93 int_digest_list[] = {
94 {"md5", init_md5},
95 {"sha1", init_sha1},
96 {"sha224", init_sha224},
97 {"sha256", init_sha256},
98 {"sha384", init_sha384},
99 {"sha512", init_sha512},
100 {NULL, NULL}
103 /* MD5 */
105 static unsigned
106 int_md5_len(PX_MD * h)
108 return MD5_DIGEST_LENGTH;
111 static unsigned
112 int_md5_block_len(PX_MD * h)
114 return MD5_BLOCK_SIZE;
117 static void
118 int_md5_update(PX_MD * h, const uint8 *data, unsigned dlen)
120 MD5_CTX *ctx = (MD5_CTX *) h->p.ptr;
122 MD5Update(ctx, data, dlen);
125 static void
126 int_md5_reset(PX_MD * h)
128 MD5_CTX *ctx = (MD5_CTX *) h->p.ptr;
130 MD5Init(ctx);
133 static void
134 int_md5_finish(PX_MD * h, uint8 *dst)
136 MD5_CTX *ctx = (MD5_CTX *) h->p.ptr;
138 MD5Final(dst, ctx);
141 static void
142 int_md5_free(PX_MD * h)
144 MD5_CTX *ctx = (MD5_CTX *) h->p.ptr;
146 memset(ctx, 0, sizeof(*ctx));
147 px_free(ctx);
148 px_free(h);
151 /* SHA1 */
153 static unsigned
154 int_sha1_len(PX_MD * h)
156 return SHA1_DIGEST_LENGTH;
159 static unsigned
160 int_sha1_block_len(PX_MD * h)
162 return SHA1_BLOCK_SIZE;
165 static void
166 int_sha1_update(PX_MD * h, const uint8 *data, unsigned dlen)
168 SHA1_CTX *ctx = (SHA1_CTX *) h->p.ptr;
170 SHA1Update(ctx, data, dlen);
173 static void
174 int_sha1_reset(PX_MD * h)
176 SHA1_CTX *ctx = (SHA1_CTX *) h->p.ptr;
178 SHA1Init(ctx);
181 static void
182 int_sha1_finish(PX_MD * h, uint8 *dst)
184 SHA1_CTX *ctx = (SHA1_CTX *) h->p.ptr;
186 SHA1Final(dst, ctx);
189 static void
190 int_sha1_free(PX_MD * h)
192 SHA1_CTX *ctx = (SHA1_CTX *) h->p.ptr;
194 memset(ctx, 0, sizeof(*ctx));
195 px_free(ctx);
196 px_free(h);
199 /* init functions */
201 static void
202 init_md5(PX_MD * md)
204 MD5_CTX *ctx;
206 ctx = px_alloc(sizeof(*ctx));
207 memset(ctx, 0, sizeof(*ctx));
209 md->p.ptr = ctx;
211 md->result_size = int_md5_len;
212 md->block_size = int_md5_block_len;
213 md->reset = int_md5_reset;
214 md->update = int_md5_update;
215 md->finish = int_md5_finish;
216 md->free = int_md5_free;
218 md->reset(md);
221 static void
222 init_sha1(PX_MD * md)
224 SHA1_CTX *ctx;
226 ctx = px_alloc(sizeof(*ctx));
227 memset(ctx, 0, sizeof(*ctx));
229 md->p.ptr = ctx;
231 md->result_size = int_sha1_len;
232 md->block_size = int_sha1_block_len;
233 md->reset = int_sha1_reset;
234 md->update = int_sha1_update;
235 md->finish = int_sha1_finish;
236 md->free = int_sha1_free;
238 md->reset(md);
242 * ciphers generally
245 #define INT_MAX_KEY (512/8)
246 #define INT_MAX_IV (128/8)
248 struct int_ctx
250 uint8 keybuf[INT_MAX_KEY];
251 uint8 iv[INT_MAX_IV];
252 union
254 BlowfishContext bf;
255 rijndael_ctx rj;
256 } ctx;
257 unsigned keylen;
258 int is_init;
259 int mode;
262 static void
263 intctx_free(PX_Cipher * c)
265 struct int_ctx *cx = (struct int_ctx *) c->ptr;
267 if (cx)
269 memset(cx, 0, sizeof *cx);
270 px_free(cx);
272 px_free(c);
276 * AES/rijndael
279 #define MODE_ECB 0
280 #define MODE_CBC 1
282 static unsigned
283 rj_block_size(PX_Cipher * c)
285 return 128 / 8;
288 static unsigned
289 rj_key_size(PX_Cipher * c)
291 return 256 / 8;
294 static unsigned
295 rj_iv_size(PX_Cipher * c)
297 return 128 / 8;
300 static int
301 rj_init(PX_Cipher * c, const uint8 *key, unsigned klen, const uint8 *iv)
303 struct int_ctx *cx = (struct int_ctx *) c->ptr;
305 if (klen <= 128 / 8)
306 cx->keylen = 128 / 8;
307 else if (klen <= 192 / 8)
308 cx->keylen = 192 / 8;
309 else if (klen <= 256 / 8)
310 cx->keylen = 256 / 8;
311 else
312 return PXE_KEY_TOO_BIG;
314 memcpy(&cx->keybuf, key, klen);
316 if (iv)
317 memcpy(cx->iv, iv, 128 / 8);
319 return 0;
322 static int
323 rj_real_init(struct int_ctx * cx, int dir)
325 aes_set_key(&cx->ctx.rj, cx->keybuf, cx->keylen * 8, dir);
326 return 0;
329 static int
330 rj_encrypt(PX_Cipher * c, const uint8 *data, unsigned dlen, uint8 *res)
332 struct int_ctx *cx = (struct int_ctx *) c->ptr;
334 if (!cx->is_init)
336 if (rj_real_init(cx, 1))
337 return PXE_CIPHER_INIT;
340 if (dlen == 0)
341 return 0;
343 if (dlen & 15)
344 return PXE_NOTBLOCKSIZE;
346 memcpy(res, data, dlen);
348 if (cx->mode == MODE_CBC)
350 aes_cbc_encrypt(&cx->ctx.rj, cx->iv, res, dlen);
351 memcpy(cx->iv, res + dlen - 16, 16);
353 else
354 aes_ecb_encrypt(&cx->ctx.rj, res, dlen);
356 return 0;
359 static int
360 rj_decrypt(PX_Cipher * c, const uint8 *data, unsigned dlen, uint8 *res)
362 struct int_ctx *cx = (struct int_ctx *) c->ptr;
364 if (!cx->is_init)
365 if (rj_real_init(cx, 0))
366 return PXE_CIPHER_INIT;
368 if (dlen == 0)
369 return 0;
371 if (dlen & 15)
372 return PXE_NOTBLOCKSIZE;
374 memcpy(res, data, dlen);
376 if (cx->mode == MODE_CBC)
378 aes_cbc_decrypt(&cx->ctx.rj, cx->iv, res, dlen);
379 memcpy(cx->iv, data + dlen - 16, 16);
381 else
382 aes_ecb_decrypt(&cx->ctx.rj, res, dlen);
384 return 0;
388 * initializers
391 static PX_Cipher *
392 rj_load(int mode)
394 PX_Cipher *c;
395 struct int_ctx *cx;
397 c = px_alloc(sizeof *c);
398 memset(c, 0, sizeof *c);
400 c->block_size = rj_block_size;
401 c->key_size = rj_key_size;
402 c->iv_size = rj_iv_size;
403 c->init = rj_init;
404 c->encrypt = rj_encrypt;
405 c->decrypt = rj_decrypt;
406 c->free = intctx_free;
408 cx = px_alloc(sizeof *cx);
409 memset(cx, 0, sizeof *cx);
410 cx->mode = mode;
412 c->ptr = cx;
413 return c;
417 * blowfish
420 static unsigned
421 bf_block_size(PX_Cipher * c)
423 return 8;
426 static unsigned
427 bf_key_size(PX_Cipher * c)
429 return 448 / 8;
432 static unsigned
433 bf_iv_size(PX_Cipher * c)
435 return 8;
438 static int
439 bf_init(PX_Cipher * c, const uint8 *key, unsigned klen, const uint8 *iv)
441 struct int_ctx *cx = (struct int_ctx *) c->ptr;
443 blowfish_setkey(&cx->ctx.bf, key, klen);
444 if (iv)
445 blowfish_setiv(&cx->ctx.bf, iv);
447 return 0;
450 static int
451 bf_encrypt(PX_Cipher * c, const uint8 *data, unsigned dlen, uint8 *res)
453 struct int_ctx *cx = (struct int_ctx *) c->ptr;
454 BlowfishContext *bfctx = &cx->ctx.bf;
456 if (dlen == 0)
457 return 0;
459 if (dlen & 7)
460 return PXE_NOTBLOCKSIZE;
462 memcpy(res, data, dlen);
463 switch (cx->mode)
465 case MODE_ECB:
466 blowfish_encrypt_ecb(res, dlen, bfctx);
467 break;
468 case MODE_CBC:
469 blowfish_encrypt_cbc(res, dlen, bfctx);
470 break;
472 return 0;
475 static int
476 bf_decrypt(PX_Cipher * c, const uint8 *data, unsigned dlen, uint8 *res)
478 struct int_ctx *cx = (struct int_ctx *) c->ptr;
479 BlowfishContext *bfctx = &cx->ctx.bf;
481 if (dlen == 0)
482 return 0;
484 if (dlen & 7)
485 return PXE_NOTBLOCKSIZE;
487 memcpy(res, data, dlen);
488 switch (cx->mode)
490 case MODE_ECB:
491 blowfish_decrypt_ecb(res, dlen, bfctx);
492 break;
493 case MODE_CBC:
494 blowfish_decrypt_cbc(res, dlen, bfctx);
495 break;
497 return 0;
500 static PX_Cipher *
501 bf_load(int mode)
503 PX_Cipher *c;
504 struct int_ctx *cx;
506 c = px_alloc(sizeof *c);
507 memset(c, 0, sizeof *c);
509 c->block_size = bf_block_size;
510 c->key_size = bf_key_size;
511 c->iv_size = bf_iv_size;
512 c->init = bf_init;
513 c->encrypt = bf_encrypt;
514 c->decrypt = bf_decrypt;
515 c->free = intctx_free;
517 cx = px_alloc(sizeof *cx);
518 memset(cx, 0, sizeof *cx);
519 cx->mode = mode;
520 c->ptr = cx;
521 return c;
524 /* ciphers */
526 static PX_Cipher *
527 rj_128_ecb(void)
529 return rj_load(MODE_ECB);
532 static PX_Cipher *
533 rj_128_cbc(void)
535 return rj_load(MODE_CBC);
538 static PX_Cipher *
539 bf_ecb_load(void)
541 return bf_load(MODE_ECB);
544 static PX_Cipher *
545 bf_cbc_load(void)
547 return bf_load(MODE_CBC);
550 struct int_cipher
552 char *name;
553 PX_Cipher *(*load) (void);
556 static const struct int_cipher
557 int_ciphers[] = {
558 {"bf-cbc", bf_cbc_load},
559 {"bf-ecb", bf_ecb_load},
560 {"aes-128-cbc", rj_128_cbc},
561 {"aes-128-ecb", rj_128_ecb},
562 {NULL, NULL}
565 static const PX_Alias int_aliases[] = {
566 {"bf", "bf-cbc"},
567 {"blowfish", "bf-cbc"},
568 {"aes", "aes-128-cbc"},
569 {"aes-ecb", "aes-128-ecb"},
570 {"aes-cbc", "aes-128-cbc"},
571 {"aes-128", "aes-128-cbc"},
572 {"rijndael", "aes-128-cbc"},
573 {"rijndael-128", "aes-128-cbc"},
574 {NULL, NULL}
577 /* PUBLIC FUNCTIONS */
580 px_find_digest(const char *name, PX_MD ** res)
582 const struct int_digest *p;
583 PX_MD *h;
585 for (p = int_digest_list; p->name; p++)
586 if (pg_strcasecmp(p->name, name) == 0)
588 h = px_alloc(sizeof(*h));
589 p->init(h);
591 *res = h;
593 return 0;
595 return PXE_NO_HASH;
599 px_find_cipher(const char *name, PX_Cipher ** res)
601 int i;
602 PX_Cipher *c = NULL;
604 name = px_resolve_alias(int_aliases, name);
606 for (i = 0; int_ciphers[i].name; i++)
607 if (!strcmp(int_ciphers[i].name, name))
609 c = int_ciphers[i].load();
610 break;
613 if (c == NULL)
614 return PXE_NO_CIPHER;
616 *res = c;
617 return 0;
621 * Randomness provider
625 * Use always strong randomness.
628 px_get_pseudo_random_bytes(uint8 *dst, unsigned count)
630 return px_get_random_bytes(dst, count);
633 static time_t seed_time = 0;
634 static time_t check_time = 0;
636 static void
637 system_reseed(void)
639 uint8 buf[1024];
640 int n;
641 time_t t;
642 int skip = 1;
644 t = time(NULL);
646 if (seed_time == 0)
647 skip = 0;
648 else if ((t - seed_time) < SYSTEM_RESEED_MIN)
649 skip = 1;
650 else if ((t - seed_time) > SYSTEM_RESEED_MAX)
651 skip = 0;
652 else if (check_time == 0 ||
653 (t - check_time) > SYSTEM_RESEED_CHECK_TIME)
655 check_time = t;
657 /* roll dice */
658 px_get_random_bytes(buf, 1);
659 skip = buf[0] >= SYSTEM_RESEED_CHANCE;
661 /* clear 1 byte */
662 memset(buf, 0, sizeof(buf));
664 if (skip)
665 return;
667 n = px_acquire_system_randomness(buf);
668 if (n > 0)
669 fortuna_add_entropy(buf, n);
671 seed_time = t;
672 memset(buf, 0, sizeof(buf));
676 px_get_random_bytes(uint8 *dst, unsigned count)
678 system_reseed();
679 fortuna_get_bytes(count, dst);
680 return 0;
684 px_add_entropy(const uint8 *data, unsigned count)
686 system_reseed();
687 fortuna_add_entropy(data, count);
688 return 0;