1 /*-------------------------------------------------------------------------
4 * Implements Keyed-Hashing for Message Authentication (HMAC)
6 * Fallback implementation of HMAC, as specified in RFC 2104.
8 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
9 * Portions Copyright (c) 1994, Regents of the University of California
14 *-------------------------------------------------------------------------
20 #include "postgres_fe.h"
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"
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.
34 #define ALLOC(size) palloc(size)
35 #define FREE(ptr) pfree(ptr)
37 #define ALLOC(size) malloc(size)
38 #define FREE(ptr) free(ptr)
42 * Internal structure for pg_hmac_ctx->data with this implementation.
46 pg_cryptohash_ctx
*hash
;
47 pg_cryptohash_type type
;
52 * Use the largest block size among supported options. This wastes some
53 * memory but simplifies the allocation logic.
55 uint8 k_ipad
[PG_SHA512_BLOCK_LENGTH
];
56 uint8 k_opad
[PG_SHA512_BLOCK_LENGTH
];
59 #define HMAC_IPAD 0x36
60 #define HMAC_OPAD 0x5C
65 * Allocate a hash context. Returns NULL on failure for an OOM. The
66 * backend issues an error, without returning.
69 pg_hmac_create(pg_cryptohash_type type
)
73 ctx
= ALLOC(sizeof(pg_hmac_ctx
));
76 memset(ctx
, 0, sizeof(pg_hmac_ctx
));
80 * Initialize the context data. This requires to know the digest and
81 * block lengths, that depend on the type of hash used.
86 ctx
->digest_size
= MD5_DIGEST_LENGTH
;
87 ctx
->block_size
= MD5_BLOCK_SIZE
;
90 ctx
->digest_size
= SHA1_DIGEST_LENGTH
;
91 ctx
->block_size
= SHA1_BLOCK_SIZE
;
94 ctx
->digest_size
= PG_SHA224_DIGEST_LENGTH
;
95 ctx
->block_size
= PG_SHA224_BLOCK_LENGTH
;
98 ctx
->digest_size
= PG_SHA256_DIGEST_LENGTH
;
99 ctx
->block_size
= PG_SHA256_BLOCK_LENGTH
;
102 ctx
->digest_size
= PG_SHA384_DIGEST_LENGTH
;
103 ctx
->block_size
= PG_SHA384_BLOCK_LENGTH
;
106 ctx
->digest_size
= PG_SHA512_DIGEST_LENGTH
;
107 ctx
->block_size
= PG_SHA512_BLOCK_LENGTH
;
111 ctx
->hash
= pg_cryptohash_create(type
);
112 if (ctx
->hash
== NULL
)
114 explicit_bzero(ctx
, sizeof(pg_hmac_ctx
));
125 * Initialize a HMAC context. Returns 0 on success, -1 on failure.
128 pg_hmac_init(pg_hmac_ctx
*ctx
, const uint8
*key
, size_t len
)
133 uint8
*shrinkbuf
= NULL
;
138 digest_size
= ctx
->digest_size
;
139 block_size
= ctx
->block_size
;
141 memset(ctx
->k_opad
, HMAC_OPAD
, ctx
->block_size
);
142 memset(ctx
->k_ipad
, HMAC_IPAD
, ctx
->block_size
);
145 * If the key is longer than the block size, pass it through the hash once
148 if (len
> block_size
)
150 pg_cryptohash_ctx
*hash_ctx
;
152 /* temporary buffer for one-time shrink */
153 shrinkbuf
= ALLOC(digest_size
);
154 if (shrinkbuf
== NULL
)
156 memset(shrinkbuf
, 0, digest_size
);
158 hash_ctx
= pg_cryptohash_create(ctx
->type
);
159 if (hash_ctx
== NULL
)
165 if (pg_cryptohash_init(hash_ctx
) < 0 ||
166 pg_cryptohash_update(hash_ctx
, key
, len
) < 0 ||
167 pg_cryptohash_final(hash_ctx
, shrinkbuf
, digest_size
) < 0)
169 pg_cryptohash_free(hash_ctx
);
176 pg_cryptohash_free(hash_ctx
);
179 for (i
= 0; i
< len
; i
++)
181 ctx
->k_ipad
[i
] ^= key
[i
];
182 ctx
->k_opad
[i
] ^= key
[i
];
185 /* tmp = H(K XOR ipad, text) */
186 if (pg_cryptohash_init(ctx
->hash
) < 0 ||
187 pg_cryptohash_update(ctx
->hash
, ctx
->k_ipad
, ctx
->block_size
) < 0)
202 * Update a HMAC context. Returns 0 on success, -1 on failure.
205 pg_hmac_update(pg_hmac_ctx
*ctx
, const uint8
*data
, size_t len
)
210 if (pg_cryptohash_update(ctx
->hash
, data
, len
) < 0)
219 * Finalize a HMAC context. Returns 0 on success, -1 on failure.
222 pg_hmac_final(pg_hmac_ctx
*ctx
, uint8
*dest
, size_t len
)
229 h
= ALLOC(ctx
->digest_size
);
232 memset(h
, 0, ctx
->digest_size
);
234 if (pg_cryptohash_final(ctx
->hash
, h
, ctx
->digest_size
) < 0)
240 /* H(K XOR opad, tmp) */
241 if (pg_cryptohash_init(ctx
->hash
) < 0 ||
242 pg_cryptohash_update(ctx
->hash
, ctx
->k_opad
, ctx
->block_size
) < 0 ||
243 pg_cryptohash_update(ctx
->hash
, h
, ctx
->digest_size
) < 0 ||
244 pg_cryptohash_final(ctx
->hash
, dest
, len
) < 0)
257 * Free a HMAC context.
260 pg_hmac_free(pg_hmac_ctx
*ctx
)
265 pg_cryptohash_free(ctx
->hash
);
266 explicit_bzero(ctx
, sizeof(pg_hmac_ctx
));