1 /*-------------------------------------------------------------------------
4 * Compute a checksum of any of various types using common routines
6 * Portions Copyright (c) 2016-2024, PostgreSQL Global Development Group
9 * src/common/checksum_helper.c
11 *-------------------------------------------------------------------------
17 #include "postgres_fe.h"
20 #include "common/checksum_helper.h"
23 * If 'name' is a recognized checksum type, set *type to the corresponding
24 * constant and return true. Otherwise, set *type to CHECKSUM_TYPE_NONE and
28 pg_checksum_parse_type(char *name
, pg_checksum_type
*type
)
30 pg_checksum_type result_type
= CHECKSUM_TYPE_NONE
;
33 if (pg_strcasecmp(name
, "none") == 0)
34 result_type
= CHECKSUM_TYPE_NONE
;
35 else if (pg_strcasecmp(name
, "crc32c") == 0)
36 result_type
= CHECKSUM_TYPE_CRC32C
;
37 else if (pg_strcasecmp(name
, "sha224") == 0)
38 result_type
= CHECKSUM_TYPE_SHA224
;
39 else if (pg_strcasecmp(name
, "sha256") == 0)
40 result_type
= CHECKSUM_TYPE_SHA256
;
41 else if (pg_strcasecmp(name
, "sha384") == 0)
42 result_type
= CHECKSUM_TYPE_SHA384
;
43 else if (pg_strcasecmp(name
, "sha512") == 0)
44 result_type
= CHECKSUM_TYPE_SHA512
;
53 * Get the canonical human-readable name corresponding to a checksum type.
56 pg_checksum_type_name(pg_checksum_type type
)
60 case CHECKSUM_TYPE_NONE
:
62 case CHECKSUM_TYPE_CRC32C
:
64 case CHECKSUM_TYPE_SHA224
:
66 case CHECKSUM_TYPE_SHA256
:
68 case CHECKSUM_TYPE_SHA384
:
70 case CHECKSUM_TYPE_SHA512
:
79 * Initialize a checksum context for checksums of the given type.
80 * Returns 0 for a success, -1 for a failure.
83 pg_checksum_init(pg_checksum_context
*context
, pg_checksum_type type
)
89 case CHECKSUM_TYPE_NONE
:
92 case CHECKSUM_TYPE_CRC32C
:
93 INIT_CRC32C(context
->raw_context
.c_crc32c
);
95 case CHECKSUM_TYPE_SHA224
:
96 context
->raw_context
.c_sha2
= pg_cryptohash_create(PG_SHA224
);
97 if (context
->raw_context
.c_sha2
== NULL
)
99 if (pg_cryptohash_init(context
->raw_context
.c_sha2
) < 0)
101 pg_cryptohash_free(context
->raw_context
.c_sha2
);
105 case CHECKSUM_TYPE_SHA256
:
106 context
->raw_context
.c_sha2
= pg_cryptohash_create(PG_SHA256
);
107 if (context
->raw_context
.c_sha2
== NULL
)
109 if (pg_cryptohash_init(context
->raw_context
.c_sha2
) < 0)
111 pg_cryptohash_free(context
->raw_context
.c_sha2
);
115 case CHECKSUM_TYPE_SHA384
:
116 context
->raw_context
.c_sha2
= pg_cryptohash_create(PG_SHA384
);
117 if (context
->raw_context
.c_sha2
== NULL
)
119 if (pg_cryptohash_init(context
->raw_context
.c_sha2
) < 0)
121 pg_cryptohash_free(context
->raw_context
.c_sha2
);
125 case CHECKSUM_TYPE_SHA512
:
126 context
->raw_context
.c_sha2
= pg_cryptohash_create(PG_SHA512
);
127 if (context
->raw_context
.c_sha2
== NULL
)
129 if (pg_cryptohash_init(context
->raw_context
.c_sha2
) < 0)
131 pg_cryptohash_free(context
->raw_context
.c_sha2
);
141 * Update a checksum context with new data.
142 * Returns 0 for a success, -1 for a failure.
145 pg_checksum_update(pg_checksum_context
*context
, const uint8
*input
,
148 switch (context
->type
)
150 case CHECKSUM_TYPE_NONE
:
153 case CHECKSUM_TYPE_CRC32C
:
154 COMP_CRC32C(context
->raw_context
.c_crc32c
, input
, len
);
156 case CHECKSUM_TYPE_SHA224
:
157 case CHECKSUM_TYPE_SHA256
:
158 case CHECKSUM_TYPE_SHA384
:
159 case CHECKSUM_TYPE_SHA512
:
160 if (pg_cryptohash_update(context
->raw_context
.c_sha2
, input
, len
) < 0)
169 * Finalize a checksum computation and write the result to an output buffer.
171 * The caller must ensure that the buffer is at least PG_CHECKSUM_MAX_LENGTH
172 * bytes in length. The return value is the number of bytes actually written,
173 * or -1 for a failure.
176 pg_checksum_final(pg_checksum_context
*context
, uint8
*output
)
180 StaticAssertDecl(sizeof(pg_crc32c
) <= PG_CHECKSUM_MAX_LENGTH
,
181 "CRC-32C digest too big for PG_CHECKSUM_MAX_LENGTH");
182 StaticAssertDecl(PG_SHA224_DIGEST_LENGTH
<= PG_CHECKSUM_MAX_LENGTH
,
183 "SHA224 digest too big for PG_CHECKSUM_MAX_LENGTH");
184 StaticAssertDecl(PG_SHA256_DIGEST_LENGTH
<= PG_CHECKSUM_MAX_LENGTH
,
185 "SHA256 digest too big for PG_CHECKSUM_MAX_LENGTH");
186 StaticAssertDecl(PG_SHA384_DIGEST_LENGTH
<= PG_CHECKSUM_MAX_LENGTH
,
187 "SHA384 digest too big for PG_CHECKSUM_MAX_LENGTH");
188 StaticAssertDecl(PG_SHA512_DIGEST_LENGTH
<= PG_CHECKSUM_MAX_LENGTH
,
189 "SHA512 digest too big for PG_CHECKSUM_MAX_LENGTH");
191 switch (context
->type
)
193 case CHECKSUM_TYPE_NONE
:
195 case CHECKSUM_TYPE_CRC32C
:
196 FIN_CRC32C(context
->raw_context
.c_crc32c
);
197 retval
= sizeof(pg_crc32c
);
198 memcpy(output
, &context
->raw_context
.c_crc32c
, retval
);
200 case CHECKSUM_TYPE_SHA224
:
201 retval
= PG_SHA224_DIGEST_LENGTH
;
202 if (pg_cryptohash_final(context
->raw_context
.c_sha2
,
205 pg_cryptohash_free(context
->raw_context
.c_sha2
);
207 case CHECKSUM_TYPE_SHA256
:
208 retval
= PG_SHA256_DIGEST_LENGTH
;
209 if (pg_cryptohash_final(context
->raw_context
.c_sha2
,
212 pg_cryptohash_free(context
->raw_context
.c_sha2
);
214 case CHECKSUM_TYPE_SHA384
:
215 retval
= PG_SHA384_DIGEST_LENGTH
;
216 if (pg_cryptohash_final(context
->raw_context
.c_sha2
,
219 pg_cryptohash_free(context
->raw_context
.c_sha2
);
221 case CHECKSUM_TYPE_SHA512
:
222 retval
= PG_SHA512_DIGEST_LENGTH
;
223 if (pg_cryptohash_final(context
->raw_context
.c_sha2
,
226 pg_cryptohash_free(context
->raw_context
.c_sha2
);
230 Assert(retval
<= PG_CHECKSUM_MAX_LENGTH
);