Age Owner Branch data 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-2024, 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
1472 rhaas@postgresql.org 28 :CBC 94703 : pg_checksum_parse_type(char *name, pg_checksum_type *type)
29 : : {
30 : 94703 : pg_checksum_type result_type = CHECKSUM_TYPE_NONE;
31 : 94703 : bool result = true;
32 : :
33 [ + + ]: 94703 : if (pg_strcasecmp(name, "none") == 0)
34 : 2 : result_type = CHECKSUM_TYPE_NONE;
35 [ + + ]: 94701 : else if (pg_strcasecmp(name, "crc32c") == 0)
36 : 89864 : result_type = CHECKSUM_TYPE_CRC32C;
37 [ + + ]: 4837 : else if (pg_strcasecmp(name, "sha224") == 0)
38 : 1934 : 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 : 94703 : *type = result_type;
49 : 94703 : return result;
50 : : }
51 : :
52 : : /*
53 : : * Get the canonical human-readable name corresponding to a checksum type.
54 : : */
55 : : char *
56 : 152690 : pg_checksum_type_name(pg_checksum_type type)
57 : : {
58 [ - + + + : 152690 : switch (type)
+ + - ]
59 : : {
1472 rhaas@postgresql.org 60 :UBC 0 : case CHECKSUM_TYPE_NONE:
61 : 0 : return "NONE";
1472 rhaas@postgresql.org 62 :CBC 147860 : case CHECKSUM_TYPE_CRC32C:
63 : 147860 : return "CRC32C";
64 : 1932 : case CHECKSUM_TYPE_SHA224:
65 : 1932 : 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 : :
1472 rhaas@postgresql.org 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
1472 rhaas@postgresql.org 83 :CBC 214580 : pg_checksum_init(pg_checksum_context *context, pg_checksum_type type)
84 : : {
85 : 214580 : context->type = type;
86 : :
87 [ + + + + : 214580 : switch (type)
+ + - ]
88 : : {
89 : 11233 : case CHECKSUM_TYPE_NONE:
90 : : /* do nothing */
91 : 11233 : break;
92 : 193683 : case CHECKSUM_TYPE_CRC32C:
93 : 193683 : INIT_CRC32C(context->raw_context.c_crc32c);
94 : 193683 : break;
95 : 3862 : case CHECKSUM_TYPE_SHA224:
1192 michael@paquier.xyz 96 : 3862 : context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA224);
97 [ - + ]: 3862 : if (context->raw_context.c_sha2 == NULL)
1229 michael@paquier.xyz 98 :UBC 0 : return -1;
1192 michael@paquier.xyz 99 [ - + ]:CBC 3862 : if (pg_cryptohash_init(context->raw_context.c_sha2) < 0)
100 : : {
1192 michael@paquier.xyz 101 :UBC 0 : pg_cryptohash_free(context->raw_context.c_sha2);
1229 102 : 0 : return -1;
103 : : }
1472 rhaas@postgresql.org 104 :CBC 3862 : break;
105 : 1940 : case CHECKSUM_TYPE_SHA256:
1192 michael@paquier.xyz 106 : 1940 : context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA256);
107 [ - + ]: 1940 : if (context->raw_context.c_sha2 == NULL)
1229 michael@paquier.xyz 108 :UBC 0 : return -1;
1192 michael@paquier.xyz 109 [ - + ]:CBC 1940 : if (pg_cryptohash_init(context->raw_context.c_sha2) < 0)
110 : : {
1192 michael@paquier.xyz 111 :UBC 0 : pg_cryptohash_free(context->raw_context.c_sha2);
1229 112 : 0 : return -1;
113 : : }
1472 rhaas@postgresql.org 114 :CBC 1940 : break;
115 : 1931 : case CHECKSUM_TYPE_SHA384:
1192 michael@paquier.xyz 116 : 1931 : context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA384);
117 [ - + ]: 1931 : if (context->raw_context.c_sha2 == NULL)
1229 michael@paquier.xyz 118 :UBC 0 : return -1;
1192 michael@paquier.xyz 119 [ - + ]:CBC 1931 : if (pg_cryptohash_init(context->raw_context.c_sha2) < 0)
120 : : {
1192 michael@paquier.xyz 121 :UBC 0 : pg_cryptohash_free(context->raw_context.c_sha2);
1229 122 : 0 : return -1;
123 : : }
1472 rhaas@postgresql.org 124 :CBC 1931 : break;
125 : 1931 : case CHECKSUM_TYPE_SHA512:
1192 michael@paquier.xyz 126 : 1931 : context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA512);
127 [ - + ]: 1931 : if (context->raw_context.c_sha2 == NULL)
1229 michael@paquier.xyz 128 :UBC 0 : return -1;
1192 michael@paquier.xyz 129 [ - + ]:CBC 1931 : if (pg_cryptohash_init(context->raw_context.c_sha2) < 0)
130 : : {
1192 michael@paquier.xyz 131 :UBC 0 : pg_cryptohash_free(context->raw_context.c_sha2);
1229 132 : 0 : return -1;
133 : : }
1472 rhaas@postgresql.org 134 :CBC 1931 : break;
135 : : }
136 : :
1229 michael@paquier.xyz 137 : 214580 : 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
1472 rhaas@postgresql.org 145 : 235789 : pg_checksum_update(pg_checksum_context *context, const uint8 *input,
146 : : size_t len)
147 : : {
148 [ + + + - ]: 235789 : switch (context->type)
149 : : {
150 : 10525 : case CHECKSUM_TYPE_NONE:
151 : : /* do nothing */
152 : 10525 : break;
153 : 215475 : case CHECKSUM_TYPE_CRC32C:
154 : 215475 : COMP_CRC32C(context->raw_context.c_crc32c, input, len);
155 : 215475 : break;
156 : 9789 : case CHECKSUM_TYPE_SHA224:
157 : : case CHECKSUM_TYPE_SHA256:
158 : : case CHECKSUM_TYPE_SHA384:
159 : : case CHECKSUM_TYPE_SHA512:
1192 michael@paquier.xyz 160 [ - + ]: 9789 : if (pg_cryptohash_update(context->raw_context.c_sha2, input, len) < 0)
1229 michael@paquier.xyz 161 :UBC 0 : return -1;
1472 rhaas@postgresql.org 162 :CBC 9789 : break;
163 : : }
164 : :
1229 michael@paquier.xyz 165 : 235789 : 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
1472 rhaas@postgresql.org 176 : 203348 : pg_checksum_final(pg_checksum_context *context, uint8 *output)
177 : : {
178 : 203348 : 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 [ + + + + : 203348 : switch (context->type)
+ + - ]
192 : : {
1472 rhaas@postgresql.org 193 :GBC 2 : case CHECKSUM_TYPE_NONE:
194 : 2 : break;
1472 rhaas@postgresql.org 195 :CBC 193682 : case CHECKSUM_TYPE_CRC32C:
196 : 193682 : FIN_CRC32C(context->raw_context.c_crc32c);
197 : 193682 : retval = sizeof(pg_crc32c);
198 : 193682 : memcpy(output, &context->raw_context.c_crc32c, retval);
199 : 193682 : break;
200 : 3862 : case CHECKSUM_TYPE_SHA224:
1154 michael@paquier.xyz 201 : 3862 : retval = PG_SHA224_DIGEST_LENGTH;
202 [ - + ]: 3862 : if (pg_cryptohash_final(context->raw_context.c_sha2,
203 : : output, retval) < 0)
1229 michael@paquier.xyz 204 :UBC 0 : return -1;
1192 michael@paquier.xyz 205 :CBC 3862 : pg_cryptohash_free(context->raw_context.c_sha2);
1472 rhaas@postgresql.org 206 : 3862 : break;
207 : 1940 : case CHECKSUM_TYPE_SHA256:
1154 michael@paquier.xyz 208 : 1940 : retval = PG_SHA256_DIGEST_LENGTH;
209 [ - + ]: 1940 : if (pg_cryptohash_final(context->raw_context.c_sha2,
210 : : output, retval) < 0)
1229 michael@paquier.xyz 211 :UBC 0 : return -1;
1192 michael@paquier.xyz 212 :CBC 1940 : pg_cryptohash_free(context->raw_context.c_sha2);
1472 rhaas@postgresql.org 213 : 1940 : break;
214 : 1931 : case CHECKSUM_TYPE_SHA384:
1154 michael@paquier.xyz 215 : 1931 : retval = PG_SHA384_DIGEST_LENGTH;
216 [ - + ]: 1931 : if (pg_cryptohash_final(context->raw_context.c_sha2,
217 : : output, retval) < 0)
1229 michael@paquier.xyz 218 :UBC 0 : return -1;
1192 michael@paquier.xyz 219 :CBC 1931 : pg_cryptohash_free(context->raw_context.c_sha2);
1472 rhaas@postgresql.org 220 : 1931 : break;
221 : 1931 : case CHECKSUM_TYPE_SHA512:
1154 michael@paquier.xyz 222 : 1931 : retval = PG_SHA512_DIGEST_LENGTH;
223 [ - + ]: 1931 : if (pg_cryptohash_final(context->raw_context.c_sha2,
224 : : output, retval) < 0)
1229 michael@paquier.xyz 225 :UBC 0 : return -1;
1192 michael@paquier.xyz 226 :CBC 1931 : pg_cryptohash_free(context->raw_context.c_sha2);
1472 rhaas@postgresql.org 227 : 1931 : break;
228 : : }
229 : :
230 [ - + ]: 203348 : Assert(retval <= PG_CHECKSUM_MAX_LENGTH);
231 : 203348 : return retval;
232 : : }
|