PostgreSQL Source Code  git master
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-2020, 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 /*
42  * Internal structure for pg_hmac_ctx->data with this implementation.
43  */
45 {
50 
51  /*
52  * Use the largest block size among supported options. This wastes some
53  * memory but simplifies the allocation logic.
54  */
57 };
58 
59 #define HMAC_IPAD 0x36
60 #define HMAC_OPAD 0x5C
61 
62 /*
63  * pg_hmac_create
64  *
65  * Allocate a hash context. Returns NULL on failure for an OOM. The
66  * backend issues an error, without returning.
67  */
70 {
71  pg_hmac_ctx *ctx;
72 
73  ctx = ALLOC(sizeof(pg_hmac_ctx));
74  if (ctx == NULL)
75  return NULL;
76  memset(ctx, 0, sizeof(pg_hmac_ctx));
77  ctx->type = type;
78 
79  /*
80  * Initialize the context data. This requires to know the digest and
81  * block lengths, that depend on the type of hash used.
82  */
83  switch (type)
84  {
85  case PG_MD5:
88  break;
89  case PG_SHA1:
92  break;
93  case PG_SHA224:
96  break;
97  case PG_SHA256:
100  break;
101  case PG_SHA384:
104  break;
105  case PG_SHA512:
108  break;
109  }
110 
111  ctx->hash = pg_cryptohash_create(type);
112  if (ctx->hash == NULL)
113  {
114  explicit_bzero(ctx, sizeof(pg_hmac_ctx));
115  FREE(ctx);
116  return NULL;
117  }
118 
119  return ctx;
120 }
121 
122 /*
123  * pg_hmac_init
124  *
125  * Initialize a HMAC context. Returns 0 on success, -1 on failure.
126  */
127 int
128 pg_hmac_init(pg_hmac_ctx *ctx, const uint8 *key, size_t len)
129 {
130  int i;
131  int digest_size;
132  int block_size;
133  uint8 *shrinkbuf = NULL;
134 
135  if (ctx == NULL)
136  return -1;
137 
138  digest_size = ctx->digest_size;
139  block_size = ctx->block_size;
140 
141  memset(ctx->k_opad, HMAC_OPAD, ctx->block_size);
142  memset(ctx->k_ipad, HMAC_IPAD, ctx->block_size);
143 
144  /*
145  * If the key is longer than the block size, pass it through the hash once
146  * to shrink it down.
147  */
148  if (len > block_size)
149  {
150  pg_cryptohash_ctx *hash_ctx;
151 
152  /* temporary buffer for one-time shrink */
153  shrinkbuf = ALLOC(digest_size);
154  if (shrinkbuf == NULL)
155  return -1;
156  memset(shrinkbuf, 0, digest_size);
157 
158  hash_ctx = pg_cryptohash_create(ctx->type);
159  if (hash_ctx == NULL)
160  {
161  FREE(shrinkbuf);
162  return -1;
163  }
164 
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)
168  {
169  pg_cryptohash_free(hash_ctx);
170  FREE(shrinkbuf);
171  return -1;
172  }
173 
174  key = shrinkbuf;
175  len = digest_size;
176  pg_cryptohash_free(hash_ctx);
177  }
178 
179  for (i = 0; i < len; i++)
180  {
181  ctx->k_ipad[i] ^= key[i];
182  ctx->k_opad[i] ^= key[i];
183  }
184 
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)
188  {
189  if (shrinkbuf)
190  FREE(shrinkbuf);
191  return -1;
192  }
193 
194  if (shrinkbuf)
195  FREE(shrinkbuf);
196  return 0;
197 }
198 
199 /*
200  * pg_hmac_update
201  *
202  * Update a HMAC context. Returns 0 on success, -1 on failure.
203  */
204 int
205 pg_hmac_update(pg_hmac_ctx *ctx, const uint8 *data, size_t len)
206 {
207  if (ctx == NULL)
208  return -1;
209 
210  if (pg_cryptohash_update(ctx->hash, data, len) < 0)
211  return -1;
212 
213  return 0;
214 }
215 
216 /*
217  * pg_hmac_final
218  *
219  * Finalize a HMAC context. Returns 0 on success, -1 on failure.
220  */
221 int
222 pg_hmac_final(pg_hmac_ctx *ctx, uint8 *dest, size_t len)
223 {
224  uint8 *h;
225 
226  if (ctx == NULL)
227  return -1;
228 
229  h = ALLOC(ctx->digest_size);
230  if (h == NULL)
231  return -1;
232  memset(h, 0, ctx->digest_size);
233 
234  if (pg_cryptohash_final(ctx->hash, h, ctx->digest_size) < 0)
235  return -1;
236 
237  /* H(K XOR opad, tmp) */
238  if (pg_cryptohash_init(ctx->hash) < 0 ||
239  pg_cryptohash_update(ctx->hash, ctx->k_opad, ctx->block_size) < 0 ||
240  pg_cryptohash_update(ctx->hash, h, ctx->digest_size) < 0 ||
241  pg_cryptohash_final(ctx->hash, dest, len) < 0)
242  {
243  return -1;
244  }
245 
246  return 0;
247 }
248 
249 /*
250  * pg_hmac_free
251  *
252  * Free a HMAC context.
253  */
254 void
256 {
257  if (ctx == NULL)
258  return;
259 
260  pg_cryptohash_free(ctx->hash);
261  explicit_bzero(ctx, sizeof(pg_hmac_ctx));
262  FREE(ctx);
263 }
int pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest, size_t len)
Definition: cryptohash.c:168
pg_cryptohash_ctx * hash
Definition: hmac.c:46
#define MD5_BLOCK_SIZE
Definition: internal.c:45
#define PG_SHA384_BLOCK_LENGTH
Definition: sha2.h:23
#define SHA1_DIGEST_LENGTH
Definition: sha1.h:17
#define PG_SHA256_DIGEST_LENGTH
Definition: sha2.h:22
unsigned char uint8
Definition: c.h:439
#define PG_SHA512_DIGEST_LENGTH
Definition: sha2.h:26
pg_hmac_ctx * pg_hmac_create(pg_cryptohash_type type)
Definition: hmac.c:69
#define FREE(ptr)
Definition: hmac.c:35
uint8 k_ipad[PG_SHA512_BLOCK_LENGTH]
Definition: hmac.c:55
#define SHA1_BLOCK_SIZE
Definition: internal.c:44
#define PG_SHA256_BLOCK_LENGTH
Definition: sha2.h:21
#define MD5_DIGEST_LENGTH
Definition: md5.h:20
int pg_hmac_update(pg_hmac_ctx *ctx, const uint8 *data, size_t len)
Definition: hmac.c:205
#define PG_SHA512_BLOCK_LENGTH
Definition: sha2.h:25
uint8 k_opad[PG_SHA512_BLOCK_LENGTH]
Definition: hmac.c:56
#define PG_SHA224_BLOCK_LENGTH
Definition: sha2.h:19
int digest_size
Definition: hmac.c:49
int pg_hmac_init(pg_hmac_ctx *ctx, const uint8 *key, size_t len)
Definition: hmac.c:128
void pg_hmac_free(pg_hmac_ctx *ctx)
Definition: hmac.c:255
#define ALLOC(size)
Definition: hmac.c:34
pg_cryptohash_ctx * pg_cryptohash_create(pg_cryptohash_type type)
Definition: cryptohash.c:66
#define HMAC_OPAD
Definition: hmac.c:60
int pg_cryptohash_init(pg_cryptohash_ctx *ctx)
Definition: cryptohash.c:92
int block_size
Definition: hmac.c:48
#define HMAC_IPAD
Definition: hmac.c:59
int pg_cryptohash_update(pg_cryptohash_ctx *ctx, const uint8 *data, size_t len)
Definition: cryptohash.c:130
pg_cryptohash_type type
Definition: hmac.c:47
pg_cryptohash_type
Definition: cryptohash.h:19
void explicit_bzero(void *buf, size_t len)
int i
void pg_cryptohash_free(pg_cryptohash_ctx *ctx)
Definition: cryptohash.c:216
#define PG_SHA224_DIGEST_LENGTH
Definition: sha2.h:20
#define PG_SHA384_DIGEST_LENGTH
Definition: sha2.h:24
int pg_hmac_final(pg_hmac_ctx *ctx, uint8 *dest, size_t len)
Definition: hmac.c:222