Skip to content

Commit 10cfce3

Browse files
committed
Add user-callable SHA-2 functions
Add the user-callable functions sha224, sha256, sha384, sha512. We already had these in the C code to support SCRAM, but there was no test coverage outside of the SCRAM tests. Adding these as user-callable functions allows writing some tests. Also, we have a user-callable md5 function but no more modern alternative, which led to wide use of md5 as a general-purpose hash function, which leads to occasional complaints about using md5. Also mark the existing md5 functions as leak-proof. Reviewed-by: Michael Paquier <michael@paquier.xyz>
1 parent edd4473 commit 10cfce3

File tree

8 files changed

+328
-52
lines changed

8 files changed

+328
-52
lines changed

doc/src/sgml/func.sgml

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3640,7 +3640,7 @@ SELECT format('Testing %3$s, %2$s, %s', 'one', 'two', 'three');
36403640
returning the result in hexadecimal
36413641
</entry>
36423642
<entry><literal>md5(E'Th\\000omas'::bytea)</literal></entry>
3643-
<entry><literal>8ab2d3c9689aaf18 b4958c334c82d8b1</literal></entry>
3643+
<entry><literal>8ab2d3c9689aaf18&#x200B;b4958c334c82d8b1</literal></entry>
36443644
</row>
36453645

36463646
<row>
@@ -3674,6 +3674,66 @@ SELECT format('Testing %3$s, %2$s, %s', 'one', 'two', 'three');
36743674
<entry><literal>set_byte(E'Th\\000omas'::bytea, 4, 64)</literal></entry>
36753675
<entry><literal>Th\000o@as</literal></entry>
36763676
</row>
3677+
3678+
<row>
3679+
<entry>
3680+
<indexterm>
3681+
<primary>sha224</primary>
3682+
</indexterm>
3683+
<literal><function>sha224(<type>bytea</type>)</function></literal>
3684+
</entry>
3685+
<entry><type>bytea</type></entry>
3686+
<entry>
3687+
SHA-224 hash
3688+
</entry>
3689+
<entry><literal>sha224('abc')</literal></entry>
3690+
<entry><literal>\x23097d223405d8228642a477bda2&#x200B;55b32aadbce4bda0b3f7e36c9da7</literal></entry>
3691+
</row>
3692+
3693+
<row>
3694+
<entry>
3695+
<indexterm>
3696+
<primary>sha256</primary>
3697+
</indexterm>
3698+
<literal><function>sha256(<type>bytea</type>)</function></literal>
3699+
</entry>
3700+
<entry><type>bytea</type></entry>
3701+
<entry>
3702+
SHA-256 hash
3703+
</entry>
3704+
<entry><literal>sha256('abc')</literal></entry>
3705+
<entry><literal>\xba7816bf8f01cfea414140de5dae2223&#x200B;b00361a396177a9cb410ff61f20015ad</literal></entry>
3706+
</row>
3707+
3708+
<row>
3709+
<entry>
3710+
<indexterm>
3711+
<primary>sha384</primary>
3712+
</indexterm>
3713+
<literal><function>sha384(<type>bytea</type>)</function></literal>
3714+
</entry>
3715+
<entry><type>bytea</type></entry>
3716+
<entry>
3717+
SHA-384 hash
3718+
</entry>
3719+
<entry><literal>sha384('abc')</literal></entry>
3720+
<entry><literal>\xcb00753f45a35e8bb5a03d699ac65007&#x200B;272c32ab0eded1631a8b605a43ff5bed&#x200B;8086072ba1e7cc2358baeca134c825a7</literal></entry>
3721+
</row>
3722+
3723+
<row>
3724+
<entry>
3725+
<indexterm>
3726+
<primary>sha512</primary>
3727+
</indexterm>
3728+
<literal><function>sha512(<type>bytea</type>)</function></literal>
3729+
</entry>
3730+
<entry><type>bytea</type></entry>
3731+
<entry>
3732+
SHA-512 hash
3733+
</entry>
3734+
<entry><literal>sha512('abc')</literal></entry>
3735+
<entry><literal>\xddaf35a193617abacc417349ae204131&#x200B;12e6fa4e89a97ea20a9eeee64b55d39a&#x200B;2192992a274fc1a836ba3c23a3feebbd&#x200B;454d4423643ce80e2a9ac94fa54ca49f</literal></entry>
3736+
</row>
36773737
</tbody>
36783738
</tgroup>
36793739
</table>
@@ -3686,6 +3746,15 @@ SELECT format('Testing %3$s, %2$s, %s', 'one', 'two', 'three');
36863746
the first byte, and bit 15 is the most significant bit of the second byte.
36873747
</para>
36883748

