Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * checksum_helper.c
4 : * Compute a checksum of any of various types using common routines
5 : *
6 : * Portions Copyright (c) 2016-2023, PostgreSQL Global Development Group
7 : *
8 : * IDENTIFICATION
9 : * src/common/checksum_helper.c
10 : *
11 : *-------------------------------------------------------------------------
12 : */
13 :
14 : #ifndef FRONTEND
15 : #include "postgres.h"
16 : #else
17 : #include "postgres_fe.h"
18 : #endif
19 :
20 : #include "common/checksum_helper.h"
21 :
22 : /*
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
25 : * return false.
26 : */
27 : bool
1101 rhaas 28 CBC 58044 : pg_checksum_parse_type(char *name, pg_checksum_type *type)
29 : {
30 58044 : pg_checksum_type result_type = CHECKSUM_TYPE_NONE;
31 58044 : bool result = true;
32 :
33 58044 : if (pg_strcasecmp(name, "none") == 0)
34 1 : result_type = CHECKSUM_TYPE_NONE;
35 58043 : else if (pg_strcasecmp(name, "crc32c") == 0)
36 54173 : result_type = CHECKSUM_TYPE_CRC32C;
37 3870 : else if (pg_strcasecmp(name, "sha224") == 0)
38 967 : result_type = CHECKSUM_TYPE_SHA224;
39 2903 : else if (pg_strcasecmp(name, "sha256") == 0)
40 967 : result_type = CHECKSUM_TYPE_SHA256;
41 1936 : else if (pg_strcasecmp(name, "sha384") == 0)
42 967 : result_type = CHECKSUM_TYPE_SHA384;
43 969 : else if (pg_strcasecmp(name, "sha512") == 0)
44 967 : result_type = CHECKSUM_TYPE_SHA512;
45 : else
46 2 : result = false;
47 :
48 58044 : *type = result_type;
49 58044 : return result;
50 : }
51 :
52 : /*
53 : * Get the canonical human-readable name corresponding to a checksum type.
54 : */
55 : char *
56 117601 : pg_checksum_type_name(pg_checksum_type type)
57 : {
58 117601 : switch (type)
59 : {
1101 rhaas 60 UBC 0 : case CHECKSUM_TYPE_NONE:
61 0 : return "NONE";
1101 rhaas 62 CBC 113737 : case CHECKSUM_TYPE_CRC32C:
63 113737 : return "CRC32C";
64 966 : case CHECKSUM_TYPE_SHA224:
65 966 : return "SHA224";
66 966 : case CHECKSUM_TYPE_SHA256:
67 966 : return "SHA256";
68 966 : case CHECKSUM_TYPE_SHA384:
69 966 : return "SHA384";
70 966 : case CHECKSUM_TYPE_SHA512:
71 966 : return "SHA512";
72 : }
73 :
1101 rhaas 74 UBC 0 : Assert(false);
75 : return "???";
76 : }
77 :
78 : /*
79 : * Initialize a checksum context for checksums of the given type.
80 : * Returns 0 for a success, -1 for a failure.
81 : */
82 : int
1101 rhaas 83 CBC 171761 : pg_checksum_init(pg_checksum_context *context, pg_checksum_type type)
84 : {
85 171761 : context->type = type;
86 :
87 171761 : switch (type)
88 : {
89 1935 : case CHECKSUM_TYPE_NONE:
90 : /* do nothing */
91 1935 : break;
92 162102 : case CHECKSUM_TYPE_CRC32C:
93 162102 : INIT_CRC32C(context->raw_context.c_crc32c);
94 162102 : break;
95 1931 : case CHECKSUM_TYPE_SHA224:
821 michael 96 1931 : context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA224);
97 1931 : if (context->raw_context.c_sha2 == NULL)
858 michael 98 UBC 0 : return -1;
821 michael 99 CBC 1931 : if (pg_cryptohash_init(context->raw_context.c_sha2) < 0)
100 : {
821 michael 101 UBC 0 : pg_cryptohash_free(context->raw_context.c_sha2);
858 102 0 : return -1;
103 : }
1101 rhaas 104 CBC 1931 : break;
105 1931 : case CHECKSUM_TYPE_SHA256:
821 michael 106 1931 : context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA256);
107 1931 : if (context->raw_context.c_sha2 == NULL)
858 michael 108 UBC 0 : return -1;
821 michael 109 CBC 1931 : if (pg_cryptohash_init(context->raw_context.c_sha2) < 0)
110 : {
821 michael 111 UBC 0 : pg_cryptohash_free(context->raw_context.c_sha2);
858 112 0 : return -1;
113 : }
1101 rhaas 114 CBC 1931 : break;
115 1931 : case CHECKSUM_TYPE_SHA384:
821 michael 116 1931 : context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA384);
117 1931 : if (context->raw_context.c_sha2 == NULL)
858 michael 118 UBC 0 : return -1;
821 michael 119 CBC 1931 : if (pg_cryptohash_init(context->raw_context.c_sha2) < 0)
120 : {
821 michael 121 UBC 0 : pg_cryptohash_free(context->raw_context.c_sha2);
858 122 0 : return -1;
123 : }
1101 rhaas 124 CBC 1931 : break;
125 1931 : case CHECKSUM_TYPE_SHA512:
821 michael 126 1931 : context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA512);
127 1931 : if (context->raw_context.c_sha2 == NULL)
858 michael 128 UBC 0 : return -1;
821 michael 129 CBC 1931 : if (pg_cryptohash_init(context->raw_context.c_sha2) < 0)
130 : {
821 michael 131 UBC 0 : pg_cryptohash_free(context->raw_context.c_sha2);
858 132 0 : return -1;
133 : }
1101 rhaas 134 CBC 1931 : break;
135 : }
136 :
858 michael 137 171761 : return 0;
138 : }
139 :
140 : /*
141 : * Update a checksum context with new data.
142 : * Returns 0 for a success, -1 for a failure.
143 : */
144 : int
1101 rhaas 145 458412 : pg_checksum_update(pg_checksum_context *context, const uint8 *input,
146 : size_t len)
147 : {
148 458412 : switch (context->type)
149 : {
150 2365 : case CHECKSUM_TYPE_NONE:
151 : /* do nothing */
152 2365 : break;
153 428211 : case CHECKSUM_TYPE_CRC32C:
154 428211 : COMP_CRC32C(context->raw_context.c_crc32c, input, len);
155 428211 : break;
156 27836 : case CHECKSUM_TYPE_SHA224:
157 : case CHECKSUM_TYPE_SHA256:
158 : case CHECKSUM_TYPE_SHA384:
159 : case CHECKSUM_TYPE_SHA512:
821 michael 160 27836 : if (pg_cryptohash_update(context->raw_context.c_sha2, input, len) < 0)
858 michael 161 UBC 0 : return -1;
1101 rhaas 162 CBC 27836 : break;
163 : }
164 :
858 michael 165 458412 : return 0;
166 : }
167 :
168 : /*
169 : * Finalize a checksum computation and write the result to an output buffer.
170 : *
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.
174 : */
175 : int
1101 rhaas 176 169825 : pg_checksum_final(pg_checksum_context *context, uint8 *output)
177 : {
178 169825 : int retval = 0;
179 :
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");
190 :
191 169825 : switch (context->type)
192 : {
1101 rhaas 193 UBC 0 : case CHECKSUM_TYPE_NONE:
194 0 : break;
1101 rhaas 195 CBC 162101 : case CHECKSUM_TYPE_CRC32C:
196 162101 : FIN_CRC32C(context->raw_context.c_crc32c);
197 162101 : retval = sizeof(pg_crc32c);
198 162101 : memcpy(output, &context->raw_context.c_crc32c, retval);
199 162101 : break;
200 1931 : case CHECKSUM_TYPE_SHA224:
783 michael 201 1931 : retval = PG_SHA224_DIGEST_LENGTH;
202 1931 : if (pg_cryptohash_final(context->raw_context.c_sha2,
203 : output, retval) < 0)
858 michael 204 UBC 0 : return -1;
821 michael 205 CBC 1931 : pg_cryptohash_free(context->raw_context.c_sha2);
1101 rhaas 206 1931 : break;
207 1931 : case CHECKSUM_TYPE_SHA256:
783 michael 208 1931 : retval = PG_SHA256_DIGEST_LENGTH;
209 1931 : if (pg_cryptohash_final(context->raw_context.c_sha2,
210 : output, retval) < 0)
858 michael 211 UBC 0 : return -1;
821 michael 212 CBC 1931 : pg_cryptohash_free(context->raw_context.c_sha2);
1101 rhaas 213 1931 : break;
214 1931 : case CHECKSUM_TYPE_SHA384:
783 michael 215 1931 : retval = PG_SHA384_DIGEST_LENGTH;
216 1931 : if (pg_cryptohash_final(context->raw_context.c_sha2,
217 : output, retval) < 0)
858 michael 218 UBC 0 : return -1;
821 michael 219 CBC 1931 : pg_cryptohash_free(context->raw_context.c_sha2);
1101 rhaas 220 1931 : break;
221 1931 : case CHECKSUM_TYPE_SHA512:
783 michael 222 1931 : retval = PG_SHA512_DIGEST_LENGTH;
223 1931 : if (pg_cryptohash_final(context->raw_context.c_sha2,
224 : output, retval) < 0)
858 michael 225 UBC 0 : return -1;
821 michael 226 CBC 1931 : pg_cryptohash_free(context->raw_context.c_sha2);
1101 rhaas 227 1931 : break;
228 : }
229 :
230 169825 : Assert(retval <= PG_CHECKSUM_MAX_LENGTH);
231 169825 : return retval;
232 : }
|