PostgreSQL Source Code  git master
checksum_helper.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * checksum_helper.c
4  * Compute a checksum of any of various types using common routines
5  *
6  * Portions Copyright (c) 2016-2020, 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
29 {
31  bool result = true;
32 
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;
45  else
46  result = false;
47 
48  *type = result_type;
49  return result;
50 }
51 
52 /*
53  * Get the canonical human-readable name corresponding to a checksum type.
54  */
55 char *
57 {
58  switch (type)
59  {
60  case CHECKSUM_TYPE_NONE:
61  return "NONE";
63  return "CRC32C";
65  return "SHA224";
67  return "SHA256";
69  return "SHA384";
71  return "SHA512";
72  }
73 
74  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
84 {
85  context->type = type;
86 
87  switch (type)
88  {
89  case CHECKSUM_TYPE_NONE:
90  /* do nothing */
91  break;
94  break;
97  if (context->raw_context.c_sha224 == NULL)
98  return -1;
99  if (pg_cryptohash_init(context->raw_context.c_sha224) < 0)
100  {
102  return -1;
103  }
104  break;
107  if (context->raw_context.c_sha256 == NULL)
108  return -1;
109  if (pg_cryptohash_init(context->raw_context.c_sha256) < 0)
110  {
112  return -1;
113  }
114  break;
117  if (context->raw_context.c_sha384 == NULL)
118  return -1;
119  if (pg_cryptohash_init(context->raw_context.c_sha384) < 0)
120  {
122  return -1;
123  }
124  break;
127  if (context->raw_context.c_sha512 == NULL)
128  return -1;
129  if (pg_cryptohash_init(context->raw_context.c_sha512) < 0)
130  {
132  return -1;
133  }
134  break;
135  }
136 
137  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
146  size_t len)
147 {
148  switch (context->type)
149  {
150  case CHECKSUM_TYPE_NONE:
151  /* do nothing */
152  break;
154  COMP_CRC32C(context->raw_context.c_crc32c, input, len);
155  break;
157  if (pg_cryptohash_update(context->raw_context.c_sha224, input, len) < 0)
158  return -1;
159  break;
161  if (pg_cryptohash_update(context->raw_context.c_sha256, input, len) < 0)
162  return -1;
163  break;
165  if (pg_cryptohash_update(context->raw_context.c_sha384, input, len) < 0)
166  return -1;
167  break;
169  if (pg_cryptohash_update(context->raw_context.c_sha512, input, len) < 0)
170  return -1;
171  break;
172  }
173 
174  return 0;
175 }
176 
177 /*
178  * Finalize a checksum computation and write the result to an output buffer.
179  *
180  * The caller must ensure that the buffer is at least PG_CHECKSUM_MAX_LENGTH
181  * bytes in length. The return value is the number of bytes actually written,
182  * or -1 for a failure.
183  */
184 int
186 {
187  int retval = 0;
188 
190  "CRC-32C digest too big for PG_CHECKSUM_MAX_LENGTH");
192  "SHA224 digest too for PG_CHECKSUM_MAX_LENGTH");
194  "SHA256 digest too for PG_CHECKSUM_MAX_LENGTH");
196  "SHA384 digest too for PG_CHECKSUM_MAX_LENGTH");
198  "SHA512 digest too for PG_CHECKSUM_MAX_LENGTH");
199 
200  switch (context->type)
201  {
202  case CHECKSUM_TYPE_NONE:
203  break;
205  FIN_CRC32C(context->raw_context.c_crc32c);
206  retval = sizeof(pg_crc32c);
207  memcpy(output, &context->raw_context.c_crc32c, retval);
208  break;
210  if (pg_cryptohash_final(context->raw_context.c_sha224, output) < 0)
211  return -1;
213  retval = PG_SHA224_DIGEST_LENGTH;
214  break;
216  if (pg_cryptohash_final(context->raw_context.c_sha256, output) < 0)
217  return -1;
219  retval = PG_SHA224_DIGEST_LENGTH;
220  break;
222  if (pg_cryptohash_final(context->raw_context.c_sha384, output) < 0)
223  return -1;
225  retval = PG_SHA384_DIGEST_LENGTH;
226  break;
228  if (pg_cryptohash_final(context->raw_context.c_sha512, output) < 0)
229  return -1;
231  retval = PG_SHA512_DIGEST_LENGTH;
232  break;
233  }
234 
235  Assert(retval <= PG_CHECKSUM_MAX_LENGTH);
236  return retval;
237 }
#define INIT_CRC32C(crc)
Definition: pg_crc32c.h:41
char * pg_checksum_type_name(pg_checksum_type type)
pg_cryptohash_ctx * c_sha224
static void output(uint64 loop_count)
uint32 pg_crc32c
Definition: pg_crc32c.h:38
pg_checksum_raw_context raw_context
#define PG_SHA256_DIGEST_LENGTH
Definition: sha2.h:23
unsigned char uint8
Definition: c.h:427
bool pg_checksum_parse_type(char *name, pg_checksum_type *type)
pg_cryptohash_ctx * c_sha384
#define PG_SHA512_DIGEST_LENGTH
Definition: sha2.h:29
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
#define PG_CHECKSUM_MAX_LENGTH
#define StaticAssertStmt(condition, errmessage)
Definition: c.h:914
pg_checksum_type
int pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest)
Definition: cryptohash.c:153
pg_cryptohash_ctx * c_sha256
int pg_checksum_final(pg_checksum_context *context, uint8 *output)
int pg_checksum_init(pg_checksum_context *context, pg_checksum_type type)
pg_cryptohash_ctx * pg_cryptohash_create(pg_cryptohash_type type)
Definition: cryptohash.c:48
#define Assert(condition)
Definition: c.h:800
int pg_cryptohash_init(pg_cryptohash_ctx *ctx)
Definition: cryptohash.c:91
int pg_checksum_update(pg_checksum_context *context, const uint8 *input, size_t len)
pg_cryptohash_ctx * c_sha512
const char * name
Definition: encode.c:561
int pg_cryptohash_update(pg_cryptohash_ctx *ctx, const uint8 *data, size_t len)
Definition: cryptohash.c:122
void pg_cryptohash_free(pg_cryptohash_ctx *ctx)
Definition: cryptohash.c:183
#define COMP_CRC32C(crc, data, len)
Definition: pg_crc32c.h:89
pg_checksum_type type
#define FIN_CRC32C(crc)
Definition: pg_crc32c.h:94
#define PG_SHA224_DIGEST_LENGTH
Definition: sha2.h:20
#define PG_SHA384_DIGEST_LENGTH
Definition: sha2.h:26