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 28 221378 : pg_checksum_parse_type(char *name, pg_checksum_type *type) 29 : { 30 221378 : pg_checksum_type result_type = CHECKSUM_TYPE_NONE; 31 221378 : bool result = true; 32 : 33 221378 : if (pg_strcasecmp(name, "none") == 0) 34 6 : result_type = CHECKSUM_TYPE_NONE; 35 221372 : else if (pg_strcasecmp(name, "crc32c") == 0) 36 203880 : result_type = CHECKSUM_TYPE_CRC32C; 37 17492 : else if (pg_strcasecmp(name, "sha224") == 0) 38 5828 : result_type = CHECKSUM_TYPE_SHA224; 39 11664 : else if (pg_strcasecmp(name, "sha256") == 0) 40 3886 : result_type = CHECKSUM_TYPE_SHA256; 41 7778 : else if (pg_strcasecmp(name, "sha384") == 0) 42 3886 : result_type = CHECKSUM_TYPE_SHA384; 43 3892 : else if (pg_strcasecmp(name, "sha512") == 0) 44 3886 : result_type = CHECKSUM_TYPE_SHA512; 45 : else 46 6 : result = false; 47 : 48 221378 : *type = result_type; 49 221378 : return result; 50 : } 51 : 52 : /* 53 : * Get the canonical human-readable name corresponding to a checksum type. 54 : */ 55 : char * 56 318444 : pg_checksum_type_name(pg_checksum_type type) 57 : { 58 318444 : switch (type) 59 : { 60 0 : case CHECKSUM_TYPE_NONE: 61 0 : return "NONE"; 62 300976 : case CHECKSUM_TYPE_CRC32C: 63 300976 : return "CRC32C"; 64 5822 : case CHECKSUM_TYPE_SHA224: 65 5822 : return "SHA224"; 66 3882 : case CHECKSUM_TYPE_SHA256: 67 3882 : return "SHA256"; 68 3882 : case CHECKSUM_TYPE_SHA384: 69 3882 : return "SHA384"; 70 3882 : case CHECKSUM_TYPE_SHA512: 71 3882 : return "SHA512"; 72 : } 73 : 74 : Assert(false); 75 0 : 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 83 456416 : pg_checksum_init(pg_checksum_context *context, pg_checksum_type type) 84 : { 85 456416 : context->type = type; 86 : 87 456416 : switch (type) 88 : { 89 27818 : case CHECKSUM_TYPE_NONE: 90 : /* do nothing */ 91 27818 : break; 92 393658 : case CHECKSUM_TYPE_CRC32C: 93 393658 : INIT_CRC32C(context->raw_context.c_crc32c); 94 393658 : break; 95 11638 : case CHECKSUM_TYPE_SHA224: 96 11638 : context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA224); 97 11638 : if (context->raw_context.c_sha2 == NULL) 98 0 : return -1; 99 11638 : if (pg_cryptohash_init(context->raw_context.c_sha2) < 0) 100 : { 101 0 : pg_cryptohash_free(context->raw_context.c_sha2); 102 0 : return -1; 103 : } 104 11638 : break; 105 7782 : case CHECKSUM_TYPE_SHA256: 106 7782 : context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA256); 107 7782 : if (context->raw_context.c_sha2 == NULL) 108 0 : return -1; 109 7782 : if (pg_cryptohash_init(context->raw_context.c_sha2) < 0) 110 : { 111 0 : pg_cryptohash_free(context->raw_context.c_sha2); 112 0 : return -1; 113 : } 114 7782 : break; 115 7760 : case CHECKSUM_TYPE_SHA384: 116 7760 : context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA384); 117 7760 : if (context->raw_context.c_sha2 == NULL) 118 0 : return -1; 119 7760 : if (pg_cryptohash_init(context->raw_context.c_sha2) < 0) 120 : { 121 0 : pg_cryptohash_free(context->raw_context.c_sha2); 122 0 : return -1; 123 : } 124 7760 : break; 125 7760 : case CHECKSUM_TYPE_SHA512: 126 7760 : context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA512); 127 7760 : if (context->raw_context.c_sha2 == NULL) 128 0 : return -1; 129 7760 : if (pg_cryptohash_init(context->raw_context.c_sha2) < 0) 130 : { 131 0 : pg_cryptohash_free(context->raw_context.c_sha2); 132 0 : return -1; 133 : } 134 7760 : break; 135 : } 136 : 137 456416 : 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 145 679986 : pg_checksum_update(pg_checksum_context *context, const uint8 *input, 146 : size_t len) 147 : { 148 679986 : switch (context->type) 149 : { 150 26438 : case CHECKSUM_TYPE_NONE: 151 : /* do nothing */ 152 26438 : break; 153 616656 : case CHECKSUM_TYPE_CRC32C: 154 616656 : COMP_CRC32C(context->raw_context.c_crc32c, input, len); 155 616656 : break; 156 36892 : case CHECKSUM_TYPE_SHA224: 157 : case CHECKSUM_TYPE_SHA256: 158 : case CHECKSUM_TYPE_SHA384: 159 : case CHECKSUM_TYPE_SHA512: 160 36892 : if (pg_cryptohash_update(context->raw_context.c_sha2, input, len) < 0) 161 0 : return -1; 162 36892 : break; 163 : } 164 : 165 679986 : 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 176 428596 : pg_checksum_final(pg_checksum_context *context, uint8 *output) 177 : { 178 428596 : 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 428596 : switch (context->type) 192 : { 193 4 : case CHECKSUM_TYPE_NONE: 194 4 : break; 195 393654 : case CHECKSUM_TYPE_CRC32C: 196 393654 : FIN_CRC32C(context->raw_context.c_crc32c); 197 393654 : retval = sizeof(pg_crc32c); 198 393654 : memcpy(output, &context->raw_context.c_crc32c, retval); 199 393654 : break; 200 11638 : case CHECKSUM_TYPE_SHA224: 201 11638 : retval = PG_SHA224_DIGEST_LENGTH; 202 11638 : if (pg_cryptohash_final(context->raw_context.c_sha2, 203 : output, retval) < 0) 204 0 : return -1; 205 11638 : pg_cryptohash_free(context->raw_context.c_sha2); 206 11638 : break; 207 7780 : case CHECKSUM_TYPE_SHA256: 208 7780 : retval = PG_SHA256_DIGEST_LENGTH; 209 7780 : if (pg_cryptohash_final(context->raw_context.c_sha2, 210 : output, retval) < 0) 211 0 : return -1; 212 7780 : pg_cryptohash_free(context->raw_context.c_sha2); 213 7780 : break; 214 7760 : case CHECKSUM_TYPE_SHA384: 215 7760 : retval = PG_SHA384_DIGEST_LENGTH; 216 7760 : if (pg_cryptohash_final(context->raw_context.c_sha2, 217 : output, retval) < 0) 218 0 : return -1; 219 7760 : pg_cryptohash_free(context->raw_context.c_sha2); 220 7760 : break; 221 7760 : case CHECKSUM_TYPE_SHA512: 222 7760 : retval = PG_SHA512_DIGEST_LENGTH; 223 7760 : if (pg_cryptohash_final(context->raw_context.c_sha2, 224 : output, retval) < 0) 225 0 : return -1; 226 7760 : pg_cryptohash_free(context->raw_context.c_sha2); 227 7760 : break; 228 : } 229 : 230 428596 : Assert(retval <= PG_CHECKSUM_MAX_LENGTH); 231 428596 : return retval; 232 : }