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 28 98668 : pg_checksum_parse_type(char *name, pg_checksum_type *type) 29 : { 30 98668 : pg_checksum_type result_type = CHECKSUM_TYPE_NONE; 31 98668 : bool result = true; 32 : 33 98668 : if (pg_strcasecmp(name, "none") == 0) 34 2 : result_type = CHECKSUM_TYPE_NONE; 35 98666 : else if (pg_strcasecmp(name, "crc32c") == 0) 36 90926 : result_type = CHECKSUM_TYPE_CRC32C; 37 7740 : else if (pg_strcasecmp(name, "sha224") == 0) 38 1934 : result_type = CHECKSUM_TYPE_SHA224; 39 5806 : else if (pg_strcasecmp(name, "sha256") == 0) 40 1934 : result_type = CHECKSUM_TYPE_SHA256; 41 3872 : else if (pg_strcasecmp(name, "sha384") == 0) 42 1934 : result_type = CHECKSUM_TYPE_SHA384; 43 1938 : else if (pg_strcasecmp(name, "sha512") == 0) 44 1934 : result_type = CHECKSUM_TYPE_SHA512; 45 : else 46 4 : result = false; 47 : 48 98668 : *type = result_type; 49 98668 : return result; 50 : } 51 : 52 : /* 53 : * Get the canonical human-readable name corresponding to a checksum type. 54 : */ 55 : char * 56 220372 : pg_checksum_type_name(pg_checksum_type type) 57 : { 58 220372 : switch (type) 59 : { 60 0 : case CHECKSUM_TYPE_NONE: 61 0 : return "NONE"; 62 212644 : case CHECKSUM_TYPE_CRC32C: 63 212644 : return "CRC32C"; 64 1932 : case CHECKSUM_TYPE_SHA224: 65 1932 : return "SHA224"; 66 1932 : case CHECKSUM_TYPE_SHA256: 67 1932 : return "SHA256"; 68 1932 : case CHECKSUM_TYPE_SHA384: 69 1932 : return "SHA384"; 70 1932 : case CHECKSUM_TYPE_SHA512: 71 1932 : 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 311308 : pg_checksum_init(pg_checksum_context *context, pg_checksum_type type) 84 : { 85 311308 : context->type = type; 86 : 87 311308 : switch (type) 88 : { 89 3870 : case CHECKSUM_TYPE_NONE: 90 : /* do nothing */ 91 3870 : break; 92 291990 : case CHECKSUM_TYPE_CRC32C: 93 291990 : INIT_CRC32C(context->raw_context.c_crc32c); 94 291990 : break; 95 3862 : case CHECKSUM_TYPE_SHA224: 96 3862 : context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA224); 97 3862 : if (context->raw_context.c_sha2 == NULL) 98 0 : return -1; 99 3862 : 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 3862 : break; 105 3862 : case CHECKSUM_TYPE_SHA256: 106 3862 : context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA256); 107 3862 : if (context->raw_context.c_sha2 == NULL) 108 0 : return -1; 109 3862 : 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 3862 : break; 115 3862 : case CHECKSUM_TYPE_SHA384: 116 3862 : context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA384); 117 3862 : if (context->raw_context.c_sha2 == NULL) 118 0 : return -1; 119 3862 : 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 3862 : break; 125 3862 : case CHECKSUM_TYPE_SHA512: 126 3862 : context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA512); 127 3862 : if (context->raw_context.c_sha2 == NULL) 128 0 : return -1; 129 3862 : 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 3862 : break; 135 : } 136 : 137 311308 : 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 783050 : pg_checksum_update(pg_checksum_context *context, const uint8 *input, 146 : size_t len) 147 : { 148 783050 : switch (context->type) 149 : { 150 4672 : case CHECKSUM_TYPE_NONE: 151 : /* do nothing */ 152 4672 : break; 153 723546 : case CHECKSUM_TYPE_CRC32C: 154 723546 : COMP_CRC32C(context->raw_context.c_crc32c, input, len); 155 723546 : break; 156 54832 : case CHECKSUM_TYPE_SHA224: 157 : case CHECKSUM_TYPE_SHA256: 158 : case CHECKSUM_TYPE_SHA384: 159 : case CHECKSUM_TYPE_SHA512: 160 54832 : if (pg_cryptohash_update(context->raw_context.c_sha2, input, len) < 0) 161 0 : return -1; 162 54832 : break; 163 : } 164 : 165 783050 : 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 307436 : pg_checksum_final(pg_checksum_context *context, uint8 *output) 177 : { 178 307436 : 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 307436 : switch (context->type) 192 : { 193 0 : case CHECKSUM_TYPE_NONE: 194 0 : break; 195 291988 : case CHECKSUM_TYPE_CRC32C: 196 291988 : FIN_CRC32C(context->raw_context.c_crc32c); 197 291988 : retval = sizeof(pg_crc32c); 198 291988 : memcpy(output, &context->raw_context.c_crc32c, retval); 199 291988 : break; 200 3862 : case CHECKSUM_TYPE_SHA224: 201 3862 : retval = PG_SHA224_DIGEST_LENGTH; 202 3862 : if (pg_cryptohash_final(context->raw_context.c_sha2, 203 : output, retval) < 0) 204 0 : return -1; 205 3862 : pg_cryptohash_free(context->raw_context.c_sha2); 206 3862 : break; 207 3862 : case CHECKSUM_TYPE_SHA256: 208 3862 : retval = PG_SHA256_DIGEST_LENGTH; 209 3862 : if (pg_cryptohash_final(context->raw_context.c_sha2, 210 : output, retval) < 0) 211 0 : return -1; 212 3862 : pg_cryptohash_free(context->raw_context.c_sha2); 213 3862 : break; 214 3862 : case CHECKSUM_TYPE_SHA384: 215 3862 : retval = PG_SHA384_DIGEST_LENGTH; 216 3862 : if (pg_cryptohash_final(context->raw_context.c_sha2, 217 : output, retval) < 0) 218 0 : return -1; 219 3862 : pg_cryptohash_free(context->raw_context.c_sha2); 220 3862 : break; 221 3862 : case CHECKSUM_TYPE_SHA512: 222 3862 : retval = PG_SHA512_DIGEST_LENGTH; 223 3862 : if (pg_cryptohash_final(context->raw_context.c_sha2, 224 : output, retval) < 0) 225 0 : return -1; 226 3862 : pg_cryptohash_free(context->raw_context.c_sha2); 227 3862 : break; 228 : } 229 : 230 307436 : Assert(retval <= PG_CHECKSUM_MAX_LENGTH); 231 307436 : return retval; 232 : }