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