summaryrefslogtreecommitdiff
path: root/contrib/pgcrypto/pgcrypto.c
diff options
context:
space:
mode:
authorPeter Eisentraut2000-10-31 13:11:28 +0000
committerPeter Eisentraut2000-10-31 13:11:28 +0000
commit0c0dde6176edc892bbd39642de08ed1014ce2f7f (patch)
tree4d08f93a269e12aab23f479464d6b399ec654a78 /contrib/pgcrypto/pgcrypto.c
parent73874a06f02691b32c07318e543d83e7947efa51 (diff)
Hashing functions from Marko Kreen <marko@l-t.ee>
Diffstat (limited to 'contrib/pgcrypto/pgcrypto.c')
-rw-r--r--contrib/pgcrypto/pgcrypto.c155
1 files changed, 155 insertions, 0 deletions
diff --git a/contrib/pgcrypto/pgcrypto.c b/contrib/pgcrypto/pgcrypto.c
new file mode 100644
index 00000000000..4897edb9d25
--- /dev/null
+++ b/contrib/pgcrypto/pgcrypto.c
@@ -0,0 +1,155 @@
+/*
+ * pgcrypto.c
+ * Cryptographic digests for PostgreSQL.
+ *
+ * Copyright (c) 2000 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: pgcrypto.c,v 1.1 2000/10/31 13:11:28 petere Exp $
+ */
+
+#include <postgres.h>
+#include <utils/builtins.h>
+
+#include "pgcrypto.h"
+
+/*
+ * maximum length of digest for internal buffers
+ */
+#define MAX_DIGEST_LENGTH 128
+
+/*
+ * NAMEDATALEN is used for hash names
+ */
+#if NAMEDATALEN < 16
+#error "NAMEDATALEN < 16: too small"
+#endif
+
+
+/* exported functions */
+Datum digest(PG_FUNCTION_ARGS);
+Datum digest_exists(PG_FUNCTION_ARGS);
+
+/* private stuff */
+static char *
+to_hex(uint8 *src, uint len, char *dst);
+static pg_digest *
+find_digest(pg_digest *hbuf, text *name, int silent);
+
+
+/* SQL function: hash(text, text) returns text */
+Datum
+digest(PG_FUNCTION_ARGS)
+{
+ text *arg;
+ text *name;
+ uint8 *p, buf[MAX_DIGEST_LENGTH];
+ uint len, hlen;
+ pg_digest *h, _hbuf;
+ text *res;
+
+ if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
+ PG_RETURN_NULL();
+
+ name = PG_GETARG_TEXT_P(1);
+ h = find_digest(&_hbuf, name, 0); /* will give error if fails */
+
+ hlen = h->length(h);
+ if (hlen > MAX_DIGEST_LENGTH)
+ elog(ERROR, "Hash length overflow: %d", hlen);
+
+ res = (text *)palloc(hlen*2 + VARHDRSZ);
+ VARATT_SIZEP(res) = hlen*2 + VARHDRSZ;
+
+ arg = PG_GETARG_TEXT_P(0);
+ len = VARSIZE(arg) - VARHDRSZ;
+
+ p = h->digest(h, VARDATA(arg), len, buf);
+ to_hex(p, hlen, VARDATA(res));
+
+ PG_FREE_IF_COPY(arg, 0);
+ PG_FREE_IF_COPY(name, 0); // unnecessary i guess
+
+ PG_RETURN_TEXT_P(res);
+}
+
+/* check if given hash exists */
+Datum
+digest_exists(PG_FUNCTION_ARGS)
+{
+ text *name;
+ pg_digest _hbuf, *res;
+
+ if (PG_ARGISNULL(0))
+ PG_RETURN_NULL();
+
+ name = PG_GETARG_TEXT_P(0);
+
+ res = find_digest(&_hbuf, name, 1);
+
+ PG_FREE_IF_COPY(name, 0); // unnecessary i guess
+
+ if (res != NULL)
+ PG_RETURN_BOOL(true);
+ PG_RETURN_BOOL(false);
+}
+
+static pg_digest *
+find_digest(pg_digest *hbuf, text *name, int silent)
+{
+ pg_digest *p;
+ char buf[NAMEDATALEN];
+ uint len;
+
+ len = VARSIZE(name) - VARHDRSZ;
+ if (len >= NAMEDATALEN) {
+ if (silent)
+ return NULL;
+ elog(ERROR, "Hash type does not exist (name too long)");
+ }
+
+ memcpy(buf, VARDATA(name), len);
+ buf[len] = 0;
+
+ p = pg_find_digest(hbuf, buf);
+
+ if (p == NULL && !silent)
+ elog(ERROR, "Hash type does not exist: '%s'", buf);
+ return p;
+}
+
+static unsigned char *hextbl = "0123456789abcdef";
+
+/* dumps binary to hex... Note that it does not null-terminate */
+static char *
+to_hex(uint8 *buf, uint len, char *dst)
+{
+ uint i;
+ for (i = 0; i < len; i++) {
+ dst[i*2] = hextbl[(buf[i] >> 4) & 0xF];
+ dst[i*2 + 1] = hextbl[buf[i] & 0xF];
+ }
+ return dst;
+}
+