3749+
<para>
3750+
Note that for historic reasons, the function <function>md5</function>
3751+
returns a hex-encoded value of type <type>text</type> whereas the SHA-2
3752+
functions return type <type>bytea</type>. Use the functions
3753+
<function>encode</function> and <function>decode</function> to convert
3754+
between the two, for example <literal>encode(sha256('abc'),
3755+
'hex')</literal> to get a hex-encoded text representation.
3756+
</para>
3757+
36893758
<para>
36903759
See also the aggregate function <function>string_agg</function> in
36913760
<xref linkend="functions-aggregate"/> and the large object functions

src/backend/utils/adt/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ include $(top_builddir)/src/Makefile.global
1111
# keep this list arranged alphabetically or it gets to be a mess
1212
OBJS = acl.o amutils.o arrayfuncs.o array_expanded.o array_selfuncs.o \
1313
array_typanalyze.o array_userfuncs.o arrayutils.o ascii.o \
14-
bool.o cash.o char.o date.o datetime.o datum.o dbsize.o domains.o \
14+
bool.o cash.o char.o cryptohashes.o \
15+
date.o datetime.o datum.o dbsize.o domains.o \
1516
encode.o enum.o expandeddatum.o expandedrecord.o \
1617
float.o format_type.o formatting.o genfile.o \
1718
geo_ops.o geo_selfuncs.o geo_spgist.o inet_cidr_ntop.o inet_net_pton.o \

src/backend/utils/adt/cryptohashes.c

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
/*-------------------------------------------------------------------------
2+
*
3+
* cryptohashes.c
4+
* Cryptographic hash functions
5+
*
6+
* Portions Copyright (c) 2018, PostgreSQL Global Development Group
7+
*
8+
*
9+
* IDENTIFICATION
10+
* src/backend/utils/adt/cryptohashes.c
11+
*
12+
*-------------------------------------------------------------------------
13+
*/
14+
#include "postgres.h"
15+
16+
#include "common/md5.h"
17+
#include "common/sha2.h"
18+
#include "utils/builtins.h"
19+
20+
21+
/*
22+
* MD5
23+
*/
24+
25+
/* MD5 produces a 16 byte (128 bit) hash; double it for hex */
26+
#define MD5_HASH_LEN 32
27+
28+
/*
29+
* Create an MD5 hash of a text value and return it as hex string.
30+
*/
31+
Datum
32+
md5_text(PG_FUNCTION_ARGS)
33+
{
34+
text *in_text = PG_GETARG_TEXT_PP(0);
35+
size_t len;
36+
char hexsum[MD5_HASH_LEN + 1];
37+
38+
/* Calculate the length of the buffer using varlena metadata */
39+
len = VARSIZE_ANY_EXHDR(in_text);
40+
41+
/* get the hash result */
42+
if (pg_md5_hash(VARDATA_ANY(in_text), len, hexsum) == false)
43+
ereport(ERROR,
44+
(errcode(ERRCODE_OUT_OF_MEMORY),
45+
errmsg("out of memory")));
46+
47+
/* convert to text and return it */
48+
PG_RETURN_TEXT_P(cstring_to_text(hexsum));
49+
}
50+
51+
/*
52+
* Create an MD5 hash of a bytea value and return it as a hex string.
53+
*/
54+
Datum
55+
md5_bytea(PG_FUNCTION_ARGS)
56+
{
57+
bytea *in = PG_GETARG_BYTEA_PP(0);
58+
size_t len;
59+
char hexsum[MD5_HASH_LEN + 1];
60+
61+
len = VARSIZE_ANY_EXHDR(in);
62+
if (pg_md5_hash(VARDATA_ANY(in), len, hexsum) == false)
63+
ereport(ERROR,
64+
(errcode(ERRCODE_OUT_OF_MEMORY),
65+
errmsg("out of memory")));
66+
67+
PG_RETURN_TEXT_P(cstring_to_text(hexsum));
68+
}
69+
70+
71+
/*
72+
* SHA-2 variants
73+
*/
74+
75+
Datum
76+
sha224_bytea(PG_FUNCTION_ARGS)
77+
{
78+
bytea *in = PG_GETARG_BYTEA_PP(0);
79+
const uint8 *data;
80+
size_t len;
81+
pg_sha224_ctx ctx;
82+
unsigned char buf[PG_SHA224_DIGEST_LENGTH];
83+
bytea *result;
84+
85+
len = VARSIZE_ANY_EXHDR(in);
86+
data = (unsigned char *) VARDATA_ANY(in);
87+
88+
pg_sha224_init(&ctx);
89+
pg_sha224_update(&ctx, data, len);
90+
pg_sha224_final(&ctx, buf);
91+
92+
result = palloc(sizeof(buf) + VARHDRSZ);
93+
SET_VARSIZE(result, sizeof(buf) + VARHDRSZ);
94+
memcpy(VARDATA(result), buf, sizeof(buf));
95+
96+
PG_RETURN_BYTEA_P(result);
97+
}
98+
99+
Datum
100+
sha256_bytea(PG_FUNCTION_ARGS)
101+
{
102+
bytea *in = PG_GETARG_BYTEA_PP(0);
103+
const uint8 *data;
104+
size_t len;
105+
pg_sha256_ctx ctx;
106+
unsigned char buf[PG_SHA256_DIGEST_LENGTH];
107+
bytea *result;
108+
109+
len = VARSIZE_ANY_EXHDR(in);
110+
data = (unsigned char *) VARDATA_ANY(in);
111+
112+
pg_sha256_init(&ctx);
113+
pg_sha256_update(&ctx, data, len);
114+
pg_sha256_final(&ctx, buf);
115+
116+
result = palloc(sizeof(buf) + VARHDRSZ);
117+
SET_VARSIZE(result, sizeof(buf) + VARHDRSZ);
118+
memcpy(VARDATA(result), buf, sizeof(buf));
119+
120+
PG_RETURN_BYTEA_P(result);
121+
}
122+
123+
Datum
124+
sha384_bytea(PG_FUNCTION_ARGS)
125+
{
126+
bytea *in = PG_GETARG_BYTEA_PP(0);
127+
const uint8 *data;
128+
size_t len;
129+
pg_sha384_ctx ctx;
130+
unsigned char buf[PG_SHA384_DIGEST_LENGTH];
131+
bytea *result;
132+
133+
len = VARSIZE_ANY_EXHDR(in);
134+
data = (unsigned char *) VARDATA_ANY(in);
135+
136+
pg_sha384_init(&ctx);
137+
pg_sha384_update(&ctx, data, len);
138+
pg_sha384_final(&ctx, buf);
139+
140+
result = palloc(sizeof(buf) + VARHDRSZ);
141+
SET_VARSIZE(result, sizeof(buf) + VARHDRSZ);
142+
memcpy(VARDATA(result), buf, sizeof(buf));
143+
144+
PG_RETURN_BYTEA_P(result);
145+
}
146+
147+
Datum
148+
sha512_bytea(PG_FUNCTION_ARGS)
149+
{
150+
bytea *in = PG_GETARG_BYTEA_PP(0);
151+
const uint8 *data;
152+
size_t len;
153+
pg_sha512_ctx ctx;
154+
unsigned char buf[PG_SHA512_DIGEST_LENGTH];
155+
bytea *result;
156+
157+
len = VARSIZE_ANY_EXHDR(in);
158+
data = (unsigned char *) VARDATA_ANY(in);
159+
160+
pg_sha512_init(&ctx);
161+
pg_sha512_update(&ctx, data, len);
162+
pg_sha512_final(&ctx, buf);
163+
164+
result = palloc(sizeof(buf) + VARHDRSZ);
165+
SET_VARSIZE(result, sizeof(buf) + VARHDRSZ);
166+
memcpy(VARDATA(result), buf, sizeof(buf));
167+
168+
PG_RETURN_BYTEA_P(result);
169+
}

