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:

Previous
From: Bruce Momjian
Date:
Subject: Re: [PATCHES] Small patch to replace 'idle' by 'trans' if transactionis still open
Next
From: "Brett W. McCoy"
Date:
Subject: Re: [GENERAL] re-instalation