Re: [PATCHES] update to contrib/pgcrypto - Mailing list pgsql-hackers
From | Bruce Momjian |
---|---|
Subject | Re: [PATCHES] update to contrib/pgcrypto |
Date | |
Msg-id | 200101240346.WAA27639@candle.pha.pa.us Whole thread Raw |
In response to | update to contrib/pgcrypto (Marko Kreen <marko@l-t.ee>) |
List | pgsql-hackers |
Thanks. Applied. > > I would like to do a interface change in pgcrypto. (Good > timing, I know :)) At the moment the digest() function returns > hexadecimal coded hash, but I want it to return pure binary. I > have also included functions encode() and decode() which support > 'base64' and 'hex' encodings, so if anyone needs digest() in hex > he can do encode(digest(...), 'hex'). > > Main reason for it is "to do one thing and do it well" :) > > Another reason is if someone needs really lot of digesting, in > the end he wants to store the binary not the hexadecimal result. > It is really silly to convert it to hex then back to binary > again. As I said if someone needs hex he can get it. > > Well, and the real reason that I am doing encrypt()/decrypt() > functions and _they_ return binary. For testing I like to see > it in hex occasionally, but it is really wrong to let them > return hex. Only now it caught my eye that hex-coding in > digest() is wrong. When doing digest() I thought about 'common > case' but hacking with psql is probably _not_ the common case :) > > -- > marko > > > diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/Makefile contrib/pgcrypto/Makefile > --- contrib/pgcrypto.orig/Makefile Tue Oct 31 15:11:28 2000 > +++ contrib/pgcrypto/Makefile Sun Jan 21 00:14:54 2001 > @@ -34,7 +34,7 @@ > endif > > NAME := pgcrypto > -SRCS += pgcrypto.c > +SRCS += pgcrypto.c encode.c > OBJS := $(SRCS:.c=.o) > SO_MAJOR_VERSION = 0 > SO_MINOR_VERSION = 1 > diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/README.pgcrypto contrib/pgcrypto/README.pgcrypto > --- contrib/pgcrypto.orig/README.pgcrypto Tue Oct 31 15:11:28 2000 > +++ contrib/pgcrypto/README.pgcrypto Sun Jan 21 00:21:29 2001 > @@ -1,14 +1,21 @@ > > DESCRIPTION > > - Here is a implementation of crypto hashes for PostgreSQL. > - It exports 2 functions to SQL level: > + Here are various cryptographic and otherwise useful > + functions for PostgreSQL. > + > + encode(data, type) > + encodes binary data into ASCII-only representation. > + Types supported are 'hex' and 'base64'. > + > + decode(data, type) > + decodes the data processed by encode() > > digest(data::text, hash_name::text) > - which returns hexadecimal coded hash over data by > + which returns cryptographic checksum over data by > specified algorithm. eg > > - > select digest('blah', 'sha1'); > + > select encode(digest('blah', 'sha1'), 'hex'); > 5bf1fd927dfb8679496a2e6cf00cbe50c1c87145 > > digest_exists(hash_name::text)::bool > diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/encode.c contrib/pgcrypto/encode.c > --- contrib/pgcrypto.orig/encode.c Thu Jan 1 03:00:00 1970 > +++ contrib/pgcrypto/encode.c Sun Jan 21 23:48:55 2001 > @@ -0,0 +1,345 @@ > +/* > + * 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$ > + */ > + > +#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; > +} > + > diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/encode.h contrib/pgcrypto/encode.h > --- contrib/pgcrypto.orig/encode.h Thu Jan 1 03:00:00 1970 > +++ contrib/pgcrypto/encode.h Sun Jan 21 20:01:01 2001 > @@ -0,0 +1,60 @@ > +/* > + * 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$ > + */ > + > +#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 */ > + > Binary files contrib/pgcrypto.orig/libpgcrypto.so.0 and contrib/pgcrypto/libpgcrypto.so.0 differ > diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/pgcrypto.c contrib/pgcrypto/pgcrypto.c > --- contrib/pgcrypto.orig/pgcrypto.c Wed Jan 10 08:23:22 2001 > +++ contrib/pgcrypto/pgcrypto.c Sun Jan 21 19:59:38 2001 > @@ -35,11 +35,6 @@ > #include "pgcrypto.h" > > /* > - * maximum length of digest for internal buffers > - */ > -#define MAX_DIGEST_LENGTH 128 > - > -/* > * NAMEDATALEN is used for hash names > */ > #if NAMEDATALEN < 16 > @@ -52,8 +47,6 @@ > 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); > > @@ -66,7 +59,6 @@ > { > text *arg; > text *name; > - uint8 *p, buf[MAX_DIGEST_LENGTH]; > uint len, hlen; > pg_digest *h, _hbuf; > text *res; > @@ -78,17 +70,14 @@ > 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); > @@ -141,19 +130,5 @@ > 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; > } > > diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/pgcrypto.sql.in contrib/pgcrypto/pgcrypto.sql.in > --- contrib/pgcrypto.orig/pgcrypto.sql.in Mon Nov 20 22:36:56 2000 > +++ contrib/pgcrypto/pgcrypto.sql.in Sun Jan 21 21:27:48 2001 > @@ -1,6 +1,9 @@ > > -- drop function digest(text, text); > -- drop function digest_exists(text); > +-- drop function encode(text, text); > +-- drop function decode(text, text); > + > > CREATE FUNCTION digest(text, text) RETURNS text > AS '@MODULE_FILENAME@', > @@ -9,4 +12,12 @@ > CREATE FUNCTION digest_exists(text) RETURNS bool > AS '@MODULE_FILENAME@', > 'digest_exists' LANGUAGE 'C'; > + > +CREATE FUNCTION encode(text, text) RETURNS text > + AS '@MODULE_FILENAME@', > + 'encode' LANGUAGE 'C'; > + > +CREATE FUNCTION decode(text, text) RETURNS text > + AS '@MODULE_FILENAME@', > + 'decode' LANGUAGE 'C'; > -- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 853-3000 + If your life is a hard drive, | 830 Blythe Avenue + Christ can be your backup. | Drexel Hill, Pennsylvania 19026
pgsql-hackers by date: