summaryrefslogtreecommitdiffstats
path: root/contrib/pgcrypto/pgcrypto.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/pgcrypto/pgcrypto.c')
-rw-r--r--contrib/pgcrypto/pgcrypto.c475
1 files changed, 475 insertions, 0 deletions
diff --git a/contrib/pgcrypto/pgcrypto.c b/contrib/pgcrypto/pgcrypto.c
new file mode 100644
index 0000000..f0ac625
--- /dev/null
+++ b/contrib/pgcrypto/pgcrypto.c
@@ -0,0 +1,475 @@
+/*
+ * pgcrypto.c
+ * Various cryptographic stuff for PostgreSQL.
+ *
+ * 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.
+ *
+ * contrib/pgcrypto/pgcrypto.c
+ */
+
+#include "postgres.h"
+
+#include <ctype.h>
+
+#include "parser/scansup.h"
+#include "pgcrypto.h"
+#include "px-crypt.h"
+#include "px.h"
+#include "utils/builtins.h"
+#include "utils/uuid.h"
+
+PG_MODULE_MAGIC;
+
+/* private stuff */
+
+typedef int (*PFN) (const char *name, void **res);
+static void *find_provider(text *name, PFN pf, const char *desc, int silent);
+
+/* SQL function: hash(bytea, text) returns bytea */
+PG_FUNCTION_INFO_V1(pg_digest);
+
+Datum
+pg_digest(PG_FUNCTION_ARGS)
+{
+ bytea *arg;
+ text *name;
+ unsigned len,
+ hlen;
+ PX_MD *md;
+ bytea *res;
+
+ name = PG_GETARG_TEXT_PP(1);
+
+ /* 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);
+ SET_VARSIZE(res, hlen + VARHDRSZ);
+
+ arg = PG_GETARG_BYTEA_PP(0);
+ len = VARSIZE_ANY_EXHDR(arg);
+
+ px_md_update(md, (uint8 *) VARDATA_ANY(arg), len);
+ px_md_finish(md, (uint8 *) VARDATA(res));
+ px_md_free(md);
+
+ PG_FREE_IF_COPY(arg, 0);
+ PG_FREE_IF_COPY(name, 1);
+
+ PG_RETURN_BYTEA_P(res);
+}
+
+/* SQL function: hmac(data:bytea, key:bytea, type:text) returns bytea */
+PG_FUNCTION_INFO_V1(pg_hmac);
+
+Datum
+pg_hmac(PG_FUNCTION_ARGS)
+{
+ bytea *arg;
+ bytea *key;
+ text *name;
+ unsigned len,
+ hlen,
+ klen;
+ PX_HMAC *h;
+ bytea *res;
+
+ name = PG_GETARG_TEXT_PP(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);
+ SET_VARSIZE(res, hlen + VARHDRSZ);
+
+ arg = PG_GETARG_BYTEA_PP(0);
+ key = PG_GETARG_BYTEA_PP(1);
+ len = VARSIZE_ANY_EXHDR(arg);
+ klen = VARSIZE_ANY_EXHDR(key);
+
+ px_hmac_init(h, (uint8 *) VARDATA_ANY(key), klen);
+ px_hmac_update(h, (uint8 *) VARDATA_ANY(arg), len);
+ px_hmac_finish(h, (uint8 *) 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);
+}
+
+
+/* SQL function: pg_gen_salt(text) returns text */
+PG_FUNCTION_INFO_V1(pg_gen_salt);
+
+Datum
+pg_gen_salt(PG_FUNCTION_ARGS)
+{
+ text *arg0 = PG_GETARG_TEXT_PP(0);
+ int len;
+ char buf[PX_MAX_SALT_LEN + 1];
+
+ text_to_cstring_buffer(arg0, buf, sizeof(buf));
+ len = px_gen_salt(buf, buf, 0);
+ if (len < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("gen_salt: %s", px_strerror(len))));
+
+ PG_FREE_IF_COPY(arg0, 0);
+
+ PG_RETURN_TEXT_P(cstring_to_text_with_len(buf, len));
+}
+
+/* SQL function: pg_gen_salt(text, int4) returns text */
+PG_FUNCTION_INFO_V1(pg_gen_salt_rounds);
+
+Datum
+pg_gen_salt_rounds(PG_FUNCTION_ARGS)
+{
+ text *arg0 = PG_GETARG_TEXT_PP(0);
+ int rounds = PG_GETARG_INT32(1);
+ int len;
+ char buf[PX_MAX_SALT_LEN + 1];
+
+ text_to_cstring_buffer(arg0, buf, sizeof(buf));
+ len = px_gen_salt(buf, buf, rounds);
+ if (len < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("gen_salt: %s", px_strerror(len))));
+
+ PG_FREE_IF_COPY(arg0, 0);
+
+ PG_RETURN_TEXT_P(cstring_to_text_with_len(buf, len));
+}
+
+/* SQL function: pg_crypt(psw:text, salt:text) returns text */
+PG_FUNCTION_INFO_V1(pg_crypt);
+
+Datum
+pg_crypt(PG_FUNCTION_ARGS)
+{
+ text *arg0 = PG_GETARG_TEXT_PP(0);
+ text *arg1 = PG_GETARG_TEXT_PP(1);
+ char *buf0,
+ *buf1,
+ *cres,
+ *resbuf;
+ text *res;
+
+ buf0 = text_to_cstring(arg0);
+ buf1 = text_to_cstring(arg1);
+
+ resbuf = palloc0(PX_MAX_CRYPT);
+
+ cres = px_crypt(buf0, buf1, resbuf, PX_MAX_CRYPT);
+
+ pfree(buf0);
+ pfree(buf1);
+
+ if (cres == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("crypt(3) returned NULL")));
+
+ res = cstring_to_text(cres);
+
+ pfree(resbuf);
+
+ PG_FREE_IF_COPY(arg0, 0);
+ PG_FREE_IF_COPY(arg1, 1);
+
+ 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)
+{
+ int err;
+ bytea *data,
+ *key,
+ *res;
+ text *type;
+ PX_Combo *c;
+ unsigned dlen,
+ klen,
+ rlen;
+
+ type = PG_GETARG_TEXT_PP(2);
+ c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
+
+ data = PG_GETARG_BYTEA_PP(0);
+ key = PG_GETARG_BYTEA_PP(1);
+ dlen = VARSIZE_ANY_EXHDR(data);
+ klen = VARSIZE_ANY_EXHDR(key);
+
+ rlen = px_combo_encrypt_len(c, dlen);
+ res = palloc(VARHDRSZ + rlen);
+
+ err = px_combo_init(c, (uint8 *) VARDATA_ANY(key), klen, NULL, 0);
+ if (!err)
+ err = px_combo_encrypt(c, (uint8 *) VARDATA_ANY(data), dlen,
+ (uint8 *) 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);
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("encrypt error: %s", px_strerror(err))));
+ }
+
+ SET_VARSIZE(res, VARHDRSZ + rlen);
+ 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)
+{
+ int err;
+ bytea *data,
+ *key,
+ *res;
+ text *type;
+ PX_Combo *c;
+ unsigned dlen,
+ klen,
+ rlen;
+
+ type = PG_GETARG_TEXT_PP(2);
+ c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
+
+ data = PG_GETARG_BYTEA_PP(0);
+ key = PG_GETARG_BYTEA_PP(1);
+ dlen = VARSIZE_ANY_EXHDR(data);
+ klen = VARSIZE_ANY_EXHDR(key);
+
+ rlen = px_combo_decrypt_len(c, dlen);
+ res = palloc(VARHDRSZ + rlen);
+
+ err = px_combo_init(c, (uint8 *) VARDATA_ANY(key), klen, NULL, 0);
+ if (!err)
+ err = px_combo_decrypt(c, (uint8 *) VARDATA_ANY(data), dlen,
+ (uint8 *) VARDATA(res), &rlen);
+
+ px_combo_free(c);
+
+ if (err)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("decrypt error: %s", px_strerror(err))));
+
+ SET_VARSIZE(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_iv(bytea, bytea, bytea, text) returns bytea */
+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;
+ unsigned dlen,
+ klen,
+ ivlen,
+ rlen;
+
+ type = PG_GETARG_TEXT_PP(3);
+ c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
+
+ data = PG_GETARG_BYTEA_PP(0);
+ key = PG_GETARG_BYTEA_PP(1);
+ iv = PG_GETARG_BYTEA_PP(2);
+ dlen = VARSIZE_ANY_EXHDR(data);
+ klen = VARSIZE_ANY_EXHDR(key);
+ ivlen = VARSIZE_ANY_EXHDR(iv);
+
+ rlen = px_combo_encrypt_len(c, dlen);
+ res = palloc(VARHDRSZ + rlen);
+
+ err = px_combo_init(c, (uint8 *) VARDATA_ANY(key), klen,
+ (uint8 *) VARDATA_ANY(iv), ivlen);
+ if (!err)
+ err = px_combo_encrypt(c, (uint8 *) VARDATA_ANY(data), dlen,
+ (uint8 *) VARDATA(res), &rlen);
+
+ px_combo_free(c);
+
+ if (err)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("encrypt_iv error: %s", px_strerror(err))));
+
+ SET_VARSIZE(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(bytea, bytea, bytea, text) returns bytea */
+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;
+ unsigned dlen,
+ klen,
+ rlen,
+ ivlen;
+
+ type = PG_GETARG_TEXT_PP(3);
+ c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
+
+ data = PG_GETARG_BYTEA_PP(0);
+ key = PG_GETARG_BYTEA_PP(1);
+ iv = PG_GETARG_BYTEA_PP(2);
+ dlen = VARSIZE_ANY_EXHDR(data);
+ klen = VARSIZE_ANY_EXHDR(key);
+ ivlen = VARSIZE_ANY_EXHDR(iv);
+
+ rlen = px_combo_decrypt_len(c, dlen);
+ res = palloc(VARHDRSZ + rlen);
+
+ err = px_combo_init(c, (uint8 *) VARDATA_ANY(key), klen,
+ (uint8 *) VARDATA_ANY(iv), ivlen);
+ if (!err)
+ err = px_combo_decrypt(c, (uint8 *) VARDATA_ANY(data), dlen,
+ (uint8 *) VARDATA(res), &rlen);
+
+ px_combo_free(c);
+
+ if (err)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("decrypt_iv error: %s", px_strerror(err))));
+
+ SET_VARSIZE(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_random_bytes(int4) returns bytea */
+PG_FUNCTION_INFO_V1(pg_random_bytes);
+
+Datum
+pg_random_bytes(PG_FUNCTION_ARGS)
+{
+ int len = PG_GETARG_INT32(0);
+ bytea *res;
+
+ if (len < 1 || len > 1024)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("Length not in range")));
+
+ res = palloc(VARHDRSZ + len);
+ SET_VARSIZE(res, VARHDRSZ + len);
+
+ /* generate result */
+ if (!pg_strong_random(VARDATA(res), len))
+ px_THROW_ERROR(PXE_NO_RANDOM);
+
+ PG_RETURN_BYTEA_P(res);
+}
+
+/* SQL function: gen_random_uuid() returns uuid */
+PG_FUNCTION_INFO_V1(pg_random_uuid);
+
+Datum
+pg_random_uuid(PG_FUNCTION_ARGS)
+{
+ /* redirect to built-in function */
+ return gen_random_uuid(fcinfo);
+}
+
+static void *
+find_provider(text *name,
+ PFN provider_lookup,
+ const char *desc, int silent)
+{
+ void *res;
+ char *buf;
+ int err;
+
+ buf = downcase_truncate_identifier(VARDATA_ANY(name),
+ VARSIZE_ANY_EXHDR(name),
+ false);
+
+ err = provider_lookup(buf, &res);
+
+ if (err && !silent)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("Cannot use \"%s\": %s", buf, px_strerror(err))));
+
+ pfree(buf);
+
+ return err ? NULL : res;
+}