aboutsummaryrefslogtreecommitdiff
path: root/contrib/pgcrypto/px.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/pgcrypto/px.c')
-rw-r--r--contrib/pgcrypto/px.c299
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;
+}
+