src/backend/utils/adt/varlena.c

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
#include "catalog/pg_collation.h"
2323
#include "catalog/pg_type.h"
2424
#include "common/int.h"
25-
#include "common/md5.h"
2625
#include "lib/hyperloglog.h"
2726
#include "libpq/pqformat.h"
2827
#include "miscadmin.h"
@@ -4564,53 +4563,6 @@ to_hex64(PG_FUNCTION_ARGS)
45644563
PG_RETURN_TEXT_P(cstring_to_text(ptr));
45654564
}
45664565

4567-
/*
4568-
* Create an md5 hash of a text string and return it as hex
4569-
*
4570-
* md5 produces a 16 byte (128 bit) hash; double it for hex
4571-
*/
4572-
#define MD5_HASH_LEN 32
4573-
4574-
Datum
4575-
md5_text(PG_FUNCTION_ARGS)
4576-
{
4577-
text *in_text = PG_GETARG_TEXT_PP(0);
4578-
size_t len;
4579-
char hexsum[MD5_HASH_LEN + 1];
4580-
4581-
/* Calculate the length of the buffer using varlena metadata */
4582-
len = VARSIZE_ANY_EXHDR(in_text);
4583-
4584-
/* get the hash result */
4585-
if (pg_md5_hash(VARDATA_ANY(in_text), len, hexsum) == false)
4586-
ereport(ERROR,
4587-
(errcode(ERRCODE_OUT_OF_MEMORY),
4588-
errmsg("out of memory")));
4589-
4590-
/* convert to text and return it */
4591-
PG_RETURN_TEXT_P(cstring_to_text(hexsum));
4592-
}
4593-
4594-
/*
4595-
* Create an md5 hash of a bytea field and return it as a hex string:
4596-
* 16-byte md5 digest is represented in 32 hex characters.
4597-
*/
4598-
Datum
4599-
md5_bytea(PG_FUNCTION_ARGS)
4600-
{
4601-
bytea *in = PG_GETARG_BYTEA_PP(0);
4602-
size_t len;
4603-
char hexsum[MD5_HASH_LEN + 1];
4604-
4605-
len = VARSIZE_ANY_EXHDR(in);
4606-
if (pg_md5_hash(VARDATA_ANY(in), len, hexsum) == false)
4607-
ereport(ERROR,
4608-
(errcode(ERRCODE_OUT_OF_MEMORY),
4609-
errmsg("out of memory")));
4610-
4611-
PG_RETURN_TEXT_P(cstring_to_text(hexsum));
4612-
}
4613-
46144566
/*
46154567
* Return the size of a datum, possibly compressed
46164568
*

src/include/catalog/pg_proc.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3917,10 +3917,18 @@ DATA(insert OID = 3314 ( system PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 33
39173917
DESCR("SYSTEM tablesample method handler");
39183918

39193919
/* cryptographic */
3920-
DATA(insert OID = 2311 ( md5 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 25 "25" _null_ _null_ _null_ _null_ _null_ md5_text _null_ _null_ _null_ ));
3920+
DATA(insert OID = 2311 ( md5 PGNSP PGUID 12 1 0 0 0 f f f t t f i s 1 0 25 "25" _null_ _null_ _null_ _null_ _null_ md5_text _null_ _null_ _null_ ));
39213921
DESCR("MD5 hash");
3922-
DATA(insert OID = 2321 ( md5 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 25 "17" _null_ _null_ _null_ _null_ _null_ md5_bytea _null_ _null_ _null_ ));
3922+
DATA(insert OID = 2321 ( md5 PGNSP PGUID 12 1 0 0 0 f f f t t f i s 1 0 25 "17" _null_ _null_ _null_ _null_ _null_ md5_bytea _null_ _null_ _null_ ));
39233923
DESCR("MD5 hash");
3924+
DATA(insert OID = 3419 ( sha224 PGNSP PGUID 12 1 0 0 0 f f f t t f i s 1 0 17 "17" _null_ _null_ _null_ _null_ _null_ sha224_bytea _null_ _null_ _null_ ));
3925+
DESCR("SHA-224 hash");
3926+
DATA(insert OID = 3420 ( sha256 PGNSP PGUID 12 1 0 0 0 f f f t t f i s 1 0 17 "17" _null_ _null_ _null_ _null_ _null_ sha256_bytea _null_ _null_ _null_ ));
3927+
DESCR("SHA-256 hash");
3928+
DATA(insert OID = 3421 ( sha384 PGNSP PGUID 12 1 0 0 0 f f f t t f i s 1 0 17 "17" _null_ _null_ _null_ _null_ _null_ sha384_bytea _null_ _null_ _null_ ));
3929+
DESCR("SHA-384 hash");
3930+
DATA(insert OID = 3422 ( sha512 PGNSP PGUID 12 1 0 0 0 f f f t t f i s 1 0 17 "17" _null_ _null_ _null_ _null_ _null_ sha512_bytea _null_ _null_ _null_ ));
3931+
DESCR("SHA-512 hash");
39243932

