--- /dev/null
+/*
+ * encode.c
+ * Various data encoding/decoding things.
+ *
+ * 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: encode.c,v 1.1 2001/01/24 03:46:16 momjian Exp $
+ */
+
+#include <postgres.h>
+#include <fmgr.h>
+
+#include "encode.h"
+
+/*
+ * NAMEDATALEN is used for hash names
+ */
+#if NAMEDATALEN < 16
+#error "NAMEDATALEN < 16: too small"
+#endif
+
+static pg_coding *
+find_coding(pg_coding *hbuf, text *name, int silent);
+static pg_coding *
+pg_find_coding(pg_coding *res, char *name);
+
+
+/* SQL function: encode(bytea, text) returns text */
+PG_FUNCTION_INFO_V1(encode);
+
+Datum
+encode(PG_FUNCTION_ARGS)
+{
+ text *arg;
+ text *name;
+ uint len, rlen, rlen0;
+ pg_coding *c, cbuf;
+ text *res;
+
+ if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
+ PG_RETURN_NULL();
+
+ name = PG_GETARG_TEXT_P(1);
+ c = find_coding(&cbuf, name, 0); /* will give error if fails */
+
+ arg = PG_GETARG_TEXT_P(0);
+ len = VARSIZE(arg) - VARHDRSZ;
+
+ rlen0 = c->encode_len(len);
+
+ res = (text *)palloc(rlen0 + VARHDRSZ);
+
+ rlen = c->encode(VARDATA(arg), len, VARDATA(res));
+ VARATT_SIZEP(res) = rlen + VARHDRSZ;
+
+ if (rlen > rlen0)
+ elog(FATAL, "pg_encode: overflow, encode estimate too small");
+
+ PG_FREE_IF_COPY(arg, 0);
+ PG_FREE_IF_COPY(name, 0);
+
+ PG_RETURN_TEXT_P(res);
+}
+
+/* SQL function: decode(text, text) returns bytea */
+PG_FUNCTION_INFO_V1(decode);
+
+Datum
+decode(PG_FUNCTION_ARGS)
+{
+ text *arg;
+ text *name;
+ uint len, rlen, rlen0;
+ pg_coding *c, cbuf;
+ text *res;
+
+ if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
+ PG_RETURN_NULL();
+
+ name = PG_GETARG_TEXT_P(1);
+ c = find_coding(&cbuf, name, 0); /* will give error if fails */
+
+ arg = PG_GETARG_TEXT_P(0);
+ len = VARSIZE(arg) - VARHDRSZ;
+
+ rlen0 = c->decode_len(len);
+
+ res = (text *)palloc(rlen0 + VARHDRSZ);
+
+ rlen = c->decode(VARDATA(arg), len, VARDATA(res));
+ VARATT_SIZEP(res) = rlen + VARHDRSZ;
+
+ if (rlen > rlen0)
+ elog(FATAL, "pg_decode: overflow, decode estimate too small");
+
+ PG_FREE_IF_COPY(arg, 0);
+ PG_FREE_IF_COPY(name, 0);
+
+ PG_RETURN_TEXT_P(res);
+}
+
+static pg_coding *
+find_coding(pg_coding *dst, text *name, int silent)
+{
+ pg_coding *p;
+ char buf[NAMEDATALEN];
+ uint len;
+
+ len = VARSIZE(name) - VARHDRSZ;
+ if (len >= NAMEDATALEN) {
+ if (silent)
+ return NULL;
+ elog(ERROR, "Encoding type does not exist (name too long)");
+ }
+
+ memcpy(buf, VARDATA(name), len);
+ buf[len] = 0;
+
+ p = pg_find_coding(dst, buf);
+
+ if (p == NULL && !silent)
+ elog(ERROR, "Encoding type does not exist: '%s'", buf);
+ return p;
+}
+
+static char *hextbl = "0123456789abcdef";
+
+uint
+hex_encode(uint8 *src, uint len, uint8 *dst)
+{
+ uint8 *end = src + len;
+ while (src < end) {
+ *dst++ = hextbl[(*src >> 4) & 0xF];
+ *dst++ = hextbl[*src & 0xF];
+ src++;
+ }
+ return len*2;
+}
+
+/* probably should use lookup table */
+static uint8
+get_hex(char c)
+{
+ uint8 res = 0;
+
+ if (c >= '0' && c <= '9')
+ res = c - '0';
+ else if (c >= 'a' && c <= 'f')
+ res = c - 'a' + 10;
+ else if (c >= 'A' && c <= 'F')
+ res = c - 'A' + 10;
+ else
+ elog(ERROR, "Bad hex code: '%c'", c);
+
+ return res;
+}
+
+uint
+hex_decode(uint8 *src, uint len, uint8 *dst)
+{
+ uint8 *s, *srcend, v1, v2, *p = dst;
+
+ srcend = src + len;
+ s = src; p = dst;
+ while (s < srcend) {
+ if (*s == ' ' || *s == '\n' || *s == '\t' || *s == '\r') {
+ s++;
+ continue;
+ }
+ v1 = get_hex(*s++) << 4;
+ if (s >= srcend)
+ elog(ERROR, "hex_decode: invalid data");
+ v2 = get_hex(*s++);
+ *p++ = v1 | v2;
+ }
+
+ return p - dst;
+}
+
+
+static unsigned char _base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+uint
+b64_encode(uint8 *src, uint len, uint8 *dst)
+{
+ uint8 *s, *p, *end = src + len, *lend = dst + 76;
+ int pos = 2;
+ unsigned long buf = 0;
+
+ s = src; p = dst;
+
+ while (s < end) {
+ buf |= *s << (pos << 3);
+ pos--;
+ s++;
+
+ /* write it out */
+ if (pos < 0) {
+ *p++ = _base64[(buf >> 18) & 0x3f];
+ *p++ = _base64[(buf >> 12) & 0x3f];
+ *p++ = _base64[(buf >> 6) & 0x3f];
+ *p++ = _base64[buf & 0x3f];
+
+ pos = 2;
+ buf = 0;
+ }
+ if (p >= lend) {
+ *p++ = '\n';
+ lend = p + 76;
+ }
+ }
+ if (pos != 2) {
+ *p++ = _base64[(buf >> 18) & 0x3f];
+ *p++ = _base64[(buf >> 12) & 0x3f];
+ *p++ = (pos == 0) ? _base64[(buf >> 6) & 0x3f] : '=';
+ *p++ = '=';
+ }
+
+ return p - dst;
+}
+
+/* probably should use lookup table */
+uint
+b64_decode(uint8 *src, uint len, uint8 *dst)
+{
+ char *srcend = src + len, *s = src;
+ uint8 *p = dst;
+ char c;
+ uint b = 0;
+ unsigned long buf = 0;
+ int pos = 0, end = 0;
+
+ while (s < srcend) {
+ c = *s++;
+ if (c >= 'A' && c <= 'Z')
+ b = c - 'A';
+ else if (c >= 'a' && c <= 'z')
+ b = c - 'a' + 26;
+ else if (c >= '0' && c <= '9')
+ b = c - '0' + 52;
+ else if (c == '+')
+ b = 62;
+ else if (c == '/')
+ b = 63;
+ else if (c == '=') {
+ /* end sequence */
+ if (!end) {
+ if (pos == 2) end = 1;
+ else if (pos == 3) end = 2;
+ else
+ elog(ERROR, "base64: unexpected '='");
+ }
+ b = 0;
+ } else if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
+ continue;
+ else
+ elog(ERROR, "base64: Invalid symbol");
+
+ /* add it to buffer */
+ buf = (buf << 6) + b;
+ pos++;
+ if (pos == 4) {
+ *p++ = (buf >> 16) & 255;
+ if (end == 0 || end > 1)
+ *p++ = (buf >> 8) & 255;
+ if (end == 0 || end > 2)
+ *p++ = buf & 255;
+ buf = 0;
+ pos = 0;
+ }
+ }
+
+ if (pos != 0)
+ elog(ERROR, "base64: invalid end sequence");
+
+ return p - dst;
+}
+
+
+uint
+hex_enc_len(uint srclen)
+{
+ return srclen << 1;
+}
+
+uint
+hex_dec_len(uint srclen)
+{
+ return srclen >> 1;
+}
+
+uint
+b64_enc_len(uint srclen)
+{
+ return srclen + (srclen / 3) + (srclen / (76 / 2));
+}
+
+uint
+b64_dec_len(uint srclen)
+{
+ return (srclen * 3) >> 2;
+}
+
+static pg_coding
+encoding_list [] = {
+ { "hex", hex_enc_len, hex_dec_len, hex_encode, hex_decode},
+ { "base64", b64_enc_len, b64_dec_len, b64_encode, b64_decode},
+ { NULL, NULL, NULL, NULL, NULL}
+};
+
+
+static pg_coding *
+pg_find_coding(pg_coding *res, char *name)
+{
+ pg_coding *p;
+ for (p = encoding_list; p->name; p++) {
+ if (!strcasecmp(p->name, name))
+ return p;
+ }
+ return NULL;
+}
+
--- /dev/null
+/*
+ * pg_encode.h
+ * encode.c
+ *
+ * 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: encode.h,v 1.1 2001/01/24 03:46:16 momjian Exp $
+ */
+
+#ifndef __PG_ENCODE_H
+#define __PG_ENCODE_H
+
+/* exported functions */
+Datum encode(PG_FUNCTION_ARGS);
+Datum decode(PG_FUNCTION_ARGS);
+
+typedef struct _pg_coding pg_coding;
+struct _pg_coding {
+ char *name;
+ uint (*encode_len)(uint dlen);
+ uint (*decode_len)(uint dlen);
+ uint (*encode)(uint8 *data, uint dlen, uint8 *res);
+ uint (*decode)(uint8 *data, uint dlen, uint8 *res);
+};
+
+/* They are for outside usage in C code, if needed */
+uint hex_encode(uint8 *src, uint len, uint8 *dst);
+uint hex_decode(uint8 *src, uint len, uint8 *dst);
+uint b64_encode(uint8 *src, uint len, uint8 *dst);
+uint b64_decode(uint8 *src, uint len, uint8 *dst);
+
+uint hex_enc_len(uint srclen);
+uint hex_dec_len(uint srclen);
+uint b64_enc_len(uint srclen);
+uint b64_dec_len(uint srclen);
+
+#endif /* __PG_ENCODE_H */
+
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: pgcrypto.c,v 1.3 2001/01/09 16:07:13 momjian Exp $
+ * $Id: pgcrypto.c,v 1.4 2001/01/24 03:46:16 momjian Exp $
*/
#include <postgres.h>
#include "pgcrypto.h"
-/*
- * maximum length of digest for internal buffers
- */
-#define MAX_DIGEST_LENGTH 128
-
/*
* NAMEDATALEN is used for hash names
*/
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);
{
text *arg;
text *name;
- uint8 *p, buf[MAX_DIGEST_LENGTH];
uint len, hlen;
pg_digest *h, _hbuf;
text *res;
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;
+ res = (text *)palloc(hlen + VARHDRSZ);
+ VARATT_SIZEP(res) = hlen + 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));
+ h->digest(h, VARDATA(arg), len, VARDATA(res));
PG_FREE_IF_COPY(arg, 0);
PG_FREE_IF_COPY(name, 0);
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;
-}
-