mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
/contrib/pgcrypto:
* remove support for encode() as it is in main tree now * remove krb5.c * new 'PX library' architecture * remove BSD license from my code to let the general PostgreSQL one to apply * md5, sha1: ANSIfy, use const where appropriate * various other formatting and clarity changes * hmac() * UN*X-like crypt() - system or internal crypt * Internal crypt: DES, Extended DES, MD5, Blowfish crypt-des.c, crypt-md5.c from FreeBSD crypt-blowfish.c from Solar Designer * gen_salt() for crypt() - Blowfish, MD5, DES, Extended DES * encrypt(), decrypt(), encrypt_iv(), decrypt_iv() * Cipher support in mhash.c, openssl.c * internal: Blowfish, Rijndael-128 ciphers * blf.[ch], rijndael.[ch] from OpenBSD * there will be generated file rijndael-tbl.inc. Marko Kreen
This commit is contained in:
@ -1,8 +1,8 @@
|
||||
/*
|
||||
* pgcrypto.c
|
||||
* Cryptographic digests for PostgreSQL.
|
||||
* Various cryptographic stuff for PostgreSQL.
|
||||
*
|
||||
* 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,113 +26,487 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: pgcrypto.c,v 1.7 2001/03/22 03:59:10 momjian Exp $
|
||||
* $Id: pgcrypto.c,v 1.8 2001/08/21 00:42:41 momjian Exp $
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
#include "utils/builtins.h"
|
||||
#include <postgres.h>
|
||||
#include <fmgr.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "px.h"
|
||||
#include "px-crypt.h"
|
||||
#include "pgcrypto.h"
|
||||
|
||||
/*
|
||||
* NAMEDATALEN is used for hash names
|
||||
*/
|
||||
#if NAMEDATALEN < 16
|
||||
#error "NAMEDATALEN < 16: too small"
|
||||
#endif
|
||||
|
||||
|
||||
/* exported functions */
|
||||
Datum digest(PG_FUNCTION_ARGS);
|
||||
Datum digest_exists(PG_FUNCTION_ARGS);
|
||||
|
||||
/* private stuff */
|
||||
static pg_digest *
|
||||
find_digest(pg_digest * hbuf, text *name, int silent);
|
||||
|
||||
typedef int (*PFN) (const char *name, void **res);
|
||||
static void *
|
||||
find_provider(text * name, PFN pf, char *desc, int silent);
|
||||
|
||||
/* SQL function: hash(text, text) returns text */
|
||||
PG_FUNCTION_INFO_V1(digest);
|
||||
PG_FUNCTION_INFO_V1(pg_digest);
|
||||
|
||||
Datum
|
||||
digest(PG_FUNCTION_ARGS)
|
||||
pg_digest(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *arg;
|
||||
bytea *arg;
|
||||
text *name;
|
||||
uint len,
|
||||
hlen;
|
||||
pg_digest *h,
|
||||
_hbuf;
|
||||
text *res;
|
||||
PX_MD *md;
|
||||
bytea *res;
|
||||
|
||||
if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
|
||||
PG_RETURN_NULL();
|
||||
|
||||
name = PG_GETARG_TEXT_P(1);
|
||||
h = find_digest(&_hbuf, name, 0); /* will give error if fails */
|
||||
|
||||
hlen = h->length(h);
|
||||
/* will give error if fails */
|
||||
md = find_provider(name, (PFN) px_find_digest, "Digest", 0);
|
||||
|
||||
hlen = px_md_result_size(md);
|
||||
|
||||
res = (text *) palloc(hlen + VARHDRSZ);
|
||||
VARATT_SIZEP(res) = hlen + VARHDRSZ;
|
||||
|
||||
arg = PG_GETARG_TEXT_P(0);
|
||||
arg = PG_GETARG_BYTEA_P(0);
|
||||
len = VARSIZE(arg) - VARHDRSZ;
|
||||
|
||||
h->digest(h, VARDATA(arg), len, VARDATA(res));
|
||||
px_md_update(md, VARDATA(arg), len);
|
||||
px_md_finish(md, VARDATA(res));
|
||||
px_md_free(md);
|
||||
|
||||
PG_FREE_IF_COPY(arg, 0);
|
||||
PG_FREE_IF_COPY(name, 1);
|
||||
|
||||
PG_RETURN_TEXT_P(res);
|
||||
PG_RETURN_BYTEA_P(res);
|
||||
}
|
||||
|
||||
/* check if given hash exists */
|
||||
PG_FUNCTION_INFO_V1(digest_exists);
|
||||
PG_FUNCTION_INFO_V1(pg_digest_exists);
|
||||
|
||||
Datum
|
||||
digest_exists(PG_FUNCTION_ARGS)
|
||||
pg_digest_exists(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *name;
|
||||
pg_digest _hbuf,
|
||||
*res;
|
||||
PX_MD *res;
|
||||
|
||||
if (PG_ARGISNULL(0))
|
||||
PG_RETURN_NULL();
|
||||
|
||||
name = PG_GETARG_TEXT_P(0);
|
||||
|
||||
res = find_digest(&_hbuf, name, 1);
|
||||
res = find_provider(name, (PFN) px_find_digest, "Digest", 1);
|
||||
|
||||
PG_FREE_IF_COPY(name, 0);
|
||||
|
||||
if (res != NULL)
|
||||
if (res == NULL)
|
||||
PG_RETURN_BOOL(false);
|
||||
|
||||
res->free(res);
|
||||
|
||||
PG_RETURN_BOOL(true);
|
||||
}
|
||||
|
||||
/* SQL function: hmac(data:text, key:text, type:text) */
|
||||
PG_FUNCTION_INFO_V1(pg_hmac);
|
||||
|
||||
Datum
|
||||
pg_hmac(PG_FUNCTION_ARGS)
|
||||
{
|
||||
bytea *arg;
|
||||
bytea *key;
|
||||
text *name;
|
||||
uint len,
|
||||
hlen,
|
||||
klen;
|
||||
PX_HMAC *h;
|
||||
bytea *res;
|
||||
|
||||
if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2))
|
||||
PG_RETURN_NULL();
|
||||
|
||||
name = PG_GETARG_TEXT_P(2);
|
||||
|
||||
/* will give error if fails */
|
||||
h = find_provider(name, (PFN) px_find_hmac, "HMAC", 0);
|
||||
|
||||
hlen = px_hmac_result_size(h);
|
||||
|
||||
res = (text *) palloc(hlen + VARHDRSZ);
|
||||
VARATT_SIZEP(res) = hlen + VARHDRSZ;
|
||||
|
||||
arg = PG_GETARG_BYTEA_P(0);
|
||||
key = PG_GETARG_BYTEA_P(1);
|
||||
len = VARSIZE(arg) - VARHDRSZ;
|
||||
klen = VARSIZE(key) - VARHDRSZ;
|
||||
|
||||
px_hmac_init(h, VARDATA(key), klen);
|
||||
px_hmac_update(h, VARDATA(arg), len);
|
||||
px_hmac_finish(h, VARDATA(res));
|
||||
px_hmac_free(h);
|
||||
|
||||
PG_FREE_IF_COPY(arg, 0);
|
||||
PG_FREE_IF_COPY(key, 1);
|
||||
PG_FREE_IF_COPY(name, 2);
|
||||
|
||||
PG_RETURN_BYTEA_P(res);
|
||||
}
|
||||
|
||||
/* check if given hmac type exists */
|
||||
PG_FUNCTION_INFO_V1(pg_hmac_exists);
|
||||
|
||||
Datum
|
||||
pg_hmac_exists(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *name;
|
||||
PX_HMAC *h;
|
||||
|
||||
if (PG_ARGISNULL(0))
|
||||
PG_RETURN_NULL();
|
||||
|
||||
name = PG_GETARG_TEXT_P(0);
|
||||
|
||||
h = find_provider(name, (PFN) px_find_hmac, "HMAC", 1);
|
||||
|
||||
PG_FREE_IF_COPY(name, 0);
|
||||
|
||||
if (h != NULL)
|
||||
{
|
||||
px_hmac_free(h);
|
||||
PG_RETURN_BOOL(true);
|
||||
}
|
||||
PG_RETURN_BOOL(false);
|
||||
}
|
||||
|
||||
static pg_digest *
|
||||
find_digest(pg_digest * hbuf, text *name, int silent)
|
||||
|
||||
/* SQL function: pg_gen_salt(text) returns text */
|
||||
PG_FUNCTION_INFO_V1(pg_gen_salt);
|
||||
|
||||
Datum
|
||||
pg_gen_salt(PG_FUNCTION_ARGS)
|
||||
{
|
||||
pg_digest *p;
|
||||
char buf[NAMEDATALEN];
|
||||
text *arg0;
|
||||
uint len;
|
||||
text *res;
|
||||
char buf[PX_MAX_SALT_LEN + 1];
|
||||
|
||||
if (PG_ARGISNULL(0))
|
||||
PG_RETURN_NULL();
|
||||
|
||||
arg0 = PG_GETARG_TEXT_P(0);
|
||||
|
||||
len = VARSIZE(arg0) - VARHDRSZ;
|
||||
len = len > PX_MAX_SALT_LEN ? PX_MAX_SALT_LEN : len;
|
||||
memcpy(buf, VARDATA(arg0), len);
|
||||
buf[len] = 0;
|
||||
len = px_gen_salt(buf, buf);
|
||||
if (len == 0)
|
||||
elog(ERROR, "No such crypt algorithm");
|
||||
|
||||
res = (text *) palloc(len + VARHDRSZ);
|
||||
VARATT_SIZEP(res) = len + VARHDRSZ;
|
||||
memcpy(VARDATA(res), buf, len);
|
||||
|
||||
PG_FREE_IF_COPY(arg0, 0);
|
||||
|
||||
PG_RETURN_TEXT_P(res);
|
||||
}
|
||||
|
||||
/* SQL function: pg_crypt(psw:text, salt:text) returns text */
|
||||
PG_FUNCTION_INFO_V1(pg_crypt);
|
||||
|
||||
Datum
|
||||
pg_crypt(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *arg0;
|
||||
text *arg1;
|
||||
uint len0,
|
||||
len1,
|
||||
clen;
|
||||
char *buf0,
|
||||
*buf1,
|
||||
*cres,
|
||||
*resbuf;
|
||||
text *res;
|
||||
|
||||
if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
|
||||
PG_RETURN_NULL();
|
||||
|
||||
arg0 = PG_GETARG_TEXT_P(0);
|
||||
arg1 = PG_GETARG_TEXT_P(1);
|
||||
len0 = VARSIZE(arg0) - VARHDRSZ;
|
||||
len1 = VARSIZE(arg1) - VARHDRSZ;
|
||||
|
||||
buf0 = palloc(len0 + 1);
|
||||
buf1 = palloc(len1 + 1);
|
||||
|
||||
memcpy(buf0, VARDATA(arg0), len0);
|
||||
memcpy(buf1, VARDATA(arg1), len1);
|
||||
|
||||
buf0[len0] = '\0';
|
||||
buf1[len1] = '\0';
|
||||
|
||||
resbuf = palloc(PX_MAX_CRYPT);
|
||||
|
||||
memset(resbuf, 0, PX_MAX_CRYPT);
|
||||
|
||||
cres = px_crypt(buf0, buf1, resbuf, PX_MAX_CRYPT);
|
||||
|
||||
pfree(buf0);
|
||||
pfree(buf1);
|
||||
|
||||
if (cres == NULL)
|
||||
elog(ERROR, "crypt(3) returned NULL");
|
||||
|
||||
clen = strlen(cres);
|
||||
|
||||
res = (text *) palloc(clen + VARHDRSZ);
|
||||
VARATT_SIZEP(res) = clen + VARHDRSZ;
|
||||
memcpy(VARDATA(res), cres, clen);
|
||||
pfree(resbuf);
|
||||
|
||||
PG_FREE_IF_COPY(arg0, 0);
|
||||
PG_FREE_IF_COPY(arg1, 1);
|
||||
|
||||
PG_RETURN_TEXT_P(res);
|
||||
}
|
||||
|
||||
/* SQL function: pg_encrypt(text, text, text) returns text */
|
||||
PG_FUNCTION_INFO_V1(pg_encrypt);
|
||||
|
||||
Datum
|
||||
pg_encrypt(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int err;
|
||||
bytea *data, *key, *res;
|
||||
text *type;
|
||||
PX_Combo *c;
|
||||
uint dlen, klen, rlen;
|
||||
|
||||
if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2))
|
||||
PG_RETURN_NULL();
|
||||
|
||||
type = PG_GETARG_TEXT_P(2);
|
||||
c = find_provider(type, (PFN)px_find_combo, "Cipher", 0);
|
||||
|
||||
data = PG_GETARG_BYTEA_P(0);
|
||||
key = PG_GETARG_BYTEA_P(1);
|
||||
dlen = VARSIZE(data) - VARHDRSZ;
|
||||
klen = VARSIZE(key) - VARHDRSZ;
|
||||
|
||||
rlen = px_combo_encrypt_len(c, dlen);
|
||||
res = palloc(VARHDRSZ + rlen);
|
||||
|
||||
err = px_combo_init(c, VARDATA(key), klen, NULL, 0);
|
||||
if (!err)
|
||||
err = px_combo_encrypt(c, VARDATA(data), dlen, VARDATA(res), &rlen);
|
||||
px_combo_free(c);
|
||||
|
||||
PG_FREE_IF_COPY(data, 0);
|
||||
PG_FREE_IF_COPY(key, 1);
|
||||
PG_FREE_IF_COPY(type, 2);
|
||||
|
||||
if (err) {
|
||||
pfree(res);
|
||||
elog(ERROR, "encrypt error: %d", err);
|
||||
}
|
||||
|
||||
VARATT_SIZEP(res) = VARHDRSZ + rlen;
|
||||
PG_RETURN_BYTEA_P(res);
|
||||
}
|
||||
|
||||
/* SQL function: pg_decrypt(text, text, text) returns text */
|
||||
PG_FUNCTION_INFO_V1(pg_decrypt);
|
||||
|
||||
Datum
|
||||
pg_decrypt(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int err;
|
||||
bytea *data, *key, *res;
|
||||
text *type;
|
||||
PX_Combo *c;
|
||||
uint dlen, klen, rlen;
|
||||
|
||||
if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2))
|
||||
PG_RETURN_NULL();
|
||||
|
||||
type = PG_GETARG_TEXT_P(2);
|
||||
c = find_provider(type, (PFN)px_find_combo, "Cipher", 0);
|
||||
|
||||
data = PG_GETARG_BYTEA_P(0);
|
||||
key = PG_GETARG_BYTEA_P(1);
|
||||
dlen = VARSIZE(data) - VARHDRSZ;
|
||||
klen = VARSIZE(key) - VARHDRSZ;
|
||||
|
||||
rlen = px_combo_decrypt_len(c, dlen);
|
||||
res = palloc(VARHDRSZ + rlen);
|
||||
|
||||
err = px_combo_init(c, VARDATA(key), klen, NULL, 0);
|
||||
if (!err)
|
||||
err = px_combo_decrypt(c, VARDATA(data), dlen, VARDATA(res), &rlen);
|
||||
|
||||
px_combo_free(c);
|
||||
|
||||
if (err)
|
||||
elog(ERROR, "decrypt error: %d", err);
|
||||
|
||||
VARATT_SIZEP(res) = VARHDRSZ + rlen;
|
||||
|
||||
PG_FREE_IF_COPY(data, 0);
|
||||
PG_FREE_IF_COPY(key, 1);
|
||||
PG_FREE_IF_COPY(type, 2);
|
||||
|
||||
PG_RETURN_BYTEA_P(res);
|
||||
}
|
||||
|
||||
/* SQL function: pg_encrypt(text, text, text) returns text */
|
||||
PG_FUNCTION_INFO_V1(pg_encrypt_iv);
|
||||
|
||||
Datum
|
||||
pg_encrypt_iv(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int err;
|
||||
bytea *data, *key, *iv, *res;
|
||||
text *type;
|
||||
PX_Combo *c;
|
||||
uint dlen, klen, ivlen, rlen;
|
||||
|
||||
if (PG_ARGISNULL(0) || PG_ARGISNULL(1)
|
||||
|| PG_ARGISNULL(2) || PG_ARGISNULL(3))
|
||||
PG_RETURN_NULL();
|
||||
|
||||
type = PG_GETARG_TEXT_P(3);
|
||||
c = find_provider(type, (PFN)px_find_combo, "Cipher", 0);
|
||||
|
||||
data = PG_GETARG_BYTEA_P(0);
|
||||
key = PG_GETARG_BYTEA_P(1);
|
||||
iv = PG_GETARG_BYTEA_P(2);
|
||||
dlen = VARSIZE(data) - VARHDRSZ;
|
||||
klen = VARSIZE(key) - VARHDRSZ;
|
||||
ivlen = VARSIZE(iv) - VARHDRSZ;
|
||||
|
||||
rlen = px_combo_encrypt_len(c, dlen);
|
||||
res = palloc(VARHDRSZ + rlen);
|
||||
|
||||
err = px_combo_init(c, VARDATA(key), klen, VARDATA(iv), ivlen);
|
||||
if (!err)
|
||||
px_combo_encrypt(c, VARDATA(data), dlen, VARDATA(res), &rlen);
|
||||
|
||||
px_combo_free(c);
|
||||
|
||||
if (err)
|
||||
elog(ERROR, "encrypt_iv error: %d", err);
|
||||
|
||||
VARATT_SIZEP(res) = VARHDRSZ + rlen;
|
||||
|
||||
PG_FREE_IF_COPY(data, 0);
|
||||
PG_FREE_IF_COPY(key, 1);
|
||||
PG_FREE_IF_COPY(iv, 2);
|
||||
PG_FREE_IF_COPY(type, 3);
|
||||
|
||||
PG_RETURN_BYTEA_P(res);
|
||||
}
|
||||
|
||||
/* SQL function: pg_decrypt_iv(text, text, text) returns text */
|
||||
PG_FUNCTION_INFO_V1(pg_decrypt_iv);
|
||||
|
||||
Datum
|
||||
pg_decrypt_iv(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int err;
|
||||
bytea *data, *key, *iv, *res;
|
||||
text *type;
|
||||
PX_Combo *c;
|
||||
uint dlen, klen, rlen, ivlen;
|
||||
|
||||
if (PG_ARGISNULL(0) || PG_ARGISNULL(1)
|
||||
|| PG_ARGISNULL(2) || PG_ARGISNULL(3))
|
||||
PG_RETURN_NULL();
|
||||
|
||||
type = PG_GETARG_TEXT_P(3);
|
||||
c = find_provider(type, (PFN)px_find_combo, "Cipher", 0);
|
||||
|
||||
data = PG_GETARG_BYTEA_P(0);
|
||||
key = PG_GETARG_BYTEA_P(1);
|
||||
iv = PG_GETARG_BYTEA_P(2);
|
||||
dlen = VARSIZE(data) - VARHDRSZ;
|
||||
klen = VARSIZE(key) - VARHDRSZ;
|
||||
ivlen = VARSIZE(iv) - VARHDRSZ;
|
||||
|
||||
rlen = px_combo_decrypt_len(c, dlen);
|
||||
res = palloc(VARHDRSZ + rlen);
|
||||
|
||||
err = px_combo_init(c, VARDATA(key), klen, VARDATA(iv), ivlen);
|
||||
if (!err)
|
||||
px_combo_decrypt(c, VARDATA(data), dlen, VARDATA(res), &rlen);
|
||||
|
||||
px_combo_free(c);
|
||||
|
||||
if (err)
|
||||
elog(ERROR, "decrypt_iv error: %d", err);
|
||||
|
||||
VARATT_SIZEP(res) = VARHDRSZ + rlen;
|
||||
|
||||
PG_FREE_IF_COPY(data, 0);
|
||||
PG_FREE_IF_COPY(key, 1);
|
||||
PG_FREE_IF_COPY(iv, 2);
|
||||
PG_FREE_IF_COPY(type, 3);
|
||||
|
||||
PG_RETURN_BYTEA_P(res);
|
||||
}
|
||||
|
||||
/* SQL function: pg_decrypt(text, text, text) returns text */
|
||||
PG_FUNCTION_INFO_V1(pg_cipher_exists);
|
||||
|
||||
Datum
|
||||
pg_cipher_exists(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *arg;
|
||||
PX_Combo *c;
|
||||
|
||||
if (PG_ARGISNULL(0))
|
||||
PG_RETURN_NULL();
|
||||
|
||||
arg = PG_GETARG_TEXT_P(0);
|
||||
|
||||
c = find_provider(arg, (PFN)px_find_combo, "Cipher", 1);
|
||||
if (c != NULL)
|
||||
px_combo_free(c);
|
||||
|
||||
PG_RETURN_BOOL((c != NULL) ? true : false);
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
find_provider(text * name,
|
||||
PFN provider_lookup,
|
||||
char *desc, int silent)
|
||||
{
|
||||
void *res;
|
||||
char buf[PX_MAX_NAMELEN + 1],
|
||||
*p;
|
||||
uint len;
|
||||
uint i;
|
||||
int err;
|
||||
|
||||
len = VARSIZE(name) - VARHDRSZ;
|
||||
if (len >= NAMEDATALEN)
|
||||
if (len > PX_MAX_NAMELEN)
|
||||
{
|
||||
if (silent)
|
||||
return NULL;
|
||||
elog(ERROR, "Hash type does not exist (name too long)");
|
||||
elog(ERROR, "%s type does not exist (name too long)", desc);
|
||||
}
|
||||
|
||||
memcpy(buf, VARDATA(name), len);
|
||||
p = VARDATA(name);
|
||||
for (i = 0; i < len; i++)
|
||||
buf[i] = tolower(p[i]);
|
||||
buf[len] = 0;
|
||||
|
||||
p = pg_find_digest(hbuf, buf);
|
||||
err = provider_lookup(buf, &res);
|
||||
|
||||
if (p == NULL && !silent)
|
||||
elog(ERROR, "Hash type does not exist: '%s'", buf);
|
||||
return p;
|
||||
if (err && !silent)
|
||||
elog(ERROR, "%s type does not exist: '%s'", desc, buf);
|
||||
|
||||
return err ? NULL : res;
|
||||
}
|
||||
|
Reference in New Issue
Block a user