summaryrefslogtreecommitdiffstats
path: root/src/common/checksum_helper.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:17:33 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:17:33 +0000
commit5e45211a64149b3c659b90ff2de6fa982a5a93ed (patch)
tree739caf8c461053357daa9f162bef34516c7bf452 /src/common/checksum_helper.c
parentInitial commit. (diff)
downloadpostgresql-15-5e45211a64149b3c659b90ff2de6fa982a5a93ed.tar.xz
postgresql-15-5e45211a64149b3c659b90ff2de6fa982a5a93ed.zip
Adding upstream version 15.5.upstream/15.5
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/common/checksum_helper.c')
-rw-r--r--src/common/checksum_helper.c232
1 files changed, 232 insertions, 0 deletions
diff --git a/src/common/checksum_helper.c b/src/common/checksum_helper.c
new file mode 100644
index 0000000..74d0cf0
--- /dev/null
+++ b/src/common/checksum_helper.c
@@ -0,0 +1,232 @@
+/*-------------------------------------------------------------------------
+ *
+ * checksum_helper.c
+ * Compute a checksum of any of various types using common routines
+ *
+ * Portions Copyright (c) 2016-2022, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/common/checksum_helper.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+#include "common/checksum_helper.h"
+
+/*
+ * If 'name' is a recognized checksum type, set *type to the corresponding
+ * constant and return true. Otherwise, set *type to CHECKSUM_TYPE_NONE and
+ * return false.
+ */
+bool
+pg_checksum_parse_type(char *name, pg_checksum_type *type)
+{
+ pg_checksum_type result_type = CHECKSUM_TYPE_NONE;
+ bool result = true;
+
+ if (pg_strcasecmp(name, "none") == 0)
+ result_type = CHECKSUM_TYPE_NONE;
+ else if (pg_strcasecmp(name, "crc32c") == 0)
+ result_type = CHECKSUM_TYPE_CRC32C;
+ else if (pg_strcasecmp(name, "sha224") == 0)
+ result_type = CHECKSUM_TYPE_SHA224;
+ else if (pg_strcasecmp(name, "sha256") == 0)
+ result_type = CHECKSUM_TYPE_SHA256;
+ else if (pg_strcasecmp(name, "sha384") == 0)
+ result_type = CHECKSUM_TYPE_SHA384;
+ else if (pg_strcasecmp(name, "sha512") == 0)
+ result_type = CHECKSUM_TYPE_SHA512;
+ else
+ result = false;
+
+ *type = result_type;
+ return result;
+}
+
+/*
+ * Get the canonical human-readable name corresponding to a checksum type.
+ */
+char *
+pg_checksum_type_name(pg_checksum_type type)
+{
+ switch (type)
+ {
+ case CHECKSUM_TYPE_NONE:
+ return "NONE";
+ case CHECKSUM_TYPE_CRC32C:
+ return "CRC32C";
+ case CHECKSUM_TYPE_SHA224:
+ return "SHA224";
+ case CHECKSUM_TYPE_SHA256:
+ return "SHA256";
+ case CHECKSUM_TYPE_SHA384:
+ return "SHA384";
+ case CHECKSUM_TYPE_SHA512:
+ return "SHA512";
+ }
+
+ Assert(false);
+ return "???";
+}
+
+/*
+ * Initialize a checksum context for checksums of the given type.
+ * Returns 0 for a success, -1 for a failure.
+ */
+int
+pg_checksum_init(pg_checksum_context *context, pg_checksum_type type)
+{
+ context->type = type;
+
+ switch (type)
+ {
+ case CHECKSUM_TYPE_NONE:
+ /* do nothing */
+ break;
+ case CHECKSUM_TYPE_CRC32C:
+ INIT_CRC32C(context->raw_context.c_crc32c);
+ break;
+ case CHECKSUM_TYPE_SHA224:
+ context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA224);
+ if (context->raw_context.c_sha2 == NULL)
+ return -1;
+ if (pg_cryptohash_init(context->raw_context.c_sha2) < 0)
+ {
+ pg_cryptohash_free(context->raw_context.c_sha2);
+ return -1;
+ }
+ break;
+ case CHECKSUM_TYPE_SHA256:
+ context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA256);
+ if (context->raw_context.c_sha2 == NULL)
+ return -1;
+ if (pg_cryptohash_init(context->raw_context.c_sha2) < 0)
+ {
+ pg_cryptohash_free(context->raw_context.c_sha2);
+ return -1;
+ }
+ break;
+ case CHECKSUM_TYPE_SHA384:
+ context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA384);
+ if (context->raw_context.c_sha2 == NULL)
+ return -1;
+ if (pg_cryptohash_init(context->raw_context.c_sha2) < 0)
+ {
+ pg_cryptohash_free(context->raw_context.c_sha2);
+ return -1;
+ }
+ break;
+ case CHECKSUM_TYPE_SHA512:
+ context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA512);
+ if (context->raw_context.c_sha2 == NULL)
+ return -1;
+ if (pg_cryptohash_init(context->raw_context.c_sha2) < 0)
+ {
+ pg_cryptohash_free(context->raw_context.c_sha2);
+ return -1;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * Update a checksum context with new data.
+ * Returns 0 for a success, -1 for a failure.
+ */
+int
+pg_checksum_update(pg_checksum_context *context, const uint8 *input,
+ size_t len)
+{
+ switch (context->type)
+ {
+ case CHECKSUM_TYPE_NONE:
+ /* do nothing */
+ break;
+ case CHECKSUM_TYPE_CRC32C:
+ COMP_CRC32C(context->raw_context.c_crc32c, input, len);
+ break;
+ case CHECKSUM_TYPE_SHA224:
+ case CHECKSUM_TYPE_SHA256:
+ case CHECKSUM_TYPE_SHA384:
+ case CHECKSUM_TYPE_SHA512:
+ if (pg_cryptohash_update(context->raw_context.c_sha2, input, len) < 0)
+ return -1;
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * Finalize a checksum computation and write the result to an output buffer.
+ *
+ * The caller must ensure that the buffer is at least PG_CHECKSUM_MAX_LENGTH
+ * bytes in length. The return value is the number of bytes actually written,
+ * or -1 for a failure.
+ */
+int
+pg_checksum_final(pg_checksum_context *context, uint8 *output)
+{
+ int retval = 0;
+
+ StaticAssertStmt(sizeof(pg_crc32c) <= PG_CHECKSUM_MAX_LENGTH,
+ "CRC-32C digest too big for PG_CHECKSUM_MAX_LENGTH");
+ StaticAssertStmt(PG_SHA224_DIGEST_LENGTH <= PG_CHECKSUM_MAX_LENGTH,
+ "SHA224 digest too big for PG_CHECKSUM_MAX_LENGTH");
+ StaticAssertStmt(PG_SHA256_DIGEST_LENGTH <= PG_CHECKSUM_MAX_LENGTH,
+ "SHA256 digest too big for PG_CHECKSUM_MAX_LENGTH");
+ StaticAssertStmt(PG_SHA384_DIGEST_LENGTH <= PG_CHECKSUM_MAX_LENGTH,
+ "SHA384 digest too big for PG_CHECKSUM_MAX_LENGTH");
+ StaticAssertStmt(PG_SHA512_DIGEST_LENGTH <= PG_CHECKSUM_MAX_LENGTH,
+ "SHA512 digest too big for PG_CHECKSUM_MAX_LENGTH");
+
+ switch (context->type)
+ {
+ case CHECKSUM_TYPE_NONE:
+ break;
+ case CHECKSUM_TYPE_CRC32C:
+ FIN_CRC32C(context->raw_context.c_crc32c);
+ retval = sizeof(pg_crc32c);
+ memcpy(output, &context->raw_context.c_crc32c, retval);
+ break;
+ case CHECKSUM_TYPE_SHA224:
+ retval = PG_SHA224_DIGEST_LENGTH;
+ if (pg_cryptohash_final(context->raw_context.c_sha2,
+ output, retval) < 0)
+ return -1;
+ pg_cryptohash_free(context->raw_context.c_sha2);
+ break;
+ case CHECKSUM_TYPE_SHA256:
+ retval = PG_SHA256_DIGEST_LENGTH;
+ if (pg_cryptohash_final(context->raw_context.c_sha2,
+ output, retval) < 0)
+ return -1;
+ pg_cryptohash_free(context->raw_context.c_sha2);
+ break;
+ case CHECKSUM_TYPE_SHA384:
+ retval = PG_SHA384_DIGEST_LENGTH;
+ if (pg_cryptohash_final(context->raw_context.c_sha2,
+ output, retval) < 0)
+ return -1;
+ pg_cryptohash_free(context->raw_context.c_sha2);
+ break;
+ case CHECKSUM_TYPE_SHA512:
+ retval = PG_SHA512_DIGEST_LENGTH;
+ if (pg_cryptohash_final(context->raw_context.c_sha2,
+ output, retval) < 0)
+ return -1;
+ pg_cryptohash_free(context->raw_context.c_sha2);
+ break;
+ }
+
+ Assert(retval <= PG_CHECKSUM_MAX_LENGTH);
+ return retval;
+}