PostgreSQL Source Code git master
Loading...
Searching...
No Matches
hmac.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * hmac.c
4 * Implements Keyed-Hashing for Message Authentication (HMAC)
5 *
6 * Fallback implementation of HMAC, as specified in RFC 2104.
7 *
8 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
9 * Portions Copyright (c) 1994, Regents of the University of California
10 *
11 * IDENTIFICATION
12 * src/common/hmac.c
13 *
14 *-------------------------------------------------------------------------
15 */
16
17#ifndef FRONTEND
18#include "postgres.h"
19#else
20#include "postgres_fe.h"
21#endif
22
23#include "common/cryptohash.h"
24#include "common/hmac.h"
25#include "common/md5.h"
26#include "common/sha1.h"
27#include "common/sha2.h"
28
29/*
30 * In backend, use palloc/pfree to ease the error handling. In frontend,
31 * use malloc to be able to return a failure status back to the caller.
32 */
33#ifndef FRONTEND
34#define ALLOC(size) palloc(size)
35#define FREE(ptr) pfree(ptr)
36#else
37#define ALLOC(size) malloc(size)
38#define FREE(ptr) free(ptr)
39#endif
40
41/* Set of error states */
48
49/* Internal pg_hmac_ctx structure */
51{
55 const char *errreason;
58
59 /*
60 * Use the largest block size among supported options. This wastes some
61 * memory but simplifies the allocation logic.
62 */
65};
66
67#define HMAC_IPAD 0x36
68#define HMAC_OPAD 0x5C
69
70/*
71 * pg_hmac_create
72 *
73 * Allocate a hash context. Returns NULL on failure for an OOM. The
74 * backend issues an error, without returning.
75 */
78{
79 pg_hmac_ctx *ctx;
80
81 ctx = ALLOC(sizeof(pg_hmac_ctx));
82 if (ctx == NULL)
83 return NULL;
84 memset(ctx, 0, sizeof(pg_hmac_ctx));
85 ctx->type = type;
87 ctx->errreason = NULL;
88
89 /*
90 * Initialize the context data. This requires to know the digest and
91 * block lengths, that depend on the type of hash used.
92 */
93 switch (type)
94 {
95 case PG_MD5:
98 break;
99 case PG_SHA1:
102 break;
103 case PG_SHA224:
106 break;
107 case PG_SHA256:
110 break;
111 case PG_SHA384:
114 break;
115 case PG_SHA512:
118 break;
119 }
120
122 if (ctx->hash == NULL)
123 {
124 explicit_bzero(ctx, sizeof(pg_hmac_ctx));
125 FREE(ctx);
126 return NULL;
127 }
128
129 return ctx;
130}
131
132/*
133 * pg_hmac_init
134 *
135 * Initialize a HMAC context. Returns 0 on success, -1 on failure.
136 */
137int
138pg_hmac_init(pg_hmac_ctx *ctx, const uint8 *key, size_t len)
139{
140 int digest_size;
141 int block_size;
143
144 if (ctx == NULL)
145 return -1;
146
147 digest_size = ctx->digest_size;
148 block_size = ctx->block_size;
149
150 memset(ctx->k_opad, HMAC_OPAD, ctx->block_size);
151 memset(ctx->k_ipad, HMAC_IPAD, ctx->block_size);
152
153 /*
154 * If the key is longer than the block size, pass it through the hash once
155 * to shrink it down.
156 */
157 if (len > block_size)
158 {
160
161 /* temporary buffer for one-time shrink */
162 shrinkbuf = ALLOC(digest_size);
163 if (shrinkbuf == NULL)
164 {
166 return -1;
167 }
168 memset(shrinkbuf, 0, digest_size);
169
171 if (hash_ctx == NULL)
172 {
175 return -1;
176 }
177
178 if (pg_cryptohash_init(hash_ctx) < 0 ||
179 pg_cryptohash_update(hash_ctx, key, len) < 0 ||
180 pg_cryptohash_final(hash_ctx, shrinkbuf, digest_size) < 0)
181 {
186 return -1;
187 }
188
189 key = shrinkbuf;
190 len = digest_size;
192 }
193
194 for (size_t i = 0; i < len; i++)
195 {
196 ctx->k_ipad[i] ^= key[i];
197 ctx->k_opad[i] ^= key[i];
198 }
199
200 /* tmp = H(K XOR ipad, text) */
201 if (pg_cryptohash_init(ctx->hash) < 0 ||
202 pg_cryptohash_update(ctx->hash, ctx->k_ipad, ctx->block_size) < 0)
203 {
206 if (shrinkbuf)
208 return -1;
209 }
210
211 if (shrinkbuf)
213 return 0;
214}
215
216/*
217 * pg_hmac_update
218 *
219 * Update a HMAC context. Returns 0 on success, -1 on failure.
220 */
221int
223{
224 if (ctx == NULL)
225 return -1;
226
227 if (pg_cryptohash_update(ctx->hash, data, len) < 0)
228 {
231 return -1;
232 }
233
234 return 0;
235}
236
237/*
238 * pg_hmac_final
239 *
240 * Finalize a HMAC context. Returns 0 on success, -1 on failure.
241 */
242int
243pg_hmac_final(pg_hmac_ctx *ctx, uint8 *dest, size_t len)
244{
245 uint8 *h;
246
247 if (ctx == NULL)
248 return -1;
249
250 h = ALLOC(ctx->digest_size);
251 if (h == NULL)
252 {
254 return -1;
255 }
256 memset(h, 0, ctx->digest_size);
257
258 if (pg_cryptohash_final(ctx->hash, h, ctx->digest_size) < 0)
259 {
262 FREE(h);
263 return -1;
264 }
265
266 /* H(K XOR opad, tmp) */
267 if (pg_cryptohash_init(ctx->hash) < 0 ||
268 pg_cryptohash_update(ctx->hash, ctx->k_opad, ctx->block_size) < 0 ||
269 pg_cryptohash_update(ctx->hash, h, ctx->digest_size) < 0 ||
270 pg_cryptohash_final(ctx->hash, dest, len) < 0)
271 {
274 FREE(h);
275 return -1;
276 }
277
278 FREE(h);
279 return 0;
280}
281
282/*
283 * pg_hmac_free
284 *
285 * Free a HMAC context.
286 */
287void
289{
290 if (ctx == NULL)
291 return;
292
294 explicit_bzero(ctx, sizeof(pg_hmac_ctx));
295 FREE(ctx);
296}
297
298/*
299 * pg_hmac_error
300 *
301 * Returns a static string providing details about an error that happened
302 * during a HMAC computation.
303 */
304const char *
306{
307 if (ctx == NULL)
308 return _("out of memory");
309
310 /*
311 * If a reason is provided, rely on it, else fallback to any error code
312 * set.
313 */
314 if (ctx->errreason)
315 return ctx->errreason;
316
317 switch (ctx->error)
318 {
320 return _("success");
322 return _("internal error");
324 return _("out of memory");
325 }
326
327 Assert(false); /* cannot be reached */
328 return _("success");
329}
uint8_t uint8
Definition c.h:681
#define Assert(condition)
Definition c.h:1002
const char * pg_cryptohash_error(pg_cryptohash_ctx *ctx)
Definition cryptohash.c:254
int pg_cryptohash_update(pg_cryptohash_ctx *ctx, const uint8 *data, size_t len)
Definition cryptohash.c:136
pg_cryptohash_ctx * pg_cryptohash_create(pg_cryptohash_type type)
Definition cryptohash.c:74
int pg_cryptohash_init(pg_cryptohash_ctx *ctx)
Definition cryptohash.c:100
void pg_cryptohash_free(pg_cryptohash_ctx *ctx)
Definition cryptohash.c:238
int pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest, size_t len)
Definition cryptohash.c:172
pg_cryptohash_type
Definition cryptohash.h:20
@ PG_SHA512
Definition cryptohash.h:26
@ PG_SHA224
Definition cryptohash.h:23
@ PG_SHA384
Definition cryptohash.h:25
@ PG_SHA1
Definition cryptohash.h:22
@ PG_SHA256
Definition cryptohash.h:24
@ PG_MD5
Definition cryptohash.h:21
#define _(x)
Definition elog.c:96
static int block_size
Definition guc_tables.c:644
#define FREE(ptr)
Definition hmac.c:35
#define HMAC_OPAD
Definition hmac.c:68
pg_hmac_ctx * pg_hmac_create(pg_cryptohash_type type)
Definition hmac.c:77
void pg_hmac_free(pg_hmac_ctx *ctx)
Definition hmac.c:288
const char * pg_hmac_error(pg_hmac_ctx *ctx)
Definition hmac.c:305
int pg_hmac_update(pg_hmac_ctx *ctx, const uint8 *data, size_t len)
Definition hmac.c:222
int pg_hmac_init(pg_hmac_ctx *ctx, const uint8 *key, size_t len)
Definition hmac.c:138
#define ALLOC(size)
Definition hmac.c:34
#define HMAC_IPAD
Definition hmac.c:67
pg_hmac_errno
Definition hmac.c:43
@ PG_HMAC_ERROR_INTERNAL
Definition hmac.c:46
@ PG_HMAC_ERROR_OOM
Definition hmac.c:45
@ PG_HMAC_ERROR_NONE
Definition hmac.c:44
int pg_hmac_final(pg_hmac_ctx *ctx, uint8 *dest, size_t len)
Definition hmac.c:243
pg_hmac_errno
int i
Definition isn.c:77
#define MD5_DIGEST_LENGTH
Definition md5.h:20
#define MD5_BLOCK_SIZE
Definition md5.h:22
const void size_t len
const void * data
void explicit_bzero(void *buf, size_t len)
static int fb(int x)
#define SHA1_DIGEST_LENGTH
Definition sha1.h:17
#define SHA1_BLOCK_SIZE
Definition sha1.h:19
#define PG_SHA256_DIGEST_LENGTH
Definition sha2.h:23
#define PG_SHA384_BLOCK_LENGTH
Definition sha2.h:25
#define PG_SHA384_DIGEST_LENGTH
Definition sha2.h:26
#define PG_SHA512_DIGEST_LENGTH
Definition sha2.h:29
#define PG_SHA256_BLOCK_LENGTH
Definition sha2.h:22
#define PG_SHA512_BLOCK_LENGTH
Definition sha2.h:28
#define PG_SHA224_BLOCK_LENGTH
Definition sha2.h:19
#define PG_SHA224_DIGEST_LENGTH
Definition sha2.h:20
const char * errreason
Definition hmac.c:55
uint8 k_opad[PG_SHA512_BLOCK_LENGTH]
Definition hmac.c:64
pg_cryptohash_ctx * hash
Definition hmac.c:52
int digest_size
Definition hmac.c:57
uint8 k_ipad[PG_SHA512_BLOCK_LENGTH]
Definition hmac.c:63
int block_size
Definition hmac.c:56
pg_cryptohash_type type
Definition hmac.c:53
pg_hmac_errno error
Definition hmac.c:54
const char * type