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
  [EMAIL PROTECTED]               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Reply via email to