Branch data Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * cryptohashfuncs.c
4 : : * Cryptographic hash functions
5 : : *
6 : : * Portions Copyright (c) 2018-2026, 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
34 : 7 : md5_text(PG_FUNCTION_ARGS)
35 : : {
36 : 7 : text *in_text = PG_GETARG_TEXT_PP(0);
37 : 7 : size_t len;
38 : 7 : char hexsum[MD5_HASH_LEN + 1];
39 : 7 : const char *errstr = NULL;
40 : :
41 : : /* Calculate the length of the buffer using varlena metadata */
42 : 7 : len = VARSIZE_ANY_EXHDR(in_text);
43 : :
44 : : /* get the hash result */
45 [ + - ]: 7 : if (pg_md5_hash(VARDATA_ANY(in_text), len, hexsum, &errstr) == false)
46 [ # # # # ]: 0 : ereport(ERROR,
47 : : (errcode(ERRCODE_INTERNAL_ERROR),
48 : : errmsg("could not compute %s hash: %s", "MD5",
49 : : errstr)));
50 : :
51 : : /* convert to text and return it */
52 : 14 : PG_RETURN_TEXT_P(cstring_to_text(hexsum));
53 : 7 : }
54 : :
55 : : /*
56 : : * Create an MD5 hash of a bytea value and return it as a hex string.
57 : : */
58 : : Datum
59 : 7 : md5_bytea(PG_FUNCTION_ARGS)
60 : : {
61 : 7 : bytea *in = PG_GETARG_BYTEA_PP(0);
62 : 7 : size_t len;
63 : 7 : char hexsum[MD5_HASH_LEN + 1];
64 : 7 : const char *errstr = NULL;
65 : :
66 : 7 : len = VARSIZE_ANY_EXHDR(in);
67 [ + - ]: 7 : if (pg_md5_hash(VARDATA_ANY(in), len, hexsum, &errstr) == false)
68 [ # # # # ]: 0 : ereport(ERROR,
69 : : (errcode(ERRCODE_INTERNAL_ERROR),
70 : : errmsg("could not compute %s hash: %s", "MD5",
71 : : errstr)));
72 : :
73 : 14 : PG_RETURN_TEXT_P(cstring_to_text(hexsum));
74 : 7 : }
75 : :
76 : : /*
77 : : * Internal routine to compute a cryptohash with the given bytea input.
78 : : */
79 : : static inline bytea *
80 : 35065 : cryptohash_internal(pg_cryptohash_type type, bytea *input)
81 : : {
82 : 35065 : const uint8 *data;
83 : 35065 : const char *typestr = NULL;
84 : 35065 : int digest_len = 0;
85 : 35065 : size_t len;
86 : 35065 : pg_cryptohash_ctx *ctx;
87 : 35065 : bytea *result;
88 : :
89 [ - + + + : 35065 : switch (type)
+ - ]
90 : : {
91 : : case PG_SHA224:
92 : 2 : typestr = "SHA224";
93 : 2 : digest_len = PG_SHA224_DIGEST_LENGTH;
94 : 2 : break;
95 : : case PG_SHA256:
96 : 35059 : typestr = "SHA256";
97 : 35059 : digest_len = PG_SHA256_DIGEST_LENGTH;
98 : 35059 : break;
99 : : case PG_SHA384:
100 : 2 : typestr = "SHA384";
101 : 2 : digest_len = PG_SHA384_DIGEST_LENGTH;
102 : 2 : break;
103 : : case PG_SHA512:
104 : 2 : typestr = "SHA512";
105 : 2 : digest_len = PG_SHA512_DIGEST_LENGTH;
106 : 2 : break;
107 : : case PG_MD5:
108 : : case PG_SHA1:
109 [ # # # # ]: 0 : elog(ERROR, "unsupported cryptohash type %d", type);
110 : 0 : break;
111 : : }
112 : :
113 : 35065 : result = palloc0(digest_len + VARHDRSZ);
114 : 35065 : len = VARSIZE_ANY_EXHDR(input);
115 : 35065 : data = (unsigned char *) VARDATA_ANY(input);
116 : :
117 : 35065 : ctx = pg_cryptohash_create(type);
118 [ + - ]: 35065 : if (pg_cryptohash_init(ctx) < 0)
119 [ # # # # ]: 0 : elog(ERROR, "could not initialize %s context: %s", typestr,
120 : : pg_cryptohash_error(ctx));
121 [ + - ]: 35065 : if (pg_cryptohash_update(ctx, data, len) < 0)
122 [ # # # # ]: 0 : elog(ERROR, "could not update %s context: %s", typestr,
123 : : pg_cryptohash_error(ctx));
124 : 70130 : if (pg_cryptohash_final(ctx, (unsigned char *) VARDATA(result),
125 [ + - + - ]: 70130 : digest_len) < 0)
126 [ # # # # ]: 0 : elog(ERROR, "could not finalize %s context: %s", typestr,
127 : : pg_cryptohash_error(ctx));
128 : 35065 : pg_cryptohash_free(ctx);
129 : :
130 : 35065 : SET_VARSIZE(result, digest_len + VARHDRSZ);
131 : :
132 : 70130 : return result;
133 : 35065 : }
134 : :
135 : : /*
136 : : * SHA-2 variants
137 : : */
138 : :
139 : : Datum
140 : 2 : sha224_bytea(PG_FUNCTION_ARGS)
141 : : {
142 : 2 : bytea *result = cryptohash_internal(PG_SHA224, PG_GETARG_BYTEA_PP(0));
143 : :
144 : 4 : PG_RETURN_BYTEA_P(result);
145 : 2 : }
146 : :
147 : : Datum
148 : 35059 : sha256_bytea(PG_FUNCTION_ARGS)
149 : : {
150 : 35059 : bytea *result = cryptohash_internal(PG_SHA256, PG_GETARG_BYTEA_PP(0));
151 : :
152 : 70118 : PG_RETURN_BYTEA_P(result);
153 : 35059 : }
154 : :
155 : : Datum
156 : 2 : sha384_bytea(PG_FUNCTION_ARGS)
157 : : {
158 : 2 : bytea *result = cryptohash_internal(PG_SHA384, PG_GETARG_BYTEA_PP(0));
159 : :
160 : 4 : PG_RETURN_BYTEA_P(result);
161 : 2 : }
162 : :
163 : : Datum
164 : 2 : sha512_bytea(PG_FUNCTION_ARGS)
165 : : {
166 : 2 : bytea *result = cryptohash_internal(PG_SHA512, PG_GETARG_BYTEA_PP(0));
167 : :
168 : 4 : PG_RETURN_BYTEA_P(result);
169 : 2 : }
|