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