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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy