Thread: [patch 0/6] pgcrypto update

[patch 0/6] pgcrypto update

From
Marko Kreen
Date:
Here are various updates for pgcrypto that
I've been sitting on for some time now.

They should be applied in order, but otherwise
they stand alone - code should in working state
after each one.

Next update is hopefully pgp_encrypt, which I
have already working, only some final polishing
is missing.

--
marko


[patch 5/6] pseudo random bytes

From
Marko Kreen
Date:
Reserve px_get_random_bytes() for strong randomness,
add new function px_get_pseudo_random_bytes() for
weak randomness and use it in gen_salt().

On openssl case, use RAND_pseudo_bytes() for
px_get_pseudo_random_bytes().

Final result is that is user has not configured random
souce but kept the 'silly' one, gen_salt() keeps
working, but pgp_encrypt() will throw error.


Index: pgsql/contrib/pgcrypto/px-crypt.c
===================================================================
*** pgsql.orig/contrib/pgcrypto/px-crypt.c
--- pgsql/contrib/pgcrypto/px-crypt.c
*************** px_gen_salt(const char *salt_type, char
*** 171,177 ****
              return PXE_BAD_SALT_ROUNDS;
      }

!     res = px_get_random_bytes(rbuf, g->input_len);
      if (res < 0)
          return res;

--- 171,177 ----
              return PXE_BAD_SALT_ROUNDS;
      }

!     res = px_get_pseudo_random_bytes(rbuf, g->input_len);
      if (res < 0)
          return res;

Index: pgsql/contrib/pgcrypto/px.h
===================================================================
*** pgsql.orig/contrib/pgcrypto/px.h
--- pgsql/contrib/pgcrypto/px.h
*************** void        px_free(void *p);
*** 83,88 ****
--- 83,89 ----
  #define PXE_UNKNOWN_SALT_ALGO        -14
  #define PXE_BAD_SALT_ROUNDS            -15
  #define PXE_MCRYPT_INTERNAL            -16
+ #define PXE_NO_RANDOM                -17

  typedef struct px_digest PX_MD;
  typedef struct px_alias PX_Alias;
*************** int            px_find_cipher(const char *name, P
*** 168,173 ****
--- 169,175 ----
  int            px_find_combo(const char *name, PX_Combo ** res);

  int            px_get_random_bytes(uint8 *dst, unsigned count);
+ int            px_get_pseudo_random_bytes(uint8 *dst, unsigned count);

  const char *px_strerror(int err);

Index: pgsql/contrib/pgcrypto/random.c
===================================================================
*** pgsql.orig/contrib/pgcrypto/random.c
--- pgsql/contrib/pgcrypto/random.c
*************** px_get_random_bytes(uint8 *dst, unsigned
*** 78,87 ****
      return res;
  }

  #elif defined(RAND_SILLY)

  int
! px_get_random_bytes(uint8 *dst, unsigned count)
  {
      int            i;

--- 78,93 ----
      return res;
  }

+ int
+ px_get_pseudo_random_bytes(uint8 *dst, unsigned count)
+ {
+     return px_get_random_bytes(dst, count);
+ }
+
  #elif defined(RAND_SILLY)

  int
! px_get_pseudo_random_bytes(uint8 *dst, unsigned count)
  {
      int            i;

*************** px_get_random_bytes(uint8 *dst, unsigned
*** 90,95 ****
--- 96,107 ----
      return i;
  }

+ int
+ px_get_random_bytes(uint8 *dst, unsigned count)
+ {
+     return PXE_NO_RANDOM;
+ }
+
  #elif defined(RAND_OPENSSL)

  #include <openssl/evp.h>
*************** px_get_random_bytes(uint8 *dst, unsigned
*** 99,120 ****

  static int    openssl_random_init = 0;

  int
  px_get_random_bytes(uint8 *dst, unsigned count)
  {
      int            res;

      if (!openssl_random_init)
!     {
!         if (RAND_get_rand_method() == NULL)
!             RAND_set_rand_method(RAND_SSLeay());
!         openssl_random_init = 1;
!     }
!
!     /*
!      * OpenSSL random should re-feeded occasionally. From /dev/urandom
!      * preferably.
!      */

      res = RAND_bytes(dst, count);
      if (res == 1)
--- 111,134 ----

  static int    openssl_random_init = 0;

+ /*
+  * OpenSSL random should re-feeded occasionally. From /dev/urandom
+  * preferably.
+  */
+ static void init_openssl()
+ {
+     if (RAND_get_rand_method() == NULL)
+         RAND_set_rand_method(RAND_SSLeay());
+     openssl_random_init = 1;
+ }
+
  int
  px_get_random_bytes(uint8 *dst, unsigned count)
  {
      int            res;

      if (!openssl_random_init)
!         init_openssl();

      res = RAND_bytes(dst, count);
      if (res == 1)
*************** px_get_random_bytes(uint8 *dst, unsigned
*** 123,128 ****
--- 137,157 ----
      return PXE_OSSL_RAND_ERROR;
  }

+ int
+ px_get_pseudo_random_bytes(uint8 *dst, unsigned count)
+ {
+     int            res;
+
+     if (!openssl_random_init)
+         init_openssl();
+
+     res = RAND_pseudo_bytes(dst, count);
+     if (res == 0 || res == 1)
+         return count;
+
+     return PXE_OSSL_RAND_ERROR;
+ }
+
  #else
  #error "Invalid random source"
  #endif
Index: pgsql/contrib/pgcrypto/px.c
===================================================================
*** pgsql.orig/contrib/pgcrypto/px.c
--- pgsql/contrib/pgcrypto/px.c
*************** static const struct error_desc px_err_li
*** 56,61 ****
--- 56,62 ----
      {PXE_UNKNOWN_SALT_ALGO, "Unknown salt algorithm"},
      {PXE_BAD_SALT_ROUNDS, "Incorrect number of rounds"},
      {PXE_MCRYPT_INTERNAL, "mcrypt internal error"},
+     {PXE_NO_RANDOM, "No strong random source"},
      {0, NULL},
  };


--

[patch 3/6] better error handling

From
Marko Kreen
Date:
* Use error codes instead of -1
* px_strerror for new error codes
* calling convention change for px_gen_salt - return error code
* use px_strerror in pgcrypto.c


Index: pgsql/contrib/pgcrypto/px.c
===================================================================
*** pgsql.orig/contrib/pgcrypto/px.c
--- pgsql/contrib/pgcrypto/px.c
***************
*** 33,38 ****
--- 33,73 ----

  #include "px.h"

+ struct error_desc {
+     int err;
+     const char *desc;
+ };
+
+ static const struct error_desc px_err_list[] = {
+     {PXE_OK, "Everything ok"},
+     {PXE_ERR_GENERIC, "Some PX error (not specified)"},
+     {PXE_NO_HASH, "No such hash algorithm"},
+     {PXE_NO_CIPHER, "No such cipher algorithm"},
+     {PXE_NOTBLOCKSIZE, "Data not a multiple of block size"},
+     {PXE_BAD_OPTION, "Unknown option"},
+     {PXE_BAD_FORMAT, "Badly formatted type"},
+     {PXE_KEY_TOO_BIG, "Key was too big"},
+     {PXE_CIPHER_INIT, "Cipher cannot be initalized ?"},
+     {PXE_HASH_UNUSABLE_FOR_HMAC, "This hash algorithm is unusable for HMAC"},
+     {PXE_DEV_READ_ERROR, "Error reading from random device"},
+     {PXE_OSSL_RAND_ERROR, "OpenSSL PRNG error"},
+     {PXE_BUG, "pgcrypto bug"},
+     {PXE_ARGUMENT_ERROR, "Illegal argument to function"},
+     {PXE_UNKNOWN_SALT_ALGO, "Unknown salt algorithm"},
+     {PXE_BAD_SALT_ROUNDS, "Incorrect number of rounds"},
+     {PXE_MCRYPT_INTERNAL, "mcrypt internal error"},
+     {0, NULL},
+ };
+
+ const char *px_strerror(int err)
+ {
+     const struct error_desc *e;
+     for (e = px_err_list; e->desc; e++)
+         if (e->err == err)
+             return e->desc;
+     return "Bad error code";
+ }
+

  const char *
  px_resolve_alias(const PX_Alias * list, const char *name)
*************** combo_decrypt(PX_Combo * cx, const uint8
*** 215,224 ****

      return 0;

-     /* error reporting should be done in pgcrypto.c */
  block_error:
!     elog(WARNING, "Data not a multiple of block size");
!     return -1;
  }

  static void
--- 250,257 ----

      return 0;

  block_error:
!     return PXE_NOTBLOCKSIZE;
  }

  static void
*************** parse_cipher_name(char *full, char **cip
*** 262,271 ****
              if (!strcmp(p, "pad"))
                  *pad = p2;
              else
!                 return -1;
          }
          else
!             return -1;

          p = q;
      }
--- 295,304 ----
              if (!strcmp(p, "pad"))
                  *pad = p2;
              else
!                 return PXE_BAD_OPTION;
          }
          else
!             return PXE_BAD_FORMAT;

          p = q;
      }
*************** err1:
*** 332,336 ****
          px_cipher_free(cx->cipher);
      px_free(cx);
      px_free(buf);
!     return -1;
  }
--- 365,369 ----
          px_cipher_free(cx->cipher);
      px_free(cx);
      px_free(buf);
!     return PXE_NO_CIPHER;
  }
Index: pgsql/contrib/pgcrypto/px.h
===================================================================
*** pgsql.orig/contrib/pgcrypto/px.h
--- pgsql/contrib/pgcrypto/px.h
*************** void        px_free(void *p);
*** 63,68 ****
--- 63,88 ----
  /* max salt returned */
  #define PX_MAX_SALT_LEN        128

+ /*
+  * PX error codes
+  */
+ #define PXE_OK                        0
+ #define PXE_ERR_GENERIC                -1
+ #define PXE_NO_HASH                    -2
+ #define PXE_NO_CIPHER                -3
+ #define PXE_NOTBLOCKSIZE            -4
+ #define PXE_BAD_OPTION                -5
+ #define PXE_BAD_FORMAT                -6
+ #define PXE_KEY_TOO_BIG                -7
+ #define PXE_CIPHER_INIT                -8
+ #define PXE_HASH_UNUSABLE_FOR_HMAC    -9
+ #define PXE_DEV_READ_ERROR            -10
+ #define PXE_OSSL_RAND_ERROR            -11
+ #define PXE_BUG                        -12
+ #define PXE_ARGUMENT_ERROR            -13
+ #define PXE_UNKNOWN_SALT_ALGO        -14
+ #define PXE_BAD_SALT_ROUNDS            -15
+ #define PXE_MCRYPT_INTERNAL            -16

  typedef struct px_digest PX_MD;
  typedef struct px_alias PX_Alias;
*************** int            px_find_combo(const char *name, PX
*** 149,154 ****
--- 169,176 ----

  int            px_get_random_bytes(uint8 *dst, unsigned count);

+ const char *px_strerror(int err);
+
  const char *px_resolve_alias(const PX_Alias * aliases, const char *name);

  #define px_md_result_size(md)        (md)->result_size(md)
Index: pgsql/contrib/pgcrypto/internal.c
===================================================================
*** pgsql.orig/contrib/pgcrypto/internal.c
--- pgsql/contrib/pgcrypto/internal.c
*************** rj_init(PX_Cipher * c, const uint8 *key,
*** 275,281 ****
      else if (klen <= 256 / 8)
          cx->keylen = 256 / 8;
      else
!         return -1;

      memcpy(&cx->keybuf, key, klen);

--- 275,281 ----
      else if (klen <= 256 / 8)
          cx->keylen = 256 / 8;
      else
!         return PXE_KEY_TOO_BIG;

      memcpy(&cx->keybuf, key, klen);

*************** rj_encrypt(PX_Cipher * c, const uint8 *d
*** 300,313 ****
      if (!cx->is_init)
      {
          if (rj_real_init(cx, 1))
!             return -1;
      }

      if (dlen == 0)
          return 0;

      if (dlen & 15)
!         return -1;

      memcpy(res, data, dlen);

--- 300,313 ----
      if (!cx->is_init)
      {
          if (rj_real_init(cx, 1))
!             return PXE_CIPHER_INIT;
      }

      if (dlen == 0)
          return 0;

      if (dlen & 15)
!         return PXE_NOTBLOCKSIZE;

      memcpy(res, data, dlen);

*************** rj_decrypt(PX_Cipher * c, const uint8 *d
*** 329,341 ****

      if (!cx->is_init)
          if (rj_real_init(cx, 0))
!             return -1;

      if (dlen == 0)
          return 0;

      if (dlen & 15)
!         return -1;

      memcpy(res, data, dlen);

--- 329,341 ----

      if (!cx->is_init)
          if (rj_real_init(cx, 0))
!             return PXE_CIPHER_INIT;

      if (dlen == 0)
          return 0;

      if (dlen & 15)
!         return PXE_NOTBLOCKSIZE;

      memcpy(res, data, dlen);

*************** bf_encrypt(PX_Cipher * c, const uint8 *d
*** 422,428 ****
          return 0;

      if (dlen & 7)
!         return -1;

      memcpy(res, data, dlen);
      switch (cx->mode)
--- 422,428 ----
          return 0;

      if (dlen & 7)
!         return PXE_NOTBLOCKSIZE;

      memcpy(res, data, dlen);
      switch (cx->mode)
*************** bf_decrypt(PX_Cipher * c, const uint8 *d
*** 446,452 ****
          return 0;

      if (dlen & 7)
!         return -1;

      memcpy(res, data, dlen);
      switch (cx->mode)
--- 446,452 ----
          return 0;

      if (dlen & 7)
!         return PXE_NOTBLOCKSIZE;

      memcpy(res, data, dlen);
      switch (cx->mode)
*************** px_find_digest(const char *name, PX_MD *
*** 556,562 ****

              return 0;
          }
!     return -1;
  }

  int
--- 556,562 ----

              return 0;
          }
!     return PXE_NO_HASH;
  }

  int
*************** px_find_cipher(const char *name, PX_Ciph
*** 575,581 ****
          }

      if (c == NULL)
!         return -1;

      *res = c;
      return 0;
--- 575,581 ----
          }

      if (c == NULL)
!         return PXE_NO_CIPHER;

      *res = c;
      return 0;
Index: pgsql/contrib/pgcrypto/openssl.c
===================================================================
*** pgsql.orig/contrib/pgcrypto/openssl.c
--- pgsql/contrib/pgcrypto/openssl.c
*************** px_find_digest(const char *name, PX_MD *
*** 112,118 ****

      md = EVP_get_digestbyname(name);
      if (md == NULL)
!         return -1;

      ctx = px_alloc(sizeof(*ctx));
      EVP_DigestInit(ctx, md);
--- 112,118 ----

      md = EVP_get_digestbyname(name);
      if (md == NULL)
!         return PXE_NO_HASH;

      ctx = px_alloc(sizeof(*ctx));
      EVP_DigestInit(ctx, md);
*************** px_find_cipher(const char *name, PX_Ciph
*** 504,510 ****
          if (!strcmp(i->name, name))
              break;
      if (i->name == NULL)
!         return -1;

      od = px_alloc(sizeof(*od));
      memset(od, 0, sizeof(*od));
--- 504,510 ----
          if (!strcmp(i->name, name))
              break;
      if (i->name == NULL)
!         return PXE_NO_CIPHER;

      od = px_alloc(sizeof(*od));
      memset(od, 0, sizeof(*od));
Index: pgsql/contrib/pgcrypto/px-hmac.c
===================================================================
*** pgsql.orig/contrib/pgcrypto/px-hmac.c
--- pgsql/contrib/pgcrypto/px-hmac.c
*************** px_find_hmac(const char *name, PX_HMAC *
*** 158,164 ****
      if (bs < 2)
      {
          px_md_free(md);
!         return -1;
      }

      h = px_alloc(sizeof(*h));
--- 158,164 ----
      if (bs < 2)
      {
          px_md_free(md);
!         return PXE_HASH_UNUSABLE_FOR_HMAC;
      }

      h = px_alloc(sizeof(*h));
Index: pgsql/contrib/pgcrypto/random.c
===================================================================
*** pgsql.orig/contrib/pgcrypto/random.c
--- pgsql/contrib/pgcrypto/random.c
*************** safe_read(int fd, void *buf, size_t coun
*** 55,61 ****
          {
              if (errno == EINTR)
                  continue;
!             return -1;
          }
          p += res;
          done += res;
--- 55,61 ----
          {
              if (errno == EINTR)
                  continue;
!             return PXE_DEV_READ_ERROR;
          }
          p += res;
          done += res;
*************** px_get_random_bytes(uint8 *dst, unsigned
*** 72,78 ****

      fd = open(RAND_DEV, O_RDONLY);
      if (fd == -1)
!         return -1;
      res = safe_read(fd, dst, count);
      close(fd);
      return res;
--- 72,78 ----

      fd = open(RAND_DEV, O_RDONLY);
      if (fd == -1)
!         return PXE_DEV_READ_ERROR;
      res = safe_read(fd, dst, count);
      close(fd);
      return res;
*************** px_get_random_bytes(uint8 *dst, unsigned
*** 117,126 ****
       */

      res = RAND_bytes(dst, count);
!     if (res > 0)
          return count;

!     return -1;
  }

  #else
--- 117,126 ----
       */

      res = RAND_bytes(dst, count);
!     if (res == 1)
          return count;

!     return PXE_OSSL_RAND_ERROR;
  }

  #else
Index: pgsql/contrib/pgcrypto/px-crypt.c
===================================================================
*** pgsql.orig/contrib/pgcrypto/px-crypt.c
--- pgsql/contrib/pgcrypto/px-crypt.c
*************** static struct generator gen_list[] = {
*** 147,185 ****
      {NULL, NULL, 0, 0, 0, 0}
  };

! unsigned
  px_gen_salt(const char *salt_type, char *buf, int rounds)
  {
!     int            i,
!                 res;
      struct generator *g;
      char       *p;
      char        rbuf[16];

!     for (i = 0; gen_list[i].name; i++)
!     {
!         g = &gen_list[i];
!         if (pg_strcasecmp(g->name, salt_type) != 0)
!             continue;
!
!         if (g->def_rounds)
!         {
!             if (rounds == 0)
!                 rounds = g->def_rounds;
!
!             if (rounds < g->min_rounds || rounds > g->max_rounds)
!                 return 0;
!         }
!
!         res = px_get_random_bytes(rbuf, g->input_len);
!         if (res != g->input_len)
!             return 0;

!         p = g->gen(rounds, rbuf, g->input_len, buf, PX_MAX_SALT_LEN);
!         memset(rbuf, 0, sizeof(rbuf));

!         return p != NULL ? strlen(p) : 0;
      }

!     return 0;
  }
--- 147,186 ----
      {NULL, NULL, 0, 0, 0, 0}
  };

! int
  px_gen_salt(const char *salt_type, char *buf, int rounds)
  {
!     int            res;
      struct generator *g;
      char       *p;
      char        rbuf[16];

!     for (g = gen_list; g->name; g++)
!         if (pg_strcasecmp(g->name, salt_type) == 0)
!             break;
!
!     if (g->name == NULL)
!         return PXE_UNKNOWN_SALT_ALGO;

!     if (g->def_rounds)
!     {
!         if (rounds == 0)
!             rounds = g->def_rounds;

!         if (rounds < g->min_rounds || rounds > g->max_rounds)
!             return PXE_BAD_SALT_ROUNDS;
      }

!     res = px_get_random_bytes(rbuf, g->input_len);
!     if (res < 0)
!         return res;
!
!     p = g->gen(rounds, rbuf, g->input_len, buf, PX_MAX_SALT_LEN);
!     memset(rbuf, 0, sizeof(rbuf));
!
!     if (p == NULL)
!         return PXE_BAD_SALT_ROUNDS;
!
!     return strlen(p);
  }
+
Index: pgsql/contrib/pgcrypto/px-crypt.h
===================================================================
*** pgsql.orig/contrib/pgcrypto/px-crypt.h
--- pgsql/contrib/pgcrypto/px-crypt.h
***************
*** 49,55 ****
   * main interface
   */
  char       *px_crypt(const char *psw, const char *salt, char *buf, unsigned buflen);
! unsigned    px_gen_salt(const char *salt_type, char *dst, int rounds);

  /*
   * internal functions
--- 49,55 ----
   * main interface
   */
  char       *px_crypt(const char *psw, const char *salt, char *buf, unsigned buflen);
! int            px_gen_salt(const char *salt_type, char *dst, int rounds);

  /*
   * internal functions
Index: pgsql/contrib/pgcrypto/pgcrypto.c
===================================================================
*** pgsql.orig/contrib/pgcrypto/pgcrypto.c
--- pgsql/contrib/pgcrypto/pgcrypto.c
*************** Datum
*** 190,196 ****
  pg_gen_salt(PG_FUNCTION_ARGS)
  {
      text       *arg0;
!     unsigned    len;
      text       *res;
      char        buf[PX_MAX_SALT_LEN + 1];

--- 190,196 ----
  pg_gen_salt(PG_FUNCTION_ARGS)
  {
      text       *arg0;
!     int            len;
      text       *res;
      char        buf[PX_MAX_SALT_LEN + 1];

*************** pg_gen_salt(PG_FUNCTION_ARGS)
*** 204,213 ****
      memcpy(buf, VARDATA(arg0), len);
      buf[len] = 0;
      len = px_gen_salt(buf, buf, 0);
!     if (len == 0)
          ereport(ERROR,
                  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
!                  errmsg("no such crypt algorithm")));

      res = (text *) palloc(len + VARHDRSZ);
      VARATT_SIZEP(res) = len + VARHDRSZ;
--- 204,213 ----
      memcpy(buf, VARDATA(arg0), len);
      buf[len] = 0;
      len = px_gen_salt(buf, buf, 0);
!     if (len < 0)
          ereport(ERROR,
                  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
!                  errmsg("gen_salt: %s", px_strerror(len))));

      res = (text *) palloc(len + VARHDRSZ);
      VARATT_SIZEP(res) = len + VARHDRSZ;
*************** pg_gen_salt_rounds(PG_FUNCTION_ARGS)
*** 226,232 ****
  {
      text       *arg0;
      int            rounds;
!     unsigned    len;
      text       *res;
      char        buf[PX_MAX_SALT_LEN + 1];

--- 226,232 ----
  {
      text       *arg0;
      int            rounds;
!     int            len;
      text       *res;
      char        buf[PX_MAX_SALT_LEN + 1];

*************** pg_gen_salt_rounds(PG_FUNCTION_ARGS)
*** 241,250 ****
      memcpy(buf, VARDATA(arg0), len);
      buf[len] = 0;
      len = px_gen_salt(buf, buf, rounds);
!     if (len == 0)
          ereport(ERROR,
                  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
!              errmsg("no such crypt algorithm or bad number of rounds")));

      res = (text *) palloc(len + VARHDRSZ);
      VARATT_SIZEP(res) = len + VARHDRSZ;
--- 241,250 ----
      memcpy(buf, VARDATA(arg0), len);
      buf[len] = 0;
      len = px_gen_salt(buf, buf, rounds);
!     if (len < 0)
          ereport(ERROR,
                  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
!              errmsg("gen_salt: %s", px_strerror(len))));

      res = (text *) palloc(len + VARHDRSZ);
      VARATT_SIZEP(res) = len + VARHDRSZ;
*************** pg_encrypt(PG_FUNCTION_ARGS)
*** 360,366 ****
          pfree(res);
          ereport(ERROR,
                  (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
!                  errmsg("encrypt error: %d", err)));
      }

      VARATT_SIZEP(res) = VARHDRSZ + rlen;
--- 360,366 ----
          pfree(res);
          ereport(ERROR,
                  (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
!                  errmsg("encrypt error: %s", px_strerror(err))));
      }

      VARATT_SIZEP(res) = VARHDRSZ + rlen;
*************** pg_decrypt(PG_FUNCTION_ARGS)
*** 406,412 ****
      if (err)
          ereport(ERROR,
                  (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
!                  errmsg("decrypt error: %d", err)));

      VARATT_SIZEP(res) = VARHDRSZ + rlen;

--- 406,412 ----
      if (err)
          ereport(ERROR,
                  (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
!                  errmsg("decrypt error: %s", px_strerror(err))));

      VARATT_SIZEP(res) = VARHDRSZ + rlen;

*************** pg_encrypt_iv(PG_FUNCTION_ARGS)
*** 461,467 ****
      if (err)
          ereport(ERROR,
                  (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
!                  errmsg("encrypt_iv error: %d", err)));

      VARATT_SIZEP(res) = VARHDRSZ + rlen;

--- 461,467 ----
      if (err)
          ereport(ERROR,
                  (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
!                  errmsg("encrypt_iv error: %s", px_strerror(err))));

      VARATT_SIZEP(res) = VARHDRSZ + rlen;

*************** pg_decrypt_iv(PG_FUNCTION_ARGS)
*** 517,523 ****
      if (err)
          ereport(ERROR,
                  (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
!                  errmsg("decrypt_iv error: %d", err)));

      VARATT_SIZEP(res) = VARHDRSZ + rlen;

--- 517,523 ----
      if (err)
          ereport(ERROR,
                  (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
!                  errmsg("decrypt_iv error: %s", px_strerror(err))));

      VARATT_SIZEP(res) = VARHDRSZ + rlen;

*************** find_provider(text *name,
*** 568,574 ****
      if (err && !silent)
          ereport(ERROR,
                  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
!                  errmsg("%s type does not exist: \"%s\"", desc, buf)));

      pfree(buf);

--- 568,574 ----
      if (err && !silent)
          ereport(ERROR,
                  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
!                  errmsg("Cannot use \"%s\": %s", buf, px_strerror(err))));

      pfree(buf);


--

[patch 2/6] various cleanups

From
Marko Kreen
Date:
* construct "struct {} list [] = {}" confuses pgindent - split those.
  It was a bad style to begin with, and now several loops can be clearer.
* pgcrypto.c: Fix function comments
* crypt-gensalt.c, crypt-blowfish.c: stop messing with errno
* openssl.c: use px_free instead pfree
* px.h: make redefining px_alloc/px_realloc/px_free easier


Index: pgsql/contrib/pgcrypto/openssl.c
===================================================================
*** pgsql.orig/contrib/pgcrypto/openssl.c
--- pgsql/contrib/pgcrypto/openssl.c
*************** gen_ossl_free(PX_Cipher * c)
*** 208,215 ****
      ossldata   *od = (ossldata *) c->ptr;

      memset(od, 0, sizeof(*od));
!     pfree(od);
!     pfree(c);
  }

  /* Blowfish */
--- 208,215 ----
      ossldata   *od = (ossldata *) c->ptr;

      memset(od, 0, sizeof(*od));
!     px_free(od);
!     px_free(c);
  }

  /* Blowfish */
*************** static const struct ossl_cipher ossl_cas
*** 473,509 ****
  /*
   * Special handlers
   */
! static const struct
  {
      const char *name;
      const struct ossl_cipher *ciph;
! }    ossl_cipher_types[] =

! {
!     {
!         "bf-cbc", &ossl_bf_cbc
!     },
!     {
!         "bf-ecb", &ossl_bf_ecb
!     },
!     {
!         "bf-cfb", &ossl_bf_cfb
!     },
!     {
!         "des-ecb", &ossl_des_ecb
!     },
!     {
!         "des-cbc", &ossl_des_cbc
!     },
!     {
!         "cast5-ecb", &ossl_cast_ecb
!     },
!     {
!         "cast5-cbc", &ossl_cast_cbc
!     },
!     {
!         NULL
!     }
  };

  /* PUBLIC functions */
--- 473,493 ----
  /*
   * Special handlers
   */
! struct ossl_cipher_lookup
  {
      const char *name;
      const struct ossl_cipher *ciph;
! };

! static const struct ossl_cipher_lookup ossl_cipher_types[] = {
!     {"bf-cbc", &ossl_bf_cbc},
!     {"bf-ecb", &ossl_bf_ecb},
!     {"bf-cfb", &ossl_bf_cfb},
!     {"des-ecb", &ossl_des_ecb},
!     {"des-cbc", &ossl_des_cbc},
!     {"cast5-ecb", &ossl_cast_ecb},
!     {"cast5-cbc", &ossl_cast_cbc},
!     {NULL}
  };

  /* PUBLIC functions */
*************** static const struct
*** 511,548 ****
  int
  px_find_cipher(const char *name, PX_Cipher ** res)
  {
!     unsigned    i;
!     PX_Cipher  *c = NULL,
!                *csrc;
      ossldata   *od;
-     const struct ossl_cipher *ossl_ciph = NULL;

      name = px_resolve_alias(ossl_aliases, name);
!     for (i = 0; ossl_cipher_types[i].name; i++)
!     {
!         if (!strcmp(ossl_cipher_types[i].name, name))
!         {
!             ossl_ciph = ossl_cipher_types[i].ciph;
              break;
!         }
!     }
!     if (ossl_ciph == NULL)
          return -1;

      od = px_alloc(sizeof(*od));
      memset(od, 0, sizeof(*od));
!     od->ciph = ossl_ciph;
!
!     csrc = NULL;

      c = px_alloc(sizeof(*c));
      c->block_size = gen_ossl_block_size;
      c->key_size = gen_ossl_key_size;
      c->iv_size = gen_ossl_iv_size;
      c->free = gen_ossl_free;
!     c->init = ossl_ciph->init;
!     c->encrypt = ossl_ciph->encrypt;
!     c->decrypt = ossl_ciph->decrypt;
      c->ptr = od;

      *res = c;
--- 495,523 ----
  int
  px_find_cipher(const char *name, PX_Cipher ** res)
  {
!     const struct ossl_cipher_lookup *i;
!     PX_Cipher  *c = NULL;
      ossldata   *od;

      name = px_resolve_alias(ossl_aliases, name);
!     for (i = ossl_cipher_types; i->name; i++)
!         if (!strcmp(i->name, name))
              break;
!     if (i->name == NULL)
          return -1;

      od = px_alloc(sizeof(*od));
      memset(od, 0, sizeof(*od));
!     od->ciph = i->ciph;

      c = px_alloc(sizeof(*c));
      c->block_size = gen_ossl_block_size;
      c->key_size = gen_ossl_key_size;
      c->iv_size = gen_ossl_iv_size;
      c->free = gen_ossl_free;
!     c->init = od->ciph->init;
!     c->encrypt = od->ciph->encrypt;
!     c->decrypt = od->ciph->decrypt;
      c->ptr = od;

      *res = c;
Index: pgsql/contrib/pgcrypto/px-crypt.c
===================================================================
*** pgsql.orig/contrib/pgcrypto/px-crypt.c
--- pgsql/contrib/pgcrypto/px-crypt.c
*************** run_crypt_bf(const char *psw, const char
*** 69,120 ****
      return res;
  }

! static struct
  {
      char       *id;
      unsigned    id_len;
      char       *(*crypt) (const char *psw, const char *salt,
                                        char *buf, unsigned len);
! }    px_crypt_list[] =

! {
!     {
!         "$2a$", 4, run_crypt_bf
!     },
!     {
!         "$2$", 3, NULL
!     },                            /* N/A */
!     {
!         "$1$", 3, run_crypt_md5
!     },
!     {
!         "_", 1, run_crypt_des
!     },
!     {
!         "", 0, run_crypt_des
!     },
!     {
!         NULL, 0, NULL
!     }
  };

  char *
  px_crypt(const char *psw, const char *salt, char *buf, unsigned len)
  {
!     int            i;

!     for (i = 0; px_crypt_list[i].id; i++)
      {
!         if (!px_crypt_list[i].id_len)
              break;
!         if (!strncmp(salt, px_crypt_list[i].id, px_crypt_list[i].id_len))
              break;
      }

!     if (px_crypt_list[i].crypt == NULL)
          return NULL;

!     return px_crypt_list[i].crypt(psw, salt, buf, len);
  }

  #else                            /* PX_SYSTEM_CRYPT */
--- 69,109 ----
      return res;
  }

! struct px_crypt_algo
  {
      char       *id;
      unsigned    id_len;
      char       *(*crypt) (const char *psw, const char *salt,
                                        char *buf, unsigned len);
! };

! static const struct px_crypt_algo
! px_crypt_list[] = {
!     {"$2a$", 4, run_crypt_bf},
!     {"$2$", 3, NULL},                            /* N/A */
!     {"$1$", 3, run_crypt_md5},
!     {"_", 1, run_crypt_des},
!     {"", 0, run_crypt_des},
!     {NULL, 0, NULL}
  };

  char *
  px_crypt(const char *psw, const char *salt, char *buf, unsigned len)
  {
!     const struct px_crypt_algo *c;

!     for (c = px_crypt_list; c->id; c++)
      {
!         if (!c->id_len)
              break;
!         if (!strncmp(salt, c->id, c->id_len))
              break;
      }

!     if (c->crypt == NULL)
          return NULL;

!     return c->crypt(psw, salt, buf, len);
  }

  #else                            /* PX_SYSTEM_CRYPT */
*************** static struct generator gen_list[] = {
*** 155,161 ****
      {"md5", _crypt_gensalt_md5_rn, 6, 0, 0, 0},
      {"xdes", _crypt_gensalt_extended_rn, 3, PX_XDES_ROUNDS, 1, 0xFFFFFF},
      {"bf", _crypt_gensalt_blowfish_rn, 16, PX_BF_ROUNDS, 4, 31},
!     {NULL, NULL, 0, 0, 0}
  };

  unsigned
--- 144,150 ----
      {"md5", _crypt_gensalt_md5_rn, 6, 0, 0, 0},
      {"xdes", _crypt_gensalt_extended_rn, 3, PX_XDES_ROUNDS, 1, 0xFFFFFF},
      {"bf", _crypt_gensalt_blowfish_rn, 16, PX_BF_ROUNDS, 4, 31},
!     {NULL, NULL, 0, 0, 0, 0}
  };

  unsigned
Index: pgsql/contrib/pgcrypto/internal.c
===================================================================
*** pgsql.orig/contrib/pgcrypto/internal.c
--- pgsql/contrib/pgcrypto/internal.c
***************
*** 57,78 ****
  static void init_md5(PX_MD * h);
  static void init_sha1(PX_MD * h);

! static struct int_digest
  {
      char       *name;
      void        (*init) (PX_MD * h);
! }    int_digest_list[] =

! {
!     {
!         "md5", init_md5
!     },
!     {
!         "sha1", init_sha1
!     },
!     {
!         NULL, NULL
!     }
  };

  /* MD5 */
--- 57,73 ----
  static void init_md5(PX_MD * h);
  static void init_sha1(PX_MD * h);

! struct int_digest
  {
      char       *name;
      void        (*init) (PX_MD * h);
! };

! static const struct int_digest
! int_digest_list[] = {
!     { "md5", init_md5 },
!     { "sha1", init_sha1 },
!     { NULL, NULL }
  };

  /* MD5 */
*************** bf_cbc_load(void)
*** 516,546 ****
      return bf_load(MODE_CBC);
  }

! static struct
  {
      char       *name;
      PX_Cipher  *(*load) (void);
! }    int_ciphers[] =

! {
!     {
!         "bf-cbc", bf_cbc_load
!     },
!     {
!         "bf-ecb", bf_ecb_load
!     },
!     {
!         "aes-128-cbc", rj_128_cbc
!     },
!     {
!         "aes-128-ecb", rj_128_ecb
!     },
!     {
!         NULL, NULL
!     }
  };

! static PX_Alias int_aliases[] = {
      {"bf", "bf-cbc"},
      {"blowfish", "bf-cbc"},
      {"aes", "aes-128-cbc"},
--- 511,532 ----
      return bf_load(MODE_CBC);
  }

! struct int_cipher
  {
      char       *name;
      PX_Cipher  *(*load) (void);
! };

! static const struct int_cipher
! int_ciphers[] = {
!     { "bf-cbc", bf_cbc_load },
!     { "bf-ecb", bf_ecb_load },
!     { "aes-128-cbc", rj_128_cbc },
!     { "aes-128-ecb", rj_128_ecb },
!     { NULL, NULL }
  };

! static const PX_Alias int_aliases[] = {
      {"bf", "bf-cbc"},
      {"blowfish", "bf-cbc"},
      {"aes", "aes-128-cbc"},
*************** static PX_Alias int_aliases[] = {
*** 557,563 ****
  int
  px_find_digest(const char *name, PX_MD ** res)
  {
!     struct int_digest *p;
      PX_MD       *h;

      for (p = int_digest_list; p->name; p++)
--- 543,549 ----
  int
  px_find_digest(const char *name, PX_MD ** res)
  {
!     const struct int_digest *p;
      PX_MD       *h;

      for (p = int_digest_list; p->name; p++)
Index: pgsql/contrib/pgcrypto/pgcrypto.c
===================================================================
*** pgsql.orig/contrib/pgcrypto/pgcrypto.c
--- pgsql/contrib/pgcrypto/pgcrypto.c
*************** typedef int (*PFN) (const char *name, vo
*** 46,52 ****
  static void *
              find_provider(text *name, PFN pf, char *desc, int silent);

! /* SQL function: hash(text, text) returns text */
  PG_FUNCTION_INFO_V1(pg_digest);

  Datum
--- 46,52 ----
  static void *
              find_provider(text *name, PFN pf, char *desc, int silent);

! /* SQL function: hash(bytea, text) returns bytea */
  PG_FUNCTION_INFO_V1(pg_digest);

  Datum
*************** pg_digest_exists(PG_FUNCTION_ARGS)
*** 111,117 ****
      PG_RETURN_BOOL(true);
  }

! /* SQL function: hmac(data:text, key:text, type:text) */
  PG_FUNCTION_INFO_V1(pg_hmac);

  Datum
--- 111,117 ----
      PG_RETURN_BOOL(true);
  }

! /* SQL function: hmac(data:bytea, key:bytea, type:text) returns bytea */
  PG_FUNCTION_INFO_V1(pg_hmac);

  Datum
*************** pg_crypt(PG_FUNCTION_ARGS)
*** 316,322 ****
      PG_RETURN_TEXT_P(res);
  }

! /* SQL function: pg_encrypt(text, text, text) returns text */
  PG_FUNCTION_INFO_V1(pg_encrypt);

  Datum
--- 316,322 ----
      PG_RETURN_TEXT_P(res);
  }

! /* SQL function: pg_encrypt(bytea, bytea, text) returns bytea */
  PG_FUNCTION_INFO_V1(pg_encrypt);

  Datum
*************** pg_encrypt(PG_FUNCTION_ARGS)
*** 367,373 ****
      PG_RETURN_BYTEA_P(res);
  }

! /* SQL function: pg_decrypt(text, text, text) returns text */
  PG_FUNCTION_INFO_V1(pg_decrypt);

  Datum
--- 367,373 ----
      PG_RETURN_BYTEA_P(res);
  }

! /* SQL function: pg_decrypt(bytea, bytea, text) returns bytea */
  PG_FUNCTION_INFO_V1(pg_decrypt);

  Datum
*************** pg_decrypt(PG_FUNCTION_ARGS)
*** 417,423 ****
      PG_RETURN_BYTEA_P(res);
  }

! /* SQL function: pg_encrypt(text, text, text) returns text */
  PG_FUNCTION_INFO_V1(pg_encrypt_iv);

  Datum
--- 417,423 ----
      PG_RETURN_BYTEA_P(res);
  }

