openGauss-server/contrib/pgcrypto/pgcrypto.cpp

409 lines
11 KiB
C++

/*
* 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 "knl/knl_variable.h"
#include <ctype.h>
#include "parser/scansup.h"
#include "utils/builtins.h"
#include "px.h"
#include "px-crypt.h"
#include "pgcrypto.h"
PG_MODULE_MAGIC;
/* private stuff */
typedef int (*PFN)(const char* name, void** res);
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(PG_FUNCTION_ARGS)
{
bytea* arg = NULL;
text* name = NULL;
unsigned len, hlen;
PX_MD* md = NULL;
bytea* res = NULL;
name = PG_GETARG_TEXT_P(1);
/* will give error if fails */
md = (PX_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_P(0);
len = VARSIZE(arg) - VARHDRSZ;
px_md_update(md, (uint8*)VARDATA(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 = NULL;
bytea* key = NULL;
text* name = NULL;
unsigned len, hlen, klen;
PX_HMAC* h = NULL;
bytea* res = NULL;
name = PG_GETARG_TEXT_P(2);
/* will give error if fails */
h = (PX_HMAC*)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_P(0);
key = PG_GETARG_BYTEA_P(1);
len = VARSIZE(arg) - VARHDRSZ;
klen = VARSIZE(key) - VARHDRSZ;
px_hmac_init(h, (uint8*)VARDATA(key), klen);
px_hmac_update(h, (uint8*)VARDATA(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 = NULL;
buf0 = text_to_cstring(arg0);
buf1 = text_to_cstring(arg1);
resbuf = (char*)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 = NULL;
PX_Combo* c = NULL;
unsigned dlen, klen, rlen;
type = PG_GETARG_TEXT_P(2);
c = (PX_Combo*)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 = (bytea*)palloc(VARHDRSZ + rlen);
err = px_combo_init(c, (uint8*)VARDATA(key), klen, NULL, 0);
if (!err)
err = px_combo_encrypt(c, (uint8*)VARDATA(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 = NULL;
PX_Combo* c = NULL;
unsigned dlen, klen, rlen;
type = PG_GETARG_TEXT_P(2);
c = (PX_Combo*)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 = (bytea*)palloc(VARHDRSZ + rlen);
err = px_combo_init(c, (uint8*)VARDATA(key), klen, NULL, 0);
if (!err)
err = px_combo_decrypt(c, (uint8*)VARDATA(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 = NULL;
PX_Combo* c = NULL;
unsigned dlen, klen, ivlen, rlen;
type = PG_GETARG_TEXT_P(3);
c = (PX_Combo*)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 = (bytea*)palloc(VARHDRSZ + rlen);
err = px_combo_init(c, (uint8*)VARDATA(key), klen, (uint8*)VARDATA(iv), ivlen);
if (!err)
err = px_combo_encrypt(c, (uint8*)VARDATA(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 = NULL;
PX_Combo* c = NULL;
unsigned dlen, klen, rlen, ivlen;
type = PG_GETARG_TEXT_P(3);
c = (PX_Combo*)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 = (bytea*)palloc(VARHDRSZ + rlen);
err = px_combo_init(c, (uint8*)VARDATA(key), klen, (uint8*)VARDATA(iv), ivlen);
if (!err)
err = px_combo_decrypt(c, (uint8*)VARDATA(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 err;
int len = PG_GETARG_INT32(0);
bytea* res = NULL;
if (len < 1 || len > 1024)
ereport(ERROR, (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), errmsg("Length not in range")));
res = (bytea*)palloc(VARHDRSZ + len);
SET_VARSIZE(res, VARHDRSZ + len);
/* generate result */
err = px_get_random_bytes((uint8*)VARDATA(res), len);
if (err < 0)
ereport(ERROR,
(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
errmsg("Random generator error: %s", px_strerror(err))));
PG_RETURN_BYTEA_P(res);
}
static void* find_provider(text* name, PFN provider_lookup, char* desc, int silent)
{
void* res = NULL;
char* buf = NULL;
int err;
buf = downcase_truncate_identifier(VARDATA(name), VARSIZE(name) - VARHDRSZ, 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;
}