Hi all,

SHA-1 is now an option available for cryptohashes, and like the
existing set of functions of SHA-2, I don't really see a reason why we
should not have a SQL function for SHA1.  Attached is a patch doing
that.

The same code pattern was repeated 4 times on HEAD for the SHA-2
functions for the bytea -> bytea hashing, so I have refactored the
whole thing while integrating the new function, shaving some code from
cryptohashfuncs.c.

Thoughts?
--
Michael
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index b5f52d4e4a..e6f22a5873 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -7317,6 +7317,9 @@
 { oid => '2321', descr => 'MD5 hash',
   proname => 'md5', proleakproof => 't', prorettype => 'text',
   proargtypes => 'bytea', prosrc => 'md5_bytea' },
+{ oid => '8935', descr => 'SHA-1 hash',
+  proname => 'sha1', proleakproof => 't', prorettype => 'bytea',
+  proargtypes => 'bytea', prosrc => 'sha1_bytea' },
 { oid => '3419', descr => 'SHA-224 hash',
   proname => 'sha224', proleakproof => 't', prorettype => 'bytea',
   proargtypes => 'bytea', prosrc => 'sha224_bytea' },
diff --git a/src/backend/utils/adt/cryptohashfuncs.c b/src/backend/utils/adt/cryptohashfuncs.c
index d99485f4c6..5bdc2da531 100644
--- a/src/backend/utils/adt/cryptohashfuncs.c
+++ b/src/backend/utils/adt/cryptohashfuncs.c
@@ -15,6 +15,7 @@
 
 #include "common/cryptohash.h"
 #include "common/md5.h"
+#include "common/sha1.h"
 #include "common/sha2.h"
 #include "utils/builtins.h"
 
@@ -68,6 +69,74 @@ md5_bytea(PG_FUNCTION_ARGS)
 	PG_RETURN_TEXT_P(cstring_to_text(hexsum));
 }
 