! /* SQL function: pg_encrypt_iv(bytea, bytea, bytea, text) returns bytea */
  PG_FUNCTION_INFO_V1(pg_encrypt_iv);

  Datum
*************** pg_encrypt_iv(PG_FUNCTION_ARGS)
*** 473,479 ****
      PG_RETURN_BYTEA_P(res);
  }

! /* SQL function: pg_decrypt_iv(text, text, text) returns text */
  PG_FUNCTION_INFO_V1(pg_decrypt_iv);

  Datum
--- 473,479 ----
      PG_RETURN_BYTEA_P(res);
  }

! /* SQL function: pg_decrypt_iv(bytea, bytea, bytea, text) returns bytea */
  PG_FUNCTION_INFO_V1(pg_decrypt_iv);

  Datum
*************** pg_decrypt_iv(PG_FUNCTION_ARGS)
*** 529,535 ****
      PG_RETURN_BYTEA_P(res);
  }

! /* SQL function: pg_decrypt(text, text, text) returns text */
  PG_FUNCTION_INFO_V1(pg_cipher_exists);

  Datum
--- 529,535 ----
      PG_RETURN_BYTEA_P(res);
  }

! /* SQL function: pg_cipher_exists(text) returns bool */
  PG_FUNCTION_INFO_V1(pg_cipher_exists);

  Datum
