summaryrefslogtreecommitdiff
path: root/contrib/pgcrypto/openssl.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/pgcrypto/openssl.c')
-rw-r--r--contrib/pgcrypto/openssl.c388
1 files changed, 358 insertions, 30 deletions
diff --git a/contrib/pgcrypto/openssl.c b/contrib/pgcrypto/openssl.c
index 866d26f0ffc..b4d1a0a5e9b 100644
--- a/contrib/pgcrypto/openssl.c
+++ b/contrib/pgcrypto/openssl.c
@@ -2,7 +2,7 @@
* openssl.c
* Wrapper for OpenSSL library.
*
- * Copyright (c) 2000 Marko Kreen
+ * Copyright (c) 2001 Marko Kreen
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,60 +26,388 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: openssl.c,v 1.3 2001/03/22 03:59:10 momjian Exp $
+ * $Id: openssl.c,v 1.4 2001/08/21 00:42:41 momjian Exp $
*/
-#include "postgres.h"
+#include <postgres.h>
-#include "pgcrypto.h"
+#include "px.h"
-#include <evp.h>
+#include <openssl/evp.h>
+#include <openssl/blowfish.h>
+/*#include <openssl/crypto.h>*/
static uint
- pg_ossl_len(pg_digest * h);
-static uint8 *
- pg_ossl_digest(pg_digest * h, uint8 *src, uint len, uint8 *buf);
+digest_result_size(PX_MD * h)
+{
+ return EVP_MD_CTX_size((EVP_MD_CTX *) h->p.ptr);
+}
static uint
-pg_ossl_len(pg_digest * h)
+digest_block_size(PX_MD * h)
{
- return EVP_MD_size((EVP_MD *) h->misc.ptr);
+ return EVP_MD_CTX_block_size((EVP_MD_CTX *) h->p.ptr);
+}
+
+static void
+digest_reset(PX_MD * h)
+{
+ EVP_MD_CTX *ctx = (EVP_MD_CTX *) h->p.ptr;
+ const EVP_MD *md;
+
+ md = EVP_MD_CTX_md(ctx);
+
+ EVP_DigestInit(ctx, md);
}
-static uint8 *
-pg_ossl_digest(pg_digest * h, uint8 *src, uint len, uint8 *buf)
+static void
+digest_update(PX_MD * h, const uint8 * data, uint dlen)
{
- EVP_MD *md = (EVP_MD *) h->misc.ptr;
- EVP_MD_CTX ctx;
+ EVP_MD_CTX *ctx = (EVP_MD_CTX *) h->p.ptr;
+
+ EVP_DigestUpdate(ctx, data, dlen);
+}
- EVP_DigestInit(&ctx, md);
- EVP_DigestUpdate(&ctx, src, len);
- EVP_DigestFinal(&ctx, buf, NULL);
+static void
+digest_finish(PX_MD * h, uint8 * dst)
+{
+ EVP_MD_CTX *ctx = (EVP_MD_CTX *) h->p.ptr;
- return buf;
+ EVP_DigestFinal(ctx, dst, NULL);
}
-static int pg_openssl_initialized = 0;
+static void
+digest_free(PX_MD * h)
+{
+ EVP_MD_CTX *ctx = (EVP_MD_CTX *) h->p.ptr;
+
+ px_free(ctx);
+ px_free(h);
+}
+
+/* CIPHERS */
+
+/*
+ * The problem with OpenSSL is that the EVP* family
+ * of functions does not allow enough flexibility
+ * and forces some of the parameters (keylen,
+ * padding) to SSL defaults.
+ */
+
+
+typedef struct {
+ union {
+ struct {
+ BF_KEY key;
+ int num;
+ } bf;
+ EVP_CIPHER_CTX evp_ctx;
+ } u;
+ const EVP_CIPHER *evp_ciph;
+ uint8 key[EVP_MAX_KEY_LENGTH];
+ uint8 iv[EVP_MAX_IV_LENGTH];
+ uint klen;
+ uint init;
+} ossldata;
+
+/* generic EVP */
+
+static uint
+gen_evp_block_size(PX_Cipher *c)
+{
+ ossldata *od = (ossldata *)c->ptr;
+ return EVP_CIPHER_block_size(od->evp_ciph);
+}
+
+static uint
+gen_evp_key_size(PX_Cipher *c)
+{
+ ossldata *od = (ossldata *)c->ptr;
+ return EVP_CIPHER_key_length(od->evp_ciph);
+}
+
+static uint
+gen_evp_iv_size(PX_Cipher *c)
+{
+ uint ivlen;
+ ossldata *od = (ossldata *)c->ptr;
+ ivlen = EVP_CIPHER_iv_length(od->evp_ciph);
+ return ivlen;
+}
+
+static void
+gen_evp_free(PX_Cipher *c)
+{
+ ossldata *od = (ossldata*)c->ptr;
+ memset(od, 0, sizeof(*od));
+ pfree(od);
+ pfree(c);
+}
+
+/* fun */
+
+static int
+gen_evp_init(PX_Cipher *c, const uint8 *key, uint klen, const uint8 *iv)
+{
+ ossldata *od = (ossldata*)c->ptr;
+ uint bs = gen_evp_block_size(c);
+ if (iv) {
+ memcpy(od->iv, iv, bs);
+ } else
+ memset(od->iv, 0, bs);
+ memcpy(od->key, key, klen);
+ od->klen = klen;
+ od->init = 0;
+ return 0;
+}
+
+static void
+_gen_init(PX_Cipher *c, int enc)
+{
+ ossldata *od = c->ptr;
+
+ od->evp_ciph->init(&od->u.evp_ctx, od->key, od->iv, enc);
+ od->init = 1;
+ od->u.evp_ctx.encrypt = enc;
+}
+
+static int
+gen_evp_encrypt(PX_Cipher *c, const uint8 *data, uint dlen, uint8 *res)
+{
+ ossldata *od = c->ptr;
+ if (!od->init)
+ _gen_init(c, 1);
+ od->evp_ciph->do_cipher(&od->u.evp_ctx, res, data, dlen);
+ return 0;
+}
+
+static int
+gen_evp_decrypt(PX_Cipher *c, const uint8 *data, uint dlen, uint8 *res)
+{
+ ossldata *od = c->ptr;
+ if (!od->init)
+ _gen_init(c, 0);
+ od->evp_ciph->do_cipher(&od->u.evp_ctx, res, data, dlen);
+ return 0;
+}
+
+/* Blowfish */
+
+static int
+bf_init(PX_Cipher *c, const uint8 *key, uint klen, const uint8 *iv)
+{
+ ossldata *od = c->ptr;
+ BF_set_key(&od->u.bf.key, klen, key);
+ if (iv) {
+ memcpy(od->iv, iv, BF_BLOCK);
+ } else
+ memset(od->iv, 0, BF_BLOCK);
+ od->u.bf.num = 0;
+ return 0;
+}
-pg_digest *
-pg_find_digest(pg_digest * h, char *name)
+static int
+bf_ecb_encrypt(PX_Cipher *c, const uint8 *data, uint dlen, uint8 *res)
+{
+ uint bs = gen_evp_block_size(c), i;
+ ossldata *od = c->ptr;
+ for (i = 0; i < dlen / bs; i++)
+ BF_ecb_encrypt(data+i*bs, res+i*bs, &od->u.bf.key, BF_ENCRYPT);
+ return 0;
+}
+
+static int
+bf_ecb_decrypt(PX_Cipher *c, const uint8 *data, uint dlen, uint8 *res)
+{
+ uint bs = gen_evp_block_size(c), i;
+ ossldata *od = c->ptr;
+ for (i = 0; i < dlen / bs; i++)
+ BF_ecb_encrypt(data+i*bs, res+i*bs, &od->u.bf.key, BF_DECRYPT);
+ return 0;
+}
+
+static int
+bf_cbc_encrypt(PX_Cipher *c, const uint8 *data, uint dlen, uint8 *res)
+{
+ ossldata *od = c->ptr;
+ BF_cbc_encrypt(data, res, dlen, &od->u.bf.key, od->iv, BF_ENCRYPT);
+ return 0;
+}
+
+static int
+bf_cbc_decrypt(PX_Cipher *c, const uint8 *data, uint dlen, uint8 *res)
+{
+ ossldata *od = c->ptr;
+ BF_cbc_encrypt(data, res, dlen, &od->u.bf.key, od->iv, BF_DECRYPT);
+ return 0;
+}
+
+static int
+bf_cfb64_encrypt(PX_Cipher *c, const uint8 *data, uint dlen, uint8 *res)
+{
+ ossldata *od = c->ptr;
+ BF_cfb64_encrypt(data, res, dlen, &od->u.bf.key, od->iv,
+ &od->u.bf.num, BF_ENCRYPT);
+ return 0;
+}
+
+static int
+bf_cfb64_decrypt(PX_Cipher *c, const uint8 *data, uint dlen, uint8 *res)
+{
+ ossldata *od = c->ptr;
+ BF_cfb64_encrypt(data, res, dlen, &od->u.bf.key, od->iv,
+ &od->u.bf.num, BF_DECRYPT);
+ return 0;
+}
+
+static int
+bf_ofb64_encrypt(PX_Cipher *c, const uint8 *data, uint dlen, uint8 *res)
+{
+ ossldata *od = c->ptr;
+ BF_ofb64_encrypt(data, res, dlen, &od->u.bf.key, od->iv, &od->u.bf.num);
+ return 0;
+}
+
+static int
+bf_ofb64_decrypt(PX_Cipher *c, const uint8 *data, uint dlen, uint8 *res)
+{
+ ossldata *od = c->ptr;
+ BF_ofb64_encrypt(data, res, dlen, &od->u.bf.key, od->iv, &od->u.bf.num);
+ return 0;
+}
+
+/*
+ * aliases
+ */
+
+static PX_Alias ossl_aliases [] = {
+ { "bf", "bf-cbc" },
+ { "blowfish", "bf-cbc" },
+ { "blowfish-cbc", "bf-cbc" },
+ { "blowfish-ecb", "bf-ecb" },
+ { "blowfish-cfb", "bf-cfb" },
+ { "blowfish-ofb", "bf-ofb" },
+ { NULL }
+};
+
+/*
+static PX_Alias ossl_mode_aliases [] = {
+ { "cfb64", "cfb" },
+ { "ofb64", "ofb" },
+ { NULL }
+};*/
+
+/*
+ * Special handlers
+ */
+struct {
+ char *name;
+ PX_Cipher cf;
+} spec_types [] = {
+ { "bf-cbc", { gen_evp_block_size, gen_evp_key_size, gen_evp_iv_size,
+ bf_init, bf_cbc_encrypt, bf_cbc_decrypt, gen_evp_free}},
+ { "bf-ecb", { gen_evp_block_size, gen_evp_key_size, gen_evp_iv_size,
+ bf_init, bf_ecb_encrypt, bf_ecb_decrypt, gen_evp_free}},
+ { "bf-cfb", { gen_evp_block_size, gen_evp_key_size, gen_evp_iv_size,
+ bf_init, bf_cfb64_encrypt, bf_cfb64_decrypt, gen_evp_free}},
+ { "bf-ofb", { gen_evp_block_size, gen_evp_key_size, gen_evp_iv_size,
+ bf_init, bf_ofb64_encrypt, bf_ofb64_decrypt, gen_evp_free}},
+ { NULL }
+};
+
+/*
+ * Generic EVP_* functions handler
+ */
+static PX_Cipher gen_evp_handler = {
+ gen_evp_block_size, gen_evp_key_size, gen_evp_iv_size,
+ gen_evp_init, gen_evp_encrypt, gen_evp_decrypt, gen_evp_free
+};
+
+static int px_openssl_initialized = 0;
+
+/* ATM not needed
+static void *o_alloc(uint s) { return px_alloc(s); }
+static void *o_realloc(void *p) { return px_realloc(p); }
+static void o_free(void *p) { px_free(p); }
+*/
+
+/* PUBLIC functions */
+
+int
+px_find_digest(const char *name, PX_MD **res)
{
const EVP_MD *md;
+ EVP_MD_CTX *ctx;
+ PX_MD *h;
- if (!pg_openssl_initialized)
+ if (!px_openssl_initialized)
{
- OpenSSL_add_all_digests();
- pg_openssl_initialized = 1;
+ px_openssl_initialized = 1;
+ /*CRYPTO_set_mem_functions(o_alloc, o_realloc, o_free);*/
+ OpenSSL_add_all_algorithms();
}
md = EVP_get_digestbyname(name);
if (md == NULL)
- return NULL;
+ return -1;
- h->name = name;
- h->length = pg_ossl_len;
- h->digest = pg_ossl_digest;
- h->misc.ptr = (void *) md;
+ ctx = px_alloc(sizeof(*ctx));
+ EVP_DigestInit(ctx, md);
- return h;
+ h = px_alloc(sizeof(*h));
+ 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;
+ h->p.ptr = (void *) ctx;
+
+ *res = h;
+ return 0;
}
+
+
+int
+px_find_cipher(const char *name, PX_Cipher **res)
+{
+ uint i;
+ PX_Cipher *c = NULL, *csrc;
+ ossldata *od;
+
+ const EVP_CIPHER *evp_c;
+
+ if (!px_openssl_initialized) {
+ px_openssl_initialized = 1;
+ /*CRYPTO_set_mem_functions(o_alloc, o_realloc, o_free);*/
+ OpenSSL_add_all_algorithms();
+ }
+
+ name = px_resolve_alias(ossl_aliases, name);
+ evp_c = EVP_get_cipherbyname(name);
+ if (evp_c == NULL)
+ return -1;
+
+ od = px_alloc(sizeof(*od));
+ memset(od, 0, sizeof(*od));
+ od->evp_ciph = evp_c;
+
+ csrc = NULL;
+
+ for (i = 0; spec_types[i].name; i++)
+ if (!strcmp(name, spec_types[i].name)) {
+ csrc = &spec_types[i].cf;
+ break;
+ }
+
+ if (csrc == NULL)
+ csrc = &gen_evp_handler;
+
+ c = px_alloc(sizeof(*c));
+ memcpy(c, csrc, sizeof(*c));
+ c->ptr = od;
+
+ *res = c;
+ return 0;
+}
+