+/*
+ * Internal routine to compute a cryptohash with the given bytea input.
+ */
+static inline bytea *
+cryptohash_internal(bytea *input, int digest_len,
+					pg_cryptohash_type type)
+{
+	const uint8 *data;
+	const char  *typestr;
+	size_t		len;
+	pg_cryptohash_ctx *ctx;
+	unsigned char *buf;
+	bytea	   *result;
+
+	switch (type)
+	{
+		case PG_MD5:
+			typestr = "MD5";
+			break;
+		case PG_SHA1:
+			typestr = "SHA1";
+			break;
+		case PG_SHA224:
+			typestr = "SHA224";
+			break;
+		case PG_SHA256:
+			typestr = "SHA256";
+			break;
+		case PG_SHA384:
+			typestr = "SHA384";
+			break;
+		case PG_SHA512:
+			typestr = "SHA512";
+			break;
+	}
+
+	buf = palloc0(digest_len);
+	len = VARSIZE_ANY_EXHDR(input);
+	data = (unsigned char *) VARDATA_ANY(input);
+
+	ctx = pg_cryptohash_create(type);
+	if (pg_cryptohash_init(ctx) < 0)
+		elog(ERROR, "could not initialize %s context", typestr);
+	if (pg_cryptohash_update(ctx, data, len) < 0)
+		elog(ERROR, "could not update %s context", typestr);
+	if (pg_cryptohash_final(ctx, buf) < 0)
+		elog(ERROR, "could not finalize %s context", typestr);
+	pg_cryptohash_free(ctx);
+
+	result = palloc(digest_len + VARHDRSZ);
+	SET_VARSIZE(result, digest_len + VARHDRSZ);
+	memcpy(VARDATA(result), buf, digest_len);
+
+	return result;
+}
+
+/*
+ * SHA-1
+ */
+Datum
+sha1_bytea(PG_FUNCTION_ARGS)
+{
+	bytea   *result = cryptohash_internal(PG_GETARG_BYTEA_PP(0),
+										  SHA1_DIGEST_LENGTH,
+										  PG_SHA1);
+	PG_RETURN_BYTEA_P(result);
+}
+
 
 /*
  * SHA-2 variants
@@ -76,115 +145,35 @@ md5_bytea(PG_FUNCTION_ARGS)
 Datum
 sha224_bytea(PG_FUNCTION_ARGS)
 {
-	bytea	   *in = PG_GETARG_BYTEA_PP(0);
-	const uint8 *data;
-	size_t		len;
-	pg_cryptohash_ctx *ctx;
-	unsigned char buf[PG_SHA224_DIGEST_LENGTH];
-	bytea	   *result;
-
-	len = VARSIZE_ANY_EXHDR(in);
-	data = (unsigned char *) VARDATA_ANY(in);
-
-	ctx = pg_cryptohash_create(PG_SHA224);
-	if (pg_cryptohash_init(ctx) < 0)
-		elog(ERROR, "could not initialize %s context", "SHA224");
-	if (pg_cryptohash_update(ctx, data, len) < 0)
-		elog(ERROR, "could not update %s context", "SHA224");
-	if (pg_cryptohash_final(ctx, buf) < 0)
-		elog(ERROR, "could not finalize %s context", "SHA224");
-	pg_cryptohash_free(ctx);
-
-	result = palloc(sizeof(buf) + VARHDRSZ);
-	SET_VARSIZE(result, sizeof(buf) + VARHDRSZ);
-	memcpy(VARDATA(result), buf, sizeof(buf));
-
+	bytea   *result = cryptohash_internal(PG_GETARG_BYTEA_PP(0),
+										  PG_SHA224_DIGEST_LENGTH,
+										  PG_SHA224);
 	PG_RETURN_BYTEA_P(result);
 }
 
 Datum
 sha256_bytea(PG_FUNCTION_ARGS)
 {
-	bytea	   *in = PG_GETARG_BYTEA_PP(0);
-	const uint8 *data;
-	size_t		len;
-	pg_cryptohash_ctx *ctx;
-	unsigned char buf[PG_SHA256_DIGEST_LENGTH];
-	bytea	   *result;
-
-	len = VARSIZE_ANY_EXHDR(in);
-	data = (unsigned char *) VARDATA_ANY(in);
-
-	ctx = pg_cryptohash_create(PG_SHA256);
-	if (pg_cryptohash_init(ctx) < 0)
-		elog(ERROR, "could not initialize %s context", "SHA256");
-	if (pg_cryptohash_update(ctx, data, len) < 0)
-		elog(ERROR, "could not update %s context", "SHA256");
-	if (pg_cryptohash_final(ctx, buf) < 0)
-		elog(ERROR, "could not finalize %s context", "SHA256");
-	pg_cryptohash_free(ctx);
-
-	result = palloc(sizeof(buf) + VARHDRSZ);
-	SET_VARSIZE(result, sizeof(buf) + VARHDRSZ);
-	memcpy(VARDATA(result), buf, sizeof(buf));
-
+	bytea   *result = cryptohash_internal(PG_GETARG_BYTEA_PP(0),
+										  PG_SHA256_DIGEST_LENGTH,
+										  PG_SHA256);
 	PG_RETURN_BYTEA_P(result);
 }
 
 Datum
 sha384_bytea(PG_FUNCTION_ARGS)
 {
-	bytea	   *in = PG_GETARG_BYTEA_PP(0);
-	const uint8 *data;
-	size_t		len;
-	pg_cryptohash_ctx *ctx;
-	unsigned char buf[PG_SHA384_DIGEST_LENGTH];
-	bytea	   *result;
-
-	len = VARSIZE_ANY_EXHDR(in);
-	data = (unsigned char *) VARDATA_ANY(in);
-
-	ctx = pg_cryptohash_create(PG_SHA384);
-	if (pg_cryptohash_init(ctx) < 0)
-		elog(ERROR, "could not initialize %s context", "SHA384");
-	if (pg_cryptohash_update(ctx, data, len) < 0)
-		elog(ERROR, "could not update %s context", "SHA384");
-	if (pg_cryptohash_final(ctx, buf) < 0)
-		elog(ERROR, "could not finalize %s context", "SHA384");
-	pg_cryptohash_free(ctx);
-
-	result = palloc(sizeof(buf) + VARHDRSZ);
-	SET_VARSIZE(result, sizeof(buf) + VARHDRSZ);
-	memcpy(VARDATA(result), buf, sizeof(buf));
-
+	bytea   *result = cryptohash_internal(PG_GETARG_BYTEA_PP(0),
+										  PG_SHA384_DIGEST_LENGTH,
+										  PG_SHA384);
 	PG_RETURN_BYTEA_P(result);
 }
 
 Datum
 sha512_bytea(PG_FUNCTION_ARGS)
 {
-	bytea	   *in = PG_GETARG_BYTEA_PP(0);
-	const uint8 *data;
-	size_t		len;
-	pg_cryptohash_ctx *ctx;
-	unsigned char buf[PG_SHA512_DIGEST_LENGTH];
-	bytea	   *result;
-
-	len = VARSIZE_ANY_EXHDR(in);
-	data = (unsigned char *) VARDATA_ANY(in);
-
-	ctx = pg_cryptohash_create(PG_SHA512);
-	if (pg_cryptohash_init(ctx) < 0)
-		elog(ERROR, "could not initialize %s context", "SHA512");
-	if (pg_cryptohash_update(ctx, data, len) < 0)
-		elog(ERROR, "could not update %s context", "SHA512");
-	if (pg_cryptohash_final(ctx, buf) < 0)
-		elog(ERROR, "could not finalize %s context", "SHA512");
-	pg_cryptohash_free(ctx);
-
-	result = palloc(sizeof(buf) + VARHDRSZ);
-	SET_VARSIZE(result, sizeof(buf) + VARHDRSZ);
-	memcpy(VARDATA(result), buf, sizeof(buf));
-
+	bytea   *result = cryptohash_internal(PG_GETARG_BYTEA_PP(0),
+										  PG_SHA512_DIGEST_LENGTH,
+										  PG_SHA512);
 	PG_RETURN_BYTEA_P(result);
 }
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 254ca06d3d..4660313fcb 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -888,6 +888,7 @@ xid8ge(xid8,xid8)
 xid8eq(xid8,xid8)
 xid8ne(xid8,xid8)
 xid8cmp(xid8,xid8)
+sha1(bytea)
 -- restore normal output mode
 \a\t
 -- List of functions used by libpq's fe-lobj.c
diff --git a/src/test/regress/expected/strings.out b/src/test/regress/expected/strings.out
index 7c91afa6e4..070b41dccd 100644
--- a/src/test/regress/expected/strings.out
+++ b/src/test/regress/expected/strings.out
@@ -1769,9 +1769,21 @@ select md5('12345678901234567890123456789012345678901234567890123456789012345678
 (1 row)
 
 --
--- SHA-2
+-- SHA-1 and SHA-2
 --
 SET bytea_output TO hex;
+SELECT sha1('');
+                    sha1                    
+--------------------------------------------
+ \xda39a3ee5e6b4b0d3255bfef95601890afd80709
+(1 row)
+
+SELECT sha1('The quick brown fox jumps over the lazy dog.');
+                    sha1                    
+--------------------------------------------
+ \x408d94384216f890ff7a0c3528e8bed1e0b01621
+(1 row)
+
 SELECT sha224('');
                            sha224                           
 ------------------------------------------------------------
diff --git a/src/test/regress/sql/strings.sql b/src/test/regress/sql/strings.sql
index ef4bfb008a..2e5f16a267 100644
--- a/src/test/regress/sql/strings.sql
+++ b/src/test/regress/sql/strings.sql
@@ -612,10 +612,13 @@ select md5('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'::byt
 select md5('12345678901234567890123456789012345678901234567890123456789012345678901234567890'::bytea) = '57edf4a22be3c955ac49da2e2107b67a' AS "TRUE";
 
 --
--- SHA-2
+-- SHA-1 and SHA-2
 --
 SET bytea_output TO hex;
 
+SELECT sha1('');
+SELECT sha1('The quick brown fox jumps over the lazy dog.');
+
 SELECT sha224('');
 SELECT sha224('The quick brown fox jumps over the lazy dog.');
 
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index aa99665e2e..d9dff6d836 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -4208,6 +4208,24 @@ SELECT format('Testing %3$s, %2$s, %s', 'one', 'two', 'three');
        </para></entry>
       </row>
 
+      <row>
+       <entry role="func_table_entry"><para role="func_signature">
+        <indexterm>
+         <primary>sha1</primary>
+        </indexterm>
+        <function>sha1</function> ( <type>bytea</type> )
+        <returnvalue>bytea</returnvalue>
+       </para>
+       <para>
+        Computes the SHA-1 <link linkend="functions-hash-note">hash</link>
+        of the binary string.
+       </para>
+       <para>
+        <literal>sha1('abc'::bytea)</literal>
+        <returnvalue>\xa9993e364706816aba3e25717850&zwsp;c26c9cd0d89d</returnvalue>
+       </para></entry>
+      </row>
+
       <row>
        <entry role="func_table_entry"><para role="func_signature">
         <indexterm>

Attachment: signature.asc
Description: PGP signature

Reply via email to