diff options
Diffstat (limited to 'contrib/pgcrypto/px.c')
-rw-r--r-- | contrib/pgcrypto/px.c | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/contrib/pgcrypto/px.c b/contrib/pgcrypto/px.c new file mode 100644 index 00000000000..b3981be93ce --- /dev/null +++ b/contrib/pgcrypto/px.c @@ -0,0 +1,299 @@ +/* + * px.c + * Various cryptographic stuff for PostgreSQL. + * + * Copyright (c) 2001 Marko Kreen + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: px.c,v 1.1 2001/08/21 01:32:01 momjian Exp $ + */ + +#include <postgres.h> + +#include "px.h" + + +const char * +px_resolve_alias(const PX_Alias *list, const char *name) +{ + while (list->name) { + if (!strcasecmp(list->alias, name)) + return list->name; + list++; + } + return name; +} + +/* + * combo - cipher + padding (+ checksum) + */ + +static uint +combo_encrypt_len(PX_Combo *cx, uint dlen) +{ + return dlen + 512; +} + +static uint +combo_decrypt_len(PX_Combo *cx, uint dlen) +{ + return dlen; +} + +static int +combo_init(PX_Combo *cx, const uint8 *key, uint klen, + const uint8 *iv, uint ivlen) +{ + int err; + uint bs, ks, ivs; + PX_Cipher *c = cx->cipher; + uint8 *ivbuf = NULL; + uint8 *keybuf; + + bs = px_cipher_block_size(c); + ks = px_cipher_key_size(c); + + ivs = px_cipher_iv_size(c); + if (ivs > 0) { + ivbuf = px_alloc(ivs); + memset(ivbuf, 0, ivs); + if (ivlen > ivs) + memcpy(ivbuf, iv, ivs); + else + memcpy(ivbuf, iv, ivlen); + } + + keybuf = px_alloc(ks); + memset(keybuf, 0, ks); + memcpy(keybuf, key, klen); + + err = px_cipher_init(c, keybuf, klen, ivbuf); + + if (ivbuf) + px_free(ivbuf); + + return err; +} + +static int +combo_encrypt(PX_Combo *cx, const uint8 *data, uint dlen, + uint8 *res, uint *rlen) +{ + int err = 0; + uint8 *bbuf; + uint bs, maxlen, bpos, i, pad; + + PX_Cipher *c = cx->cipher; + + bbuf = NULL; + maxlen = *rlen; + bs = px_cipher_block_size(c); + + /* encrypt */ + if (bs > 1) { + bbuf = px_alloc(bs * 4); + bpos = dlen % bs; + *rlen = dlen - bpos; + memcpy(bbuf, data + *rlen, bpos); + + /* encrypt full-block data */ + if (*rlen) { + err = px_cipher_encrypt(c, data, *rlen, res); + if (err) + goto out; + } + + /* bbuf has now bpos bytes of stuff */ + if (cx->padding) { + pad = bs - (bpos % bs); + for (i = 0; i < pad; i++) + bbuf[bpos++] = pad; + } else if (bpos % bs) { + /* ERROR? */ + pad = bs - (bpos % bs); + for (i = 0; i < pad; i++) + bbuf[bpos++] = 0; + } + + /* encrypt the rest - pad */ + if (bpos) { + err = px_cipher_encrypt(c, bbuf, bpos, res + *rlen); + *rlen += bpos; + } + } else { + /* stream cipher/mode - no pad needed */ + err = px_cipher_encrypt(c, data, dlen, res); + if (err) + goto out; + *rlen = dlen; + } +out: + if (bbuf) px_free(bbuf); + + return err; +} + +static int +combo_decrypt(PX_Combo *cx, const uint8 *data, uint dlen, + uint8 *res, uint *rlen) +{ + uint bs, i, pad; + uint pad_ok; + + PX_Cipher *c = cx->cipher; + + bs = px_cipher_block_size(c); + if (bs > 1 && (dlen % bs) != 0) { + goto block_error; + } + + /* decrypt */ + *rlen = dlen; + px_cipher_decrypt(c, data, dlen, res); + + /* unpad */ + if (bs > 1 && cx->padding) { + pad = res[*rlen - 1]; + pad_ok = 0; + if (pad > 0 && pad <= bs && pad <= *rlen) { + pad_ok = 1; + for (i = *rlen - pad; i < *rlen; i++) + if (res[i] != pad) { + pad_ok = 0; + break; + } + } + + if (pad_ok) + *rlen -= pad; + } + + return 0; + + /* error reporting should be done in pgcrypto.c */ +block_error: + elog(NOTICE, "Data not a multiple of block size"); + return -1; +} + +static void +combo_free(PX_Combo *cx) +{ + if (cx->cipher) + px_cipher_free(cx->cipher); + memset(cx, 0, sizeof(*cx)); + px_free(cx); +} + +/* PARSER */ + +static void +parse_cipher_name(char *full, char **cipher, char **pad) +{ + char *p, *p2, *q; + *cipher = full; + *pad = NULL; + + p = strchr(full, '/'); + if (p != NULL) + *p++ = 0; + while (p != NULL) { + if ((q = strchr(p, '/')) != NULL) + *q++ = 0; + + if (!*p) { + p = q; + continue; + } + p2 = strchr(p, ':'); + if (p2 != NULL) { + *p2++ = 0; + if (!strcmp(p, "pad")) { + *pad = p2; + } else { + elog(ERROR, "Unknown component: '%s'", p); + } + } + p = q; + } +} + +/* provider */ + +int +px_find_combo(const char *name, PX_Combo **res) +{ + int err; + char *buf, *s_cipher, *s_pad; + + PX_Combo *cx; + + cx = px_alloc(sizeof(*cx)); + memset(cx, 0, sizeof(*cx)); + + buf = px_alloc(strlen(name) + 1); + strcpy(buf, name); + + parse_cipher_name(buf, &s_cipher, &s_pad); + if (s_cipher == NULL) { + px_free(buf); + px_free(cx); + return -1; + } + + err = px_find_cipher(s_cipher, &cx->cipher); + if (err) + goto err1; + + if (s_pad != NULL) { + if (!strcmp(s_pad, "pkcs")) + cx->padding = 1; + else if (!strcmp(s_pad, "none")) + cx->padding = 0; + else + goto err1; + } else + cx->padding = 1; + + cx->init = combo_init; + cx->encrypt = combo_encrypt; + cx->decrypt = combo_decrypt; + cx->encrypt_len = combo_encrypt_len; + cx->decrypt_len = combo_decrypt_len; + cx->free = combo_free; + + px_free(buf); + + *res = cx; + + return 0; + +err1: + if (cx->cipher) + px_cipher_free(cx->cipher); + px_free(cx); + px_free(buf); + return -1; +} + |