39253933
/* crosstype operations for date vs. timestamp and timestamptz */
39263934
DATA(insert OID = 2338 ( date_lt_timestamp PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 16 "1082 1114" _null_ _null_ _null_ _null_ _null_ date_lt_timestamp _null_ _null_ _null_ ));

src/test/regress/expected/opr_sanity.out

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,8 @@ timestamp_lt(timestamp without time zone,timestamp without time zone)
699699
timestamp_le(timestamp without time zone,timestamp without time zone)
700700
timestamp_ge(timestamp without time zone,timestamp without time zone)
701701
timestamp_gt(timestamp without time zone,timestamp without time zone)
702+
md5(text)
703+
md5(bytea)
702704
tidgt(tid,tid)
703705
tidlt(tid,tid)
704706
tidge(tid,tid)
@@ -711,6 +713,10 @@ uuid_gt(uuid,uuid)
711713
uuid_ne(uuid,uuid)
712714
xidneq(xid,xid)
713715
xidneqint4(xid,integer)
716+
sha224(bytea)
717+
sha256(bytea)
718+
sha384(bytea)
719+
sha512(bytea)
714720
macaddr8_eq(macaddr8,macaddr8)
715721
macaddr8_lt(macaddr8,macaddr8)
716722
macaddr8_le(macaddr8,macaddr8)

0 commit comments

Comments
 (0)