Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * cryptohashfuncs.c
4 : * Cryptographic hash functions
5 : *
6 : * Portions Copyright (c) 2018-2023, PostgreSQL Global Development Group
7 : *
8 : *
9 : * IDENTIFICATION
10 : * src/backend/utils/adt/cryptohashfuncs.c
11 : *
12 : *-------------------------------------------------------------------------
13 : */
14 : #include "postgres.h"
15 :
16 : #include "common/cryptohash.h"
17 : #include "common/md5.h"
18 : #include "common/sha2.h"
19 : #include "utils/builtins.h"
20 : #include "varatt.h"
21 :
22 :
23 : /*
24 : * MD5
25 : */
26 :
27 : /* MD5 produces a 16 byte (128 bit) hash; double it for hex */
28 : #define MD5_HASH_LEN 32
29 :
30 : /*
31 : * Create an MD5 hash of a text value and return it as hex string.
32 : */
33 : Datum
1888 peter_e 34 GIC 395929 : md5_text(PG_FUNCTION_ARGS)
1888 peter_e 35 ECB : {
1888 peter_e 36 GIC 395929 : text *in_text = PG_GETARG_TEXT_PP(0);
1888 peter_e 37 ECB : size_t len;
38 : char hexsum[MD5_HASH_LEN + 1];
453 michael 39 GIC 395929 : const char *errstr = NULL;
1888 peter_e 40 ECB :
41 : /* Calculate the length of the buffer using varlena metadata */
1888 peter_e 42 GIC 395929 : len = VARSIZE_ANY_EXHDR(in_text);
1888 peter_e 43 ECB :
44 : /* get the hash result */
453 michael 45 GIC 395929 : if (pg_md5_hash(VARDATA_ANY(in_text), len, hexsum, &errstr) == false)
1888 peter_e 46 LBC 0 : ereport(ERROR,
453 michael 47 EUB : (errcode(ERRCODE_INTERNAL_ERROR),
48 : errmsg("could not compute %s hash: %s", "MD5",
49 : errstr)));
50 :
51 : /* convert to text and return it */
1888 peter_e 52 GIC 395929 : PG_RETURN_TEXT_P(cstring_to_text(hexsum));
1888 peter_e 53 ECB : }
54 :
55 : /*
56 : * Create an MD5 hash of a bytea value and return it as a hex string.
57 : */
58 : Datum
1888 peter_e 59 GIC 21 : md5_bytea(PG_FUNCTION_ARGS)
1888 peter_e 60 ECB : {
1888 peter_e 61 GIC 21 : bytea *in = PG_GETARG_BYTEA_PP(0);
1888 peter_e 62 ECB : size_t len;
63 : char hexsum[MD5_HASH_LEN + 1];
453 michael 64 GIC 21 : const char *errstr = NULL;
1888 peter_e 65 ECB :
1888 peter_e 66 GIC 21 : len = VARSIZE_ANY_EXHDR(in);
453 michael 67 CBC 21 : if (pg_md5_hash(VARDATA_ANY(in), len, hexsum, &errstr) == false)
1888 peter_e 68 LBC 0 : ereport(ERROR,
453 michael 69 EUB : (errcode(ERRCODE_INTERNAL_ERROR),
70 : errmsg("could not compute %s hash: %s", "MD5",
71 : errstr)));
72 :
1888 peter_e 73 GIC 21 : PG_RETURN_TEXT_P(cstring_to_text(hexsum));
1888 peter_e 74 ECB : }
75 :
76 : /*
77 : * Internal routine to compute a cryptohash with the given bytea input.
78 : */
79 : static inline bytea *
801 michael 80 GIC 99195 : cryptohash_internal(pg_cryptohash_type type, bytea *input)
1888 peter_e 81 ECB : {
82 : const uint8 *data;
801 michael 83 GIC 99195 : const char *typestr = NULL;
801 michael 84 CBC 99195 : int digest_len = 0;
1888 peter_e 85 ECB : size_t len;
86 : pg_cryptohash_ctx *ctx;
87 : bytea *result;
88 :
801 michael 89 GIC 99195 : switch (type)
801 michael 90 ECB : {
801 michael 91 GIC 6 : case PG_SHA224:
801 michael 92 CBC 6 : typestr = "SHA224";
93 6 : digest_len = PG_SHA224_DIGEST_LENGTH;
94 6 : break;
95 99177 : case PG_SHA256:
96 99177 : typestr = "SHA256";
97 99177 : digest_len = PG_SHA256_DIGEST_LENGTH;
98 99177 : break;
99 6 : case PG_SHA384:
100 6 : typestr = "SHA384";
101 6 : digest_len = PG_SHA384_DIGEST_LENGTH;
102 6 : break;
103 6 : case PG_SHA512:
104 6 : typestr = "SHA512";
105 6 : digest_len = PG_SHA512_DIGEST_LENGTH;
106 6 : break;
801 michael 107 LBC 0 : case PG_MD5:
801 michael 108 EUB : case PG_SHA1:
801 michael 109 UIC 0 : elog(ERROR, "unsupported cryptohash type %d", type);
801 michael 110 EUB : break;
111 : }
112 :
801 michael 113 GIC 99195 : result = palloc0(digest_len + VARHDRSZ);
801 michael 114 CBC 99195 : len = VARSIZE_ANY_EXHDR(input);
115 99195 : data = (unsigned char *) VARDATA_ANY(input);
801 michael 116 ECB :
801 michael 117 GIC 99195 : ctx = pg_cryptohash_create(type);
858 michael 118 CBC 99195 : if (pg_cryptohash_init(ctx) < 0)
453 michael 119 LBC 0 : elog(ERROR, "could not initialize %s context: %s", typestr,
453 michael 120 EUB : pg_cryptohash_error(ctx));
858 michael 121 GIC 99195 : if (pg_cryptohash_update(ctx, data, len) < 0)
453 michael 122 LBC 0 : elog(ERROR, "could not update %s context: %s", typestr,
453 michael 123 EUB : pg_cryptohash_error(ctx));
783 michael 124 GIC 99195 : if (pg_cryptohash_final(ctx, (unsigned char *) VARDATA(result),
783 michael 125 ECB : digest_len) < 0)
453 michael 126 UIC 0 : elog(ERROR, "could not finalize %s context: %s", typestr,
453 michael 127 EUB : pg_cryptohash_error(ctx));
858 michael 128 GIC 99195 : pg_cryptohash_free(ctx);
1888 peter_e 129 ECB :
801 michael 130 GIC 99195 : SET_VARSIZE(result, digest_len + VARHDRSZ);
1888 peter_e 131 ECB :
801 michael 132 GIC 99195 : return result;
1888 peter_e 133 ECB : }
134 :
135 : /*
136 : * SHA-2 variants
137 : */
138 :
139 : Datum
801 michael 140 GIC 6 : sha224_bytea(PG_FUNCTION_ARGS)
1888 peter_e 141 ECB : {
801 michael 142 GIC 6 : bytea *result = cryptohash_internal(PG_SHA224, PG_GETARG_BYTEA_PP(0));
1888 peter_e 143 ECB :
801 michael 144 GIC 6 : PG_RETURN_BYTEA_P(result);
801 michael 145 ECB : }
146 :
147 : Datum
801 michael 148 GIC 99177 : sha256_bytea(PG_FUNCTION_ARGS)
801 michael 149 ECB : {
801 michael 150 GIC 99177 : bytea *result = cryptohash_internal(PG_SHA256, PG_GETARG_BYTEA_PP(0));
1888 peter_e 151 ECB :
1888 peter_e 152 GIC 99177 : PG_RETURN_BYTEA_P(result);
1888 peter_e 153 ECB : }
154 :
155 : Datum
1888 peter_e 156 GIC 6 : sha384_bytea(PG_FUNCTION_ARGS)
1888 peter_e 157 ECB : {
801 michael 158 GIC 6 : bytea *result = cryptohash_internal(PG_SHA384, PG_GETARG_BYTEA_PP(0));
1888 peter_e 159 ECB :
1888 peter_e 160 GIC 6 : PG_RETURN_BYTEA_P(result);
1888 peter_e 161 ECB : }
162 :
163 : Datum
1888 peter_e 164 GIC 6 : sha512_bytea(PG_FUNCTION_ARGS)
1888 peter_e 165 ECB : {
801 michael 166 GIC 6 : bytea *result = cryptohash_internal(PG_SHA512, PG_GETARG_BYTEA_PP(0));
1888 peter_e 167 ECB :
1888 peter_e 168 GIC 6 : PG_RETURN_BYTEA_P(result);
1888 peter_e 169 ECB : }
|