*************** pg_cipher_exists(PG_FUNCTION_ARGS)
*** 550,556 ****
      PG_RETURN_BOOL((c != NULL) ? true : false);
  }

-
  static void *
  find_provider(text *name,
                PFN provider_lookup,
--- 550,555 ----
Index: pgsql/contrib/pgcrypto/crypt-blowfish.c
===================================================================
*** pgsql.orig/contrib/pgcrypto/crypt-blowfish.c
--- pgsql/contrib/pgcrypto/crypt-blowfish.c
***************
*** 35,46 ****
  #include "px.h"
  #include "px-crypt.h"

- #define __set_errno(v)
-
- #ifndef __set_errno
- #define __set_errno(val) errno = (val)
- #endif
-
  #ifdef __i386__
  #define BF_ASM                0    /* 1 */
  #define BF_SCALE            1
--- 35,40 ----
*************** _crypt_blowfish_rn(const char *key, cons
*** 600,609 ****
      int            i;

      if (size < 7 + 22 + 31 + 1)
-     {
-         __set_errno(ERANGE);
          return NULL;
-     }

      if (setting[0] != '$' ||
          setting[1] != '2' ||
--- 594,600 ----
*************** _crypt_blowfish_rn(const char *key, cons
*** 613,619 ****
          setting[5] < '0' || setting[5] > '9' ||
          setting[6] != '$')
      {
-         __set_errno(EINVAL);
          return NULL;
      }

--- 604,609 ----
*************** _crypt_blowfish_rn(const char *key, cons
*** 621,627 ****
      if (count < 16 || BF_decode(data.binary.salt, &setting[7], 16))
      {
          memset(data.binary.salt, 0, sizeof(data.binary.salt));
-         __set_errno(EINVAL);
          return NULL;
      }
      BF_swap(data.binary.salt, 4);
--- 611,616 ----
Index: pgsql/contrib/pgcrypto/crypt-gensalt.c
===================================================================
*** pgsql.orig/contrib/pgcrypto/crypt-gensalt.c
--- pgsql/contrib/pgcrypto/crypt-gensalt.c
***************
*** 15,25 ****
  #include "px.h"
  #include "px-crypt.h"

- #include <errno.h>
- #ifndef __set_errno
- #define __set_errno(val) (errno = (val))
- #endif
-
  typedef unsigned int BF_word;

  unsigned char _crypt_itoa64[64 + 1] =
--- 15,20 ----
*************** _crypt_gensalt_traditional_rn(unsigned l
*** 33,39 ****
      {
          if (output_size > 0)
              output[0] = '\0';
-         __set_errno((output_size < 2 + 1) ? ERANGE : EINVAL);
          return NULL;
      }

--- 28,33 ----
*************** _crypt_gensalt_extended_rn(unsigned long
*** 57,63 ****
      {
          if (output_size > 0)
              output[0] = '\0';
-         __set_errno((output_size < 1 + 4 + 4 + 1) ? ERANGE : EINVAL);
          return NULL;
      }

--- 51,56 ----
*************** _crypt_gensalt_md5_rn(unsigned long coun
*** 91,97 ****
      {
          if (output_size > 0)
              output[0] = '\0';
-         __set_errno((output_size < 3 + 4 + 1) ? ERANGE : EINVAL);
          return NULL;
      }

--- 84,89 ----
*************** _crypt_gensalt_blowfish_rn(unsigned long
*** 173,179 ****
      {
          if (output_size > 0)
              output[0] = '\0';
-         __set_errno((output_size < 7 + 22 + 1) ? ERANGE : EINVAL);
          return NULL;
      }

--- 165,170 ----
Index: pgsql/contrib/pgcrypto/px.h
===================================================================
*** pgsql.orig/contrib/pgcrypto/px.h
--- pgsql/contrib/pgcrypto/px.h
***************
*** 43,63 ****
  #endif


! #if 1

  #define px_alloc(s) palloc(s)
! #define px_realloc(p, s) prealloc(p, s)
  #define px_free(p)    pfree(p)

  #else

! void       *xalloc(size_t s);
! void       *xrealloc(void *p, size_t s);
! void        xfree(void *p);
!
! #define px_alloc(s) xalloc(s)
! #define px_realloc(p, s) xrealloc(p, s)
! #define px_free(p)    xfree(p)
  #endif

  /* max len of 'type' parms */
--- 43,60 ----
  #endif


! #ifndef PX_OWN_ALLOC

  #define px_alloc(s) palloc(s)
! #define px_realloc(p, s) repalloc(p, s)
  #define px_free(p)    pfree(p)

  #else

! void       *px_alloc(size_t s);
! void       *px_realloc(void *p, size_t s);
! void        px_free(void *p);
!
  #endif

  /* max len of 'type' parms */

--

[patch 1/6] remove support for mhash/mcrypt

From
Marko Kreen
Date:
Remove support for libmhash/libmcrypt.

libmcrypt seems to dead, maintainer address bounces,
and cast-128 fails on 2 of the 3 test vectors from RFC2144.

So I see no reason to keep around stuff I don't trust
anymore.

Support for several crypto libraries is probably only
confusing to users, although it was good for initial
developing - it helped to find hidden assumptions and
forced me to create regression tests for all functionality.

I'll try to get libgcrypt working, although I'll submit
it only if I find a really good reason for it.


Index: pgsql/contrib/pgcrypto/Makefile
===================================================================
*** pgsql.orig/contrib/pgcrypto/Makefile
--- pgsql/contrib/pgcrypto/Makefile
***************
*** 2,8 ****
  # $PostgreSQL: pgsql/contrib/pgcrypto/Makefile,v 1.12 2004/09/14 03:39:48 tgl Exp $
  #

! # either 'builtin', 'mhash', 'openssl'
  cryptolib = builtin

  # either 'builtin', 'system'
--- 2,8 ----
  # $PostgreSQL: pgsql/contrib/pgcrypto/Makefile,v 1.12 2004/09/14 03:39:48 tgl Exp $
  #

! # either 'builtin', 'openssl'
  cryptolib = builtin

  # either 'builtin', 'system'
*************** CRYPTO_LDFLAGS = -lcrypto
*** 34,45 ****
  SRCS = openssl.c
  endif

- ifeq ($(cryptolib), mhash)
- CRYPTO_CFLAGS = -I/usr/local/include
- CRYPTO_LDFLAGS = -L/usr/local/lib -lmcrypt -lmhash -lltdl
- SRCS = mhash.c
- endif
-
  ifeq ($(cryptsrc), builtin)
  SRCS += crypt-blowfish.c crypt-des.c crypt-md5.c
  else
--- 34,39 ----
Index: pgsql/contrib/pgcrypto/README.pgcrypto
===================================================================
*** pgsql.orig/contrib/pgcrypto/README.pgcrypto
--- pgsql/contrib/pgcrypto/README.pgcrypto
*************** OpenSSL (0.9.6):
*** 186,202 ****
      Url:    http://www.openssl.org/


- mhash (0.8.9) + mcrypt (2.4.16):
-     Hashes:    MD5, SHA1, CRC32, CRC32B, GOST, TIGER, RIPEMD160,
-         HAVAL(256,224,192,160,128)
-     Ciphers:    DES, DES3, CAST-128(CAST5), CAST-256, xTEA, 3-way,
-             SKIPJACK, Blowfish, Twofish, LOKI97, RC2, RC4, RC6,
-         Rijndael-128/192/256, MARS, PANAMA, WAKE, Serpent, IDEA, GOST,
-         SAFER, SAFER+, Enigma
-     License:    LGPL
-     Url:    http://mcrypt.sourceforge.org/
-     Url:    http://mhash.sourceforge.org/
-
  CREDITS
  =======

--- 186,191 ----
Index: pgsql/contrib/pgcrypto/mhash.c
===================================================================
*** pgsql.orig/contrib/pgcrypto/mhash.c
--- /dev/null
***************
*** 1,356 ****
- /*
-  * mhash.c
-  *        Wrapper for mhash and mcrypt libraries.
-  *
-  * 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.
-  *
-  * $PostgreSQL: pgsql/contrib/pgcrypto/mhash.c,v 1.10 2004/05/07 00:24:57 tgl Exp $
-  */
-
- #include <postgres.h>
-
- #include "px.h"
-
- #include <mhash.h>
- #include <mcrypt.h>
-
- #define MAX_KEY_LENGTH 512
- #define MAX_IV_LENGTH 128
-
- #define DEF_KEY_LEN 16
-
-
- /* DIGEST */
-
- static unsigned
- digest_result_size(PX_MD * h)
- {
-     MHASH        mh = (MHASH) h->p.ptr;
-     hashid        id = mhash_get_mhash_algo(mh);
-
-     return mhash_get_block_size(id);
- }
-
- static unsigned
- digest_block_size(PX_MD * h)
- {
-     MHASH        mh = (MHASH) h->p.ptr;
-     hashid        id = mhash_get_mhash_algo(mh);
-
-     return mhash_get_hash_pblock(id);
- }
-
- static void
- digest_reset(PX_MD * h)
- {
-     MHASH        mh = (MHASH) h->p.ptr;
-     hashid        id = mhash_get_mhash_algo(mh);
-     uint8       *res = mhash_end(mh);
-
-     mhash_free(res);
-     mh = mhash_init(id);
-     h->p.ptr = mh;
- }
-
- static void
- digest_update(PX_MD * h, const uint8 *data, unsigned dlen)
- {
-     MHASH        mh = (MHASH) h->p.ptr;
-
-     mhash(mh, data, dlen);
- }
-
- static void
- digest_finish(PX_MD * h, uint8 *dst)
- {
-     MHASH        mh = (MHASH) h->p.ptr;
-     unsigned    hlen = digest_result_size(h);
-     hashid        id = mhash_get_mhash_algo(mh);
-     uint8       *buf = mhash_end(mh);
-
-     memcpy(dst, buf, hlen);
-     mhash_free(buf);
-
-     mh = mhash_init(id);
-     h->p.ptr = mh;
- }
-
- static void
- digest_free(PX_MD * h)
- {
-     MHASH        mh = (MHASH) h->p.ptr;
-     uint8       *buf = mhash_end(mh);
-
-     mhash_free(buf);
-
-     px_free(h);
- }
-
- /* ENCRYPT / DECRYPT */
-
- static unsigned
- cipher_block_size(PX_Cipher * c)
- {
-     MCRYPT        ctx = (MCRYPT) c->ptr;
-
-     return mcrypt_enc_get_block_size(ctx);
- }
-
- static unsigned
- cipher_key_size(PX_Cipher * c)
- {
-     MCRYPT        ctx = (MCRYPT) c->ptr;
-
-     return mcrypt_enc_get_key_size(ctx);
- }
-
- static unsigned
- cipher_iv_size(PX_Cipher * c)
- {
-     MCRYPT        ctx = (MCRYPT) c->ptr;
-
-     return mcrypt_enc_mode_has_iv(ctx)
-         ? mcrypt_enc_get_iv_size(ctx) : 0;
- }
-
- static int
- cipher_init(PX_Cipher * c, const uint8 *key, unsigned klen, const uint8 *iv)
- {
-     int            err;
-     MCRYPT        ctx = (MCRYPT) c->ptr;
-
-     err = mcrypt_generic_init(ctx, (char *) key, klen, (char *) iv);
-     if (err < 0)
-         ereport(ERROR,
-                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
-                  errmsg("mcrypt_generic_init error"),
-                  errdetail("%s", mcrypt_strerror(err))));
-
-     c->pstat = 1;
-     return 0;
- }
-
- static int
- cipher_encrypt(PX_Cipher * c, const uint8 *data, unsigned dlen, uint8 *res)
- {
-     int            err;
-     MCRYPT        ctx = (MCRYPT) c->ptr;
-
-     memcpy(res, data, dlen);
-
-     err = mcrypt_generic(ctx, res, dlen);
-     if (err < 0)
-         ereport(ERROR,
-                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
-                  errmsg("mcrypt_generic error"),
-                  errdetail("%s", mcrypt_strerror(err))));
-     return 0;
- }
-
- static int
- cipher_decrypt(PX_Cipher * c, const uint8 *data, unsigned dlen, uint8 *res)
- {
-     int            err;
-     MCRYPT        ctx = (MCRYPT) c->ptr;
-
-     memcpy(res, data, dlen);
-
-     err = mdecrypt_generic(ctx, res, dlen);
-     if (err < 0)
-         ereport(ERROR,
-                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
-                  errmsg("mdecrypt_generic error"),
-                  errdetail("%s", mcrypt_strerror(err))));
-     return 0;
- }
-
-
- static void
- cipher_free(PX_Cipher * c)
- {
-     MCRYPT        ctx = (MCRYPT) c->ptr;
-
-     if (c->pstat)
-         mcrypt_generic_end(ctx);
-     else
-         mcrypt_module_close(ctx);
-
-     px_free(c);
- }
-
- /* Helper functions */
-
- static int
- find_hashid(const char *name)
- {
-     int            res = -1;
-     size_t        hnum,
-                 b,
-                 i;
-     char       *mname;
-
-     hnum = mhash_count();
-     for (i = 0; i <= hnum; i++)
-     {
-         mname = mhash_get_hash_name(i);
-         if (mname == NULL)
-             continue;
-         b = pg_strcasecmp(name, mname);
-         free(mname);
-         if (b == 0)
-         {
-             res = i;
-             break;
-         }
-     }
-
-     return res;
- }
-
- static char *modes[] = {
-     "ecb", "cbc", "cfb", "ofb", "nofb", "stream",
-     "ofb64", "cfb64", NULL
- };
-
- static PX_Alias aliases[] = {
-     {"bf", "blowfish"},
-     {"3des", "tripledes"},
-     {"des3", "tripledes"},
-     {"aes", "rijndael-128"},
-     {"rijndael", "rijndael-128"},
-     {"aes-128", "rijndael-128"},
-     {"aes-192", "rijndael-192"},
-     {"aes-256", "rijndael-256"},
-     {NULL, NULL}
- };
-
- static PX_Alias mode_aliases[] = {
- #if 0                            /* N/A */
-     {"cfb", "ncfb"},
-     {"ofb", "nofb"},
-     {"cfb64", "ncfb"},
- #endif
-     /* { "ofb64", "nofb" }, not sure it works */
-     {"cfb8", "cfb"},
-     {"ofb8", "ofb"},
-     {NULL, NULL}
- };
-
- static int
- is_mode(char *s)
- {
-     char      **p;
-
-     if (*s >= '0' && *s <= '9')
-         return 0;
-
-     for (p = modes; *p; p++)
-         if (!strcmp(s, *p))
-             return 1;
-
-     return 0;
- }
-
- /* PUBLIC FUNCTIONS */
-
- int
- px_find_digest(const char *name, PX_MD ** res)
- {
-     PX_MD       *h;
-     MHASH        mh;
-     int            i;
-
-     i = find_hashid(name);
-     if (i < 0)
-         return -1;
-
-     mh = mhash_init(i);
-     h = px_alloc(sizeof(*h));
-     h->p.ptr = (void *) mh;
-
-     h->result_size = digest_result_size;
-     h->block_size = digest_block_size;
-     h->reset = digest_reset;
-     h->update = digest_update;
-     h->finish = digest_finish;
-     h->free = digest_free;
-
-     *res = h;
-     return 0;
- }
-
-
- int
- px_find_cipher(const char *name, PX_Cipher ** res)
- {
-     char        nbuf[PX_MAX_NAMELEN + 1];
-     const char *mode = NULL;
-     char       *p;
-     MCRYPT        ctx;
-
-     PX_Cipher  *c;
-
-     StrNCpy(nbuf, name, sizeof(nbuf));
-
-     if ((p = strrchr(nbuf, '-')) != NULL)
-     {
-         if (is_mode(p + 1))
-         {
-             mode = p + 1;
-             *p = 0;
-         }
-     }
-
-     name = px_resolve_alias(aliases, nbuf);
-
-     if (!mode)
-     {
-         mode = "cbc";
-
-         /*
-          * if (mcrypt_module_is_block_algorithm(name, NULL)) mode = "cbc";
-          * else mode = "stream";
-          */
-     }
-     mode = px_resolve_alias(mode_aliases, mode);
-
-     ctx = mcrypt_module_open((char *) name, NULL, (char *) mode, NULL);
-     if (ctx == (void *) MCRYPT_FAILED)
-         return -1;
-
-     c = palloc(sizeof *c);
-     c->iv_size = cipher_iv_size;
-     c->key_size = cipher_key_size;
-     c->block_size = cipher_block_size;
-     c->init = cipher_init;
-     c->encrypt = cipher_encrypt;
-     c->decrypt = cipher_decrypt;
-     c->free = cipher_free;
-     c->ptr = ctx;
-     c->pstat = 0;
-
-     *res = c;
-     return 0;
- }
--- 0 ----

--

[patch 6/6] regression test updates

From
Marko Kreen
Date:
* test error handling
* add tests for des, 3des, cast5
* add some tests to blowfish, rijndael
* Makefile: ability to specify different tests for different crypto
  libraries, so we can skip des, 3des and cast5 for builtin.


Index: pgsql/contrib/pgcrypto/sql/blowfish.sql
===================================================================
*** pgsql.orig/contrib/pgcrypto/sql/blowfish.sql
--- pgsql/contrib/pgcrypto/sql/blowfish.sql
*************** decode('6b77b4d63006dee605b156e274039793
*** 64,66 ****
--- 64,87 ----
  decode('37363534333231204e6f77206973207468652074696d6520666f722000', 'hex'),
  'bf-cbc'), 'hex');

+ -- blowfish-448
+ SELECT encode(encrypt(
+ decode('fedcba9876543210', 'hex'),
+
decode('f0e1d2c3b4a5968778695a4b3c2d1e0f001122334455667704689104c2fd3b2f584023641aba61761f1f1f1f0e0e0e0effffffffffffffff',
'hex'),
+ 'bf-ecb/pad:none'), 'hex');
+ -- result: c04504012e4e1f53
+
+ -- empty data
+ select encode(    encrypt('', 'foo', 'bf'), 'hex');
+ -- 10 bytes key
+ select encode(    encrypt('foo', '0123456789', 'bf'), 'hex');
+ -- 22 bytes key
+ select encode(    encrypt('foo', '0123456789012345678901', 'bf'), 'hex');
+
+ -- decrypt
+ select decrypt(encrypt('foo', '0123456', 'bf'), '0123456', 'bf');
+
+ -- iv
+ select encode(encrypt_iv('foo', '0123456', 'abcd', 'bf'), 'hex');
+ select decrypt_iv(decode('95c7e89322525d59', 'hex'), '0123456', 'abcd', 'bf');
+
Index: pgsql/contrib/pgcrypto/sql/rijndael.sql
===================================================================
*** pgsql.orig/contrib/pgcrypto/sql/rijndael.sql
--- pgsql/contrib/pgcrypto/sql/rijndael.sql
*************** decode('0011223344', 'hex'),
*** 41,43 ****
--- 41,58 ----
  decode('000102030405060708090a0b0c0d0e0f101112131415161718191a1b', 'hex'),
  'aes-cbc'), 'hex');

+ -- empty data
+ select encode(    encrypt('', 'foo', 'aes'), 'hex');
+ -- 10 bytes key
+ select encode(    encrypt('foo', '0123456789', 'aes'), 'hex');
+ -- 22 bytes key
+ select encode(    encrypt('foo', '0123456789012345678901', 'aes'), 'hex');
+
+ -- decrypt
+ select decrypt(encrypt('foo', '0123456', 'aes'), '0123456', 'aes');
+
+ -- iv
+ select encode(encrypt_iv('foo', '0123456', 'abcd', 'aes'), 'hex');
+ select decrypt_iv(decode('2c24cb7da91d6d5699801268b0f5adad', 'hex'),
+         '0123456', 'abcd', 'aes');
+
Index: pgsql/contrib/pgcrypto/Makefile
===================================================================
*** pgsql.orig/contrib/pgcrypto/Makefile
--- pgsql/contrib/pgcrypto/Makefile
*************** ifeq ($(cryptolib), builtin)
*** 26,37 ****
--- 26,39 ----
  CRYPTO_CFLAGS =
  CRYPTO_LDFLAGS =
  SRCS = md5.c sha1.c internal.c blf.c rijndael.c
+ EXTRA_TESTS =
  endif

  ifeq ($(cryptolib), openssl)
  CRYPTO_CFLAGS = -I/usr/include/openssl
  CRYPTO_LDFLAGS = -lcrypto
  SRCS = openssl.c
+ EXTRA_TESTS = des 3des cast5
  endif

  ifeq ($(cryptsrc), builtin)
*************** PG_CPPFLAGS    = $(CRYPTO_CFLAGS) -I$(srcdi
*** 63,68 ****
--- 65,71 ----
  SHLIB_LINK     = $(CRYPTO_LDFLAGS)

  REGRESS = init md5 sha1 hmac-md5 hmac-sha1 blowfish rijndael \
+         $(EXTRA_TESTS) \
          crypt-des crypt-md5 crypt-blowfish crypt-xdes


Index: pgsql/contrib/pgcrypto/sql/des.sql
===================================================================
*** /dev/null
--- pgsql/contrib/pgcrypto/sql/des.sql
***************
*** 0 ****
--- 1,24 ----
+ --
+ -- DES cipher
+ --
+
+ -- no official test vectors atm
+
+ -- from blowfish.sql
+ SELECT encode(encrypt(
+ decode('0123456789abcdef', 'hex'),
+ decode('fedcba9876543210', 'hex'),
+ 'des-ecb/pad:none'), 'hex');
+
+ -- empty data
+ select encode(    encrypt('', 'foo', 'des'), 'hex');
+ -- 8 bytes key
+ select encode(    encrypt('foo', '01234589', 'des'), 'hex');
+
+ -- decrypt
+ select decrypt(encrypt('foo', '0123456', 'des'), '0123456', 'des');
+
+ -- iv
+ select encode(encrypt_iv('foo', '0123456', 'abcd', 'des'), 'hex');
+ select decrypt_iv(decode('50735067b073bb93', 'hex'), '0123456', 'abcd', 'des');
+
Index: pgsql/contrib/pgcrypto/sql/cast5.sql
===================================================================
*** /dev/null
--- pgsql/contrib/pgcrypto/sql/cast5.sql
***************
*** 0 ****
--- 1,42 ----
+ --
+ -- Cast5 cipher
+ --
+
+ -- test vectors from RFC2144
+
+ -- 128 bit key
+ SELECT encode(encrypt(
+ decode('01 23 45 67 89 AB CD EF', 'hex'),
+ decode('01 23 45 67 12 34 56 78 23 45 67 89 34 56 78 9A', 'hex'),
+ 'cast5-ecb/pad:none'), 'hex');
+ -- result: 23 8B 4F E5 84 7E 44 B2
+
+ -- 80 bit key
+ SELECT encode(encrypt(
+ decode('01 23 45 67 89 AB CD EF', 'hex'),
+ decode('01 23 45 67 12 34 56 78 23 45', 'hex'),
+ 'cast5-ecb/pad:none'), 'hex');
+ -- result: EB 6A 71 1A 2C 02 27 1B
+
+ -- 40 bit key
+ SELECT encode(encrypt(
+ decode('01 23 45 67 89 AB CD EF', 'hex'),
+ decode('01 23 45 67 12', 'hex'),
+ 'cast5-ecb/pad:none'), 'hex');
+ -- result: 7A C8 16 D1 6E 9B 30 2E
+
+ -- cbc
+
+ -- empty data
+ select encode(    encrypt('', 'foo', 'cast5'), 'hex');
+ -- 10 bytes key
+ select encode(    encrypt('foo', '0123456789', 'cast5'), 'hex');
+
+ -- decrypt
+ select decrypt(encrypt('foo', '0123456', 'cast5'), '0123456', 'cast5');
+
+ -- iv
+ select encode(encrypt_iv('foo', '0123456', 'abcd', 'cast5'), 'hex');
+ select decrypt_iv(decode('384a970695ce016a', 'hex'),
+                 '0123456', 'abcd', 'cast5');
+
Index: pgsql/contrib/pgcrypto/expected/des.out
===================================================================
*** /dev/null
--- pgsql/contrib/pgcrypto/expected/des.out
***************
*** 0 ****
--- 1,48 ----
+ --
+ -- DES cipher
+ --
+ -- no official test vectors atm
+ -- from blowfish.sql
+ SELECT encode(encrypt(
+ decode('0123456789abcdef', 'hex'),
+ decode('fedcba9876543210', 'hex'),
+ 'des-ecb/pad:none'), 'hex');
+       encode
+ ------------------
+  ed39d950fa74bcc4
+ (1 row)
+
+ -- empty data
+ select encode(    encrypt('', 'foo', 'des'), 'hex');
+       encode
+ ------------------
+  752111e37a2d7ac3
+ (1 row)
+
+ -- 8 bytes key
+ select encode(    encrypt('foo', '01234589', 'des'), 'hex');
+       encode
+ ------------------
+  dec0f9c602b647a8
+ (1 row)
+
+ -- decrypt
+ select decrypt(encrypt('foo', '0123456', 'des'), '0123456', 'des');
+  decrypt
+ ---------
+  foo
+ (1 row)
+
+ -- iv
+ select encode(encrypt_iv('foo', '0123456', 'abcd', 'des'), 'hex');
+       encode
+ ------------------
+  50735067b073bb93
+ (1 row)
+
+ select decrypt_iv(decode('50735067b073bb93', 'hex'), '0123456', 'abcd', 'des');
+  decrypt_iv
+ ------------
+  foo
+ (1 row)
+
Index: pgsql/contrib/pgcrypto/expected/3des.out
===================================================================
*** /dev/null
--- pgsql/contrib/pgcrypto/expected/3des.out
***************
*** 0 ****
--- 1,56 ----
+ --
+ -- 3DES cipher
+ --
+ -- test vector from somewhere
+ SELECT encode(encrypt(
+ decode('80 00 00 00 00 00 00 00', 'hex'),
+ decode('01 01 01 01 01 01 01 01
+     01 01 01 01 01 01 01 01
+     01 01 01 01 01 01 01 01', 'hex'),
+ '3des-ecb/pad:none'), 'hex');
+       encode
+ ------------------
+  95f8a5e5dd31d900
+ (1 row)
+
+ -- val 95 F8 A5 E5 DD 31 D9 00
+ select encode(    encrypt('', 'foo', '3des'), 'hex');
+       encode
+ ------------------
+  9b641a6936249eb4
+ (1 row)
+
+ -- 10 bytes key
+ select encode(    encrypt('foo', '0123456789', '3des'), 'hex');
+       encode
+ ------------------
+  6f02b7076a366504
+ (1 row)
+
+ -- 22 bytes key
+ select encode(    encrypt('foo', '0123456789012345678901', '3des'), 'hex');
+       encode
+ ------------------
+  a44360e699269817
+ (1 row)
+
+ -- decrypt
+ select decrypt(encrypt('foo', '0123456', '3des'), '0123456', '3des');
+  decrypt
+ ---------
+  foo
+ (1 row)
+
+ -- iv
+ select encode(encrypt_iv('foo', '0123456', 'abcd', '3des'), 'hex');
+       encode
+ ------------------
+  df27c264fb24ed7a
+ (1 row)
+
+ select decrypt_iv(decode('df27c264fb24ed7a', 'hex'), '0123456', 'abcd', '3des');
+  decrypt_iv
+ ------------
+  foo
+ (1 row)
+
Index: pgsql/contrib/pgcrypto/expected/cast5.out
===================================================================
*** /dev/null
--- pgsql/contrib/pgcrypto/expected/cast5.out
***************
*** 0 ****
--- 1,73 ----
+ --
+ -- Cast5 cipher
+ --
+ -- test vectors from RFC2144
+ -- 128 bit key
+ SELECT encode(encrypt(
+ decode('01 23 45 67 89 AB CD EF', 'hex'),
+ decode('01 23 45 67 12 34 56 78 23 45 67 89 34 56 78 9A', 'hex'),
+ 'cast5-ecb/pad:none'), 'hex');
+       encode
+ ------------------
+  238b4fe5847e44b2
+ (1 row)
+
+ -- result: 23 8B 4F E5 84 7E 44 B2
+ -- 80 bit key
+ SELECT encode(encrypt(
+ decode('01 23 45 67 89 AB CD EF', 'hex'),
+ decode('01 23 45 67 12 34 56 78 23 45', 'hex'),
+ 'cast5-ecb/pad:none'), 'hex');
+       encode
+ ------------------
+  eb6a711a2c02271b
+ (1 row)
+
+ -- result: EB 6A 71 1A 2C 02 27 1B
+ -- 40 bit key
+ SELECT encode(encrypt(
+ decode('01 23 45 67 89 AB CD EF', 'hex'),
+ decode('01 23 45 67 12', 'hex'),
+ 'cast5-ecb/pad:none'), 'hex');
+       encode
+ ------------------
+  7ac816d16e9b302e
+ (1 row)
+
+ -- result: 7A C8 16 D1 6E 9B 30 2E
+ -- cbc
+ -- empty data
+ select encode(    encrypt('', 'foo', 'cast5'), 'hex');
+       encode
+ ------------------
+  a48bd1aabde4de10
+ (1 row)
+
+ -- 10 bytes key
+ select encode(    encrypt('foo', '0123456789', 'cast5'), 'hex');
+       encode
+ ------------------
+  b07f19255e60cb6d
+ (1 row)
+
+ -- decrypt
+ select decrypt(encrypt('foo', '0123456', 'cast5'), '0123456', 'cast5');
+  decrypt
+ ---------
+  foo
+ (1 row)
+
+ -- iv
+ select encode(encrypt_iv('foo', '0123456', 'abcd', 'cast5'), 'hex');
+       encode
+ ------------------
+  384a970695ce016a
+ (1 row)
+
+ select decrypt_iv(decode('384a970695ce016a', 'hex'),
+                 '0123456', 'abcd', 'cast5');
+  decrypt_iv
+ ------------
+  foo
+ (1 row)
+
Index: pgsql/contrib/pgcrypto/sql/3des.sql
===================================================================
*** /dev/null
--- pgsql/contrib/pgcrypto/sql/3des.sql
***************
*** 0 ****
--- 1,26 ----
+ --
+ -- 3DES cipher
+ --
+
+ -- test vector from somewhere
+ SELECT encode(encrypt(
+ decode('80 00 00 00 00 00 00 00', 'hex'),
+ decode('01 01 01 01 01 01 01 01
+     01 01 01 01 01 01 01 01
+     01 01 01 01 01 01 01 01', 'hex'),
+ '3des-ecb/pad:none'), 'hex');
+ -- val 95 F8 A5 E5 DD 31 D9 00
+
+ select encode(    encrypt('', 'foo', '3des'), 'hex');
+ -- 10 bytes key
+ select encode(    encrypt('foo', '0123456789', '3des'), 'hex');
+ -- 22 bytes key
+ select encode(    encrypt('foo', '0123456789012345678901', '3des'), 'hex');
+
+ -- decrypt
+ select decrypt(encrypt('foo', '0123456', '3des'), '0123456', '3des');
+
+ -- iv
+ select encode(encrypt_iv('foo', '0123456', 'abcd', '3des'), 'hex');
+ select decrypt_iv(decode('df27c264fb24ed7a', 'hex'), '0123456', 'abcd', '3des');
+
Index: pgsql/contrib/pgcrypto/expected/blowfish.out
===================================================================
*** pgsql.orig/contrib/pgcrypto/expected/blowfish.out
--- pgsql/contrib/pgcrypto/expected/blowfish.out
*************** decode('37363534333231204e6f772069732074
*** 106,108 ****
--- 106,160 ----
   3ea6357a0ee7fad6d0c4b63464f2aafa40c2e91b4b7e1bba8114932fd92b5c8f111e7e50e7b2e541
  (1 row)

+ -- blowfish-448
+ SELECT encode(encrypt(
+ decode('fedcba9876543210', 'hex'),
+
decode('f0e1d2c3b4a5968778695a4b3c2d1e0f001122334455667704689104c2fd3b2f584023641aba61761f1f1f1f0e0e0e0effffffffffffffff',
'hex'),
+ 'bf-ecb/pad:none'), 'hex');
+       encode
+ ------------------
+  c04504012e4e1f53
+ (1 row)
+
+ -- result: c04504012e4e1f53
+ -- empty data
+ select encode(    encrypt('', 'foo', 'bf'), 'hex');
+       encode
+ ------------------
+  1871949bb2311c8e
+ (1 row)
+
+ -- 10 bytes key
+ select encode(    encrypt('foo', '0123456789', 'bf'), 'hex');
+       encode
+ ------------------
+  42f58af3b2c03f46
+ (1 row)
+
+ -- 22 bytes key
+ select encode(    encrypt('foo', '0123456789012345678901', 'bf'), 'hex');
+       encode
+ ------------------
+  86ab6f0bc72b5f22
+ (1 row)
+
+ -- decrypt
+ select decrypt(encrypt('foo', '0123456', 'bf'), '0123456', 'bf');
+  decrypt
+ ---------
+  foo
+ (1 row)
+
+ -- iv
+ select encode(encrypt_iv('foo', '0123456', 'abcd', 'bf'), 'hex');
+       encode
+ ------------------
+  95c7e89322525d59
+ (1 row)
+
+ select decrypt_iv(decode('95c7e89322525d59', 'hex'), '0123456', 'abcd', 'bf');
+  decrypt_iv
+ ------------
+  foo
+ (1 row)
+
Index: pgsql/contrib/pgcrypto/expected/rijndael.out
===================================================================
*** pgsql.orig/contrib/pgcrypto/expected/rijndael.out
--- pgsql/contrib/pgcrypto/expected/rijndael.out
*************** decode('000102030405060708090a0b0c0d0e0f
*** 67,69 ****
--- 67,111 ----
   4facb6a041d53e0a5a73289170901fe7
  (1 row)

+ -- empty data
+ select encode(    encrypt('', 'foo', 'aes'), 'hex');
+               encode
+ ----------------------------------
+  b48cc3338a2eb293b6007ef72c360d48
+ (1 row)
+
+ -- 10 bytes key
+ select encode(    encrypt('foo', '0123456789', 'aes'), 'hex');
+               encode
+ ----------------------------------
+  f397f03d2819b7172b68d0706fda4693
+ (1 row)
+
+ -- 22 bytes key
+ select encode(    encrypt('foo', '0123456789012345678901', 'aes'), 'hex');
+               encode
+ ----------------------------------
+  5c9db77af02b4678117bcd8a71ae7f53
+ (1 row)
+
+ -- decrypt
+ select decrypt(encrypt('foo', '0123456', 'aes'), '0123456', 'aes');
+  decrypt
+ ---------
+  foo
+ (1 row)
+
+ -- iv
+ select encode(encrypt_iv('foo', '0123456', 'abcd', 'aes'), 'hex');
+               encode
+ ----------------------------------
+  2c24cb7da91d6d5699801268b0f5adad
+ (1 row)
+
+ select decrypt_iv(decode('2c24cb7da91d6d5699801268b0f5adad', 'hex'),
+         '0123456', 'abcd', 'aes');
+  decrypt_iv
+ ------------
+  foo
+ (1 row)
+
Index: pgsql/contrib/pgcrypto/expected/init.out
===================================================================
*** pgsql.orig/contrib/pgcrypto/expected/init.out
--- pgsql/contrib/pgcrypto/expected/init.out
*************** SELECT decode('666f6f', 'hex');
*** 15,17 ****
--- 15,26 ----
   foo
  (1 row)

+ -- check error handling
+ select gen_salt('foo');
+ ERROR:  gen_salt: Unknown salt algorithm
+ select digest('foo', 'foo');
+ ERROR:  Cannot use "foo": No such hash algorithm
+ select hmac('foo', 'foo', 'foo');
+ ERROR:  Cannot use "foo": No such hash algorithm
+ select encrypt('foo', 'foo', 'foo');
+ ERROR:  Cannot use "foo": No such cipher algorithm
Index: pgsql/contrib/pgcrypto/sql/init.sql
===================================================================
*** pgsql.orig/contrib/pgcrypto/sql/init.sql
--- pgsql/contrib/pgcrypto/sql/init.sql
***************
*** 10,12 ****
--- 10,18 ----
  SELECT encode('foo', 'hex');
  SELECT decode('666f6f', 'hex');

+ -- check error handling
+ select gen_salt('foo');
+ select digest('foo', 'foo');
+ select hmac('foo', 'foo', 'foo');
+ select encrypt('foo', 'foo', 'foo');
+

--

[patch 4/6] openssl.c: 3DES and AES support

From
Marko Kreen
Date:
* openssl.c: Add 3des and AES support
* README.pgcrypto: list only supported ciphers for openssl

OpenSSL has pre-processor symbol OPENSSL_NO_AES, which
isn't that helpful for detecting if it _does_ exist.
Thus the hack with AES_ENCRYPT.


Index: pgsql/contrib/pgcrypto/openssl.c
===================================================================
*** pgsql.orig/contrib/pgcrypto/openssl.c
--- pgsql/contrib/pgcrypto/openssl.c
***************
*** 36,41 ****
--- 36,49 ----
  #include <openssl/evp.h>

  /*
+  * Is OpenSSL compiled with AES?
+  */
+ #undef GOT_AES
+ #ifdef AES_ENCRYPT
+ #define GOT_AES
+ #endif
+
+ /*
   * Hashes
   */
  static unsigned
*************** typedef struct
*** 165,171 ****
--- 173,186 ----
          {
              des_key_schedule key_schedule;
          }            des;
+         struct
+         {
+             des_key_schedule k1, k2, k3;
+         }            des3;
          CAST_KEY    cast_key;
+ #ifdef GOT_AES
+         AES_KEY        aes_key;
+ #endif
      }            u;
      uint8        key[EVP_MAX_KEY_LENGTH];
      uint8        iv[EVP_MAX_IV_LENGTH];
*************** ossl_des_cbc_decrypt(PX_Cipher * c, cons
*** 362,367 ****
--- 377,467 ----
      return 0;
  }

+ /* DES3 */
+
+ static int
+ ossl_des3_init(PX_Cipher * c, const uint8 *key, unsigned klen, const uint8 *iv)
+ {
+     ossldata   *od = c->ptr;
+     des_cblock    xkey1,
+                 xkey2,
+                 xkey3;
+
+     memset(&xkey1, 0, sizeof(xkey1));
+     memset(&xkey2, 0, sizeof(xkey2));
+     memset(&xkey2, 0, sizeof(xkey2));
+     memcpy(&xkey1, key, klen > 8 ? 8 : klen);
+     if (klen > 8)
+         memcpy(&xkey2, key + 8, (klen - 8) > 8 ? 8 : (klen - 8));
+     if (klen > 16)
+         memcpy(&xkey3, key + 16, (klen - 16) > 8 ? 8 : (klen - 16));
+
+     DES_set_key(&xkey1, &od->u.des3.k1);
+     DES_set_key(&xkey2, &od->u.des3.k2);
+     DES_set_key(&xkey3, &od->u.des3.k3);
+     memset(&xkey1, 0, sizeof(xkey1));
+     memset(&xkey2, 0, sizeof(xkey2));
+     memset(&xkey3, 0, sizeof(xkey3));
+
+     if (iv)
+         memcpy(od->iv, iv, 8);
+     else
+         memset(od->iv, 0, 8);
+     return 0;
+ }
+
+ static int
+ ossl_des3_ecb_encrypt(PX_Cipher * c, const uint8 *data, unsigned dlen,
+                       uint8 *res)
+ {
+     unsigned    bs = gen_ossl_block_size(c);
+     unsigned    i;
+     ossldata   *od = c->ptr;
+
+     for (i = 0; i < dlen / bs; i++)
+         DES_ecb3_encrypt(data + i * bs, res + i * bs,
+                          &od->u.des3.k1, &od->u.des3.k2, &od->u.des3.k3, 1);
+     return 0;
+ }
+
+ static int
+ ossl_des3_ecb_decrypt(PX_Cipher * c, const uint8 *data, unsigned dlen,
+                       uint8 *res)
+ {
+     unsigned    bs = gen_ossl_block_size(c);
+     unsigned    i;
+     ossldata   *od = c->ptr;
+
+     for (i = 0; i < dlen / bs; i++)
+         DES_ecb3_encrypt(data + i * bs, res + i * bs,
+                          &od->u.des3.k1, &od->u.des3.k2, &od->u.des3.k3, 0);
+     return 0;
+ }
+
+ static int
+ ossl_des3_cbc_encrypt(PX_Cipher * c, const uint8 *data, unsigned dlen,
+                       uint8 *res)
+ {
+     ossldata   *od = c->ptr;
+
+     DES_ede3_cbc_encrypt(data, res, dlen,
+                          &od->u.des3.k1, &od->u.des3.k2, &od->u.des3.k3,
+                          (des_cblock *) od->iv, 1);
+     return 0;
+ }
+
+ static int
+ ossl_des3_cbc_decrypt(PX_Cipher * c, const uint8 *data, unsigned dlen,
+                       uint8 *res)
+ {
+     ossldata   *od = c->ptr;
+
+     DES_ede3_cbc_encrypt(data, res, dlen,
+                          &od->u.des3.k1, &od->u.des3.k2, &od->u.des3.k3,
+                          (des_cblock *) od->iv, 0);
+     return 0;
+ }
+
  /* CAST5 */

  static int
*************** ossl_cast_cbc_decrypt(PX_Cipher * c, con
*** 420,425 ****
--- 520,622 ----
      return 0;
  }

+ /* AES */
+
+ #ifdef GOT_AES
+
+ static int
+ ossl_aes_init(PX_Cipher * c, const uint8 *key, unsigned klen, const uint8 *iv)
+ {
+     ossldata   *od = c->ptr;
+     unsigned    bs = gen_ossl_block_size(c);
+
+     if (klen <= 128/8)
+         od->klen = 128/8;
+     else if (klen <= 192/8)
+         od->klen = 192/8;
+     else if (klen <= 256/8)
+         od->klen = 256/8;
+     else
+         return PXE_KEY_TOO_BIG;
+
+     memcpy(od->key, key, klen);
+
+     if (iv)
+         memcpy(od->iv, iv, bs);
+     else
+         memset(od->iv, 0, bs);
+     return 0;
+ }
+
+ static void
+ ossl_aes_key_init(ossldata * od, int type)
+ {
+     if (type == AES_ENCRYPT)
+         AES_set_encrypt_key(od->key, od->klen * 8, &od->u.aes_key);
+     else
+         AES_set_decrypt_key(od->key, od->klen * 8, &od->u.aes_key);
+     od->init = 1;
+ }
+
+ static int
+ ossl_aes_ecb_encrypt(PX_Cipher * c, const uint8 *data, unsigned dlen,
+                      uint8 *res)
+ {
+     unsigned    bs = gen_ossl_block_size(c);
+     ossldata   *od = c->ptr;
+     const uint8 *end = data + dlen - bs;
+
+     if (!od->init)
+         ossl_aes_key_init(od, AES_ENCRYPT);
+
+     for (; data <= end; data += bs, res += bs)
+         AES_ecb_encrypt(data, res, &od->u.aes_key, AES_ENCRYPT);
+     return 0;
+ }
+
+ static int
+ ossl_aes_ecb_decrypt(PX_Cipher * c, const uint8 *data, unsigned dlen,
+                      uint8 *res)
+ {
+     unsigned    bs = gen_ossl_block_size(c);
+     ossldata   *od = c->ptr;
+     const uint8 *end = data + dlen - bs;
+
+     if (!od->init)
+         ossl_aes_key_init(od, AES_DECRYPT);
+
+     for (; data <= end; data += bs, res += bs)
+         AES_ecb_encrypt(data, res, &od->u.aes_key, AES_DECRYPT);
+     return 0;
+ }
+
+ static int
+ ossl_aes_cbc_encrypt(PX_Cipher * c, const uint8 *data, unsigned dlen,
+                      uint8 *res)
+ {
+     ossldata   *od = c->ptr;
+
+     if (!od->init)
+         ossl_aes_key_init(od, AES_ENCRYPT);
+
+     AES_cbc_encrypt(data, res, dlen, &od->u.aes_key, od->iv, AES_ENCRYPT);
+     return 0;
+ }
+
+ static int
+ ossl_aes_cbc_decrypt(PX_Cipher * c, const uint8 *data, unsigned dlen,
+                      uint8 *res)
+ {
+     ossldata   *od = c->ptr;
+
+     if (!od->init)
+         ossl_aes_key_init(od, AES_DECRYPT);
+
+     AES_cbc_encrypt(data, res, dlen, &od->u.aes_key, od->iv, AES_DECRYPT);
+     return 0;
+ }
+ #endif
+
  /*
   * aliases
   */
*************** static PX_Alias ossl_aliases[] = {
*** 431,437 ****
--- 628,641 ----
      {"blowfish-ecb", "bf-ecb"},
      {"blowfish-cfb", "bf-cfb"},
      {"des", "des-cbc"},
+     {"3des", "des3-cbc"},
+     {"3des-ecb", "des3-ecb"},
+     {"3des-cbc", "des3-cbc"},
      {"cast5", "cast5-cbc"},
+     {"aes", "aes-cbc"},
+     {"rijndael", "aes-cbc"},
+     {"rijndael-cbc", "aes-cbc"},
+     {"rijndael-ecb", "aes-ecb"},
      {NULL}
  };

*************** static const struct ossl_cipher ossl_des
*** 460,465 ****
--- 664,679 ----
      64 / 8, 64 / 8, 0
  };

+ static const struct ossl_cipher ossl_des3_ecb = {
+     ossl_des3_init, ossl_des3_ecb_encrypt, ossl_des3_ecb_decrypt,
+     64 / 8, 192 / 8, 0
+ };
+
+ static const struct ossl_cipher ossl_des3_cbc = {
+     ossl_des3_init, ossl_des3_cbc_encrypt, ossl_des3_cbc_decrypt,
+     64 / 8, 192 / 8, 0
+ };
+
  static const struct ossl_cipher ossl_cast_ecb = {
      ossl_cast_init, ossl_cast_ecb_encrypt, ossl_cast_ecb_decrypt,
      64 / 8, 128 / 8, 0
*************** static const struct ossl_cipher ossl_cas
*** 470,475 ****
--- 684,701 ----
      64 / 8, 128 / 8, 0
  };

+ #ifdef GOT_AES
+ static const struct ossl_cipher ossl_aes_ecb = {
+     ossl_aes_init, ossl_aes_ecb_encrypt, ossl_aes_ecb_decrypt,
+     128 / 8, 256 / 8, 0
+ };
+
+ static const struct ossl_cipher ossl_aes_cbc = {
+     ossl_aes_init, ossl_aes_cbc_encrypt, ossl_aes_cbc_decrypt,
+     128 / 8, 256 / 8, 0
+ };
+ #endif
+
  /*
   * Special handlers
   */
*************** static const struct ossl_cipher_lookup o
*** 485,492 ****
--- 711,724 ----
      {"bf-cfb", &ossl_bf_cfb},
      {"des-ecb", &ossl_des_ecb},
      {"des-cbc", &ossl_des_cbc},
+     {"des3-ecb", &ossl_des3_ecb},
+     {"des3-cbc", &ossl_des3_cbc},
      {"cast5-ecb", &ossl_cast_ecb},
      {"cast5-cbc", &ossl_cast_cbc},
+ #ifdef GOT_AES
+     {"aes-ecb", &ossl_aes_ecb},
+     {"aes-cbc", &ossl_aes_cbc},
+ #endif
      {NULL}
  };

Index: pgsql/contrib/pgcrypto/README.pgcrypto
===================================================================
*** pgsql.orig/contrib/pgcrypto/README.pgcrypto
--- pgsql/contrib/pgcrypto/README.pgcrypto
*************** internal (default):
*** 178,187 ****
      Ciphers: Blowfish, Rijndael-128


! OpenSSL (0.9.6):
      Hashes:    MD5, SHA1, RIPEMD160, MD2
!     Ciphers:    DES, DESX, DES3, RC5, RC4, RC2, IDEA,
!         Blowfish, CAST5
      License:    BSD-like with strong advertisement
      Url:    http://www.openssl.org/

--- 178,186 ----
      Ciphers: Blowfish, Rijndael-128


! OpenSSL (0.9.7):
      Hashes:    MD5, SHA1, RIPEMD160, MD2
!     Ciphers:    Blowfish, AES, CAST5, DES, 3DES
      License:    BSD-like with strong advertisement
      Url:    http://www.openssl.org/


--

Re: [patch 0/6] pgcrypto update

From
Neil Conway
Date:
Marko Kreen wrote:
> Here are various updates for pgcrypto that
> I've been sitting on for some time now.

I'll apply all these later today, barring any objections.

-Neil

Re: [patch 0/6] pgcrypto update

From
Neil Conway
Date:
Marko Kreen wrote:
> Here are various updates for pgcrypto that
> I've been sitting on for some time now.

Thanks, applied.

-Neil

Re: [patch 0/6] pgcrypto update

From
Bruce Momjian
Date:

Your patch has been added to the PostgreSQL unapplied patches list at:

    http://momjian.postgresql.org/cgi-bin/pgpatches

It will be applied as soon as one of the PostgreSQL committers reviews
and approves it.

---------------------------------------------------------------------------

Marko Kreen wrote:
> Here are various updates for pgcrypto that
> I've been sitting on for some time now.
>
> They should be applied in order, but otherwise
> they stand alone - code should in working state
> after each one.
>
> Next update is hopefully pgp_encrypt, which I
> have already working, only some final polishing
> is missing.
>
> --
> marko
>
>
> ---------------------------(end of broadcast)---------------------------
> TIP 1: subscribe and unsubscribe commands go to majordomo@postgresql.org
>

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

Re: [patch 0/6] pgcrypto update

From
Tom Lane
Date:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
> Your patch has been added to the PostgreSQL unapplied patches list at:
>     http://momjian.postgresql.org/cgi-bin/pgpatches
> It will be applied as soon as one of the PostgreSQL committers reviews
> and approves it.

Neil applied all those some time ago, no?

            regards, tom lane

Re: [patch 0/6] pgcrypto update

From
Marko Kreen
Date:
On Fri, May 06, 2005 at 11:49:43AM -0400, Tom Lane wrote:
> Bruce Momjian <pgman@candle.pha.pa.us> writes:
> > Your patch has been added to the PostgreSQL unapplied patches list at:
> >     http://momjian.postgresql.org/cgi-bin/pgpatches
> > It will be applied as soon as one of the PostgreSQL committers reviews
> > and approves it.
>
> Neil applied all those some time ago, no?

Yes.

--
marko


Re: [patch 0/6] pgcrypto update

From
Bruce Momjian
Date:
Marko Kreen wrote:
> On Fri, May 06, 2005 at 11:49:43AM -0400, Tom Lane wrote:
> > Bruce Momjian <pgman@candle.pha.pa.us> writes:
> > > Your patch has been added to the PostgreSQL unapplied patches list at:
> > >     http://momjian.postgresql.org/cgi-bin/pgpatches
> > > It will be applied as soon as one of the PostgreSQL committers reviews
> > > and approves it.
> >
> > Neil applied all those some time ago, no?
>
> Yes.

Yes, I see now.  Thanks.

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

Re: [patch 0/6] pgcrypto update

From
Bruce Momjian
Date:
Already applied.

---------------------------------------------------------------------------

Marko Kreen wrote:
> Here are various updates for pgcrypto that
> I've been sitting on for some time now.
>
> They should be applied in order, but otherwise
> they stand alone - code should in working state
> after each one.
>
> Next update is hopefully pgp_encrypt, which I
> have already working, only some final polishing
> is missing.
>
> --
> marko
>
>
> ---------------------------(end of broadcast)---------------------------
> TIP 1: subscribe and unsubscribe commands go to majordomo@postgresql.org
>

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073