/*------------------------------------------------------------------------- * * cryptohashfuncs.c * Cryptographic hash functions * * Portions Copyright (c) 2018-2023, PostgreSQL Global Development Group * * * IDENTIFICATION * src/backend/utils/adt/cryptohashfuncs.c * *------------------------------------------------------------------------- */ #include "postgres.h" #include "common/cryptohash.h" #include "common/md5.h" #include "common/sha2.h" #include "utils/builtins.h" #include "varatt.h" /* * MD5 */ /* MD5 produces a 16 byte (128 bit) hash; double it for hex */ #define MD5_HASH_LEN 32 /* * Create an MD5 hash of a text value and return it as hex string. */ Datum md5_text(PG_FUNCTION_ARGS) { text *in_text = PG_GETARG_TEXT_PP(0); size_t len; char hexsum[MD5_HASH_LEN + 1]; const char *errstr = NULL; /* Calculate the length of the buffer using varlena metadata */ len = VARSIZE_ANY_EXHDR(in_text); /* get the hash result */ if (pg_md5_hash(VARDATA_ANY(in_text), len, hexsum, &errstr) == false) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("could not compute %s hash: %s", "MD5", errstr))); /* convert to text and return it */ PG_RETURN_TEXT_P(cstring_to_text(hexsum)); } /* * Create an MD5 hash of a bytea value and return it as a hex string. */ Datum md5_bytea(PG_FUNCTION_ARGS) { bytea *in = PG_GETARG_BYTEA_PP(0); size_t len; char hexsum[MD5_HASH_LEN + 1]; const char *errstr = NULL; len = VARSIZE_ANY_EXHDR(in); if (pg_md5_hash(VARDATA_ANY(in), len, hexsum, &errstr) == false) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("could not compute %s hash: %s", "MD5", errstr))); PG_RETURN_TEXT_P(cstring_to_text(hexsum)); } /* * Internal routine to compute a cryptohash with the given bytea input. */ static inline bytea * cryptohash_internal(pg_cryptohash_type type, bytea *input) { const uint8 *data; const char *typestr = NULL; int digest_len = 0; size_t len; pg_cryptohash_ctx *ctx; bytea *result; switch (type) { case PG_SHA224: typestr = "SHA224"; digest_len = PG_SHA224_DIGEST_LENGTH; break; case PG_SHA256: typestr = "SHA256"; digest_len = PG_SHA256_DIGEST_LENGTH; break; case PG_SHA384: typestr = "SHA384"; digest_len = PG_SHA384_DIGEST_LENGTH; break; case PG_SHA512: typestr = "SHA512"; digest_len = PG_SHA512_DIGEST_LENGTH; break; case PG_MD5: case PG_SHA1: elog(ERROR, "unsupported cryptohash type %d", type); break; } result = palloc0(digest_len + VARHDRSZ); len = VARSIZE_ANY_EXHDR(input); data = (unsigned char *) VARDATA_ANY(input); ctx = pg_cryptohash_create(type); if (pg_cryptohash_init(ctx) < 0) elog(ERROR, "could not initialize %s context: %s", typestr, pg_cryptohash_error(ctx)); if (pg_cryptohash_update(ctx, data, len) < 0) elog(ERROR, "could not update %s context: %s", typestr, pg_cryptohash_error(ctx)); if (pg_cryptohash_final(ctx, (unsigned char *) VARDATA(result), digest_len) < 0) elog(ERROR, "could not finalize %s context: %s", typestr, pg_cryptohash_error(ctx)); pg_cryptohash_free(ctx); SET_VARSIZE(result, digest_len + VARHDRSZ); return result; } /* * SHA-2 variants */ Datum sha224_bytea(PG_FUNCTION_ARGS) { bytea *result = cryptohash_internal(PG_SHA224, PG_GETARG_BYTEA_PP(0)); PG_RETURN_BYTEA_P(result); } Datum sha256_bytea(PG_FUNCTION_ARGS) { bytea *result = cryptohash_internal(PG_SHA256, PG_GETARG_BYTEA_PP(0)); PG_RETURN_BYTEA_P(result); } Datum sha384_bytea(PG_FUNCTION_ARGS) { bytea *result = cryptohash_internal(PG_SHA384, PG_GETARG_BYTEA_PP(0)); PG_RETURN_BYTEA_P(result); } Datum sha512_bytea(PG_FUNCTION_ARGS) { bytea *result = cryptohash_internal(PG_SHA512, PG_GETARG_BYTEA_PP(0)); PG_RETURN_BYTEA_P(result); }