PostgreSQL Source Code  git master
scram-common.c File Reference
#include "postgres.h"
#include "common/base64.h"
#include "common/hmac.h"
#include "common/scram-common.h"
#include "port/pg_bswap.h"
Include dependency graph for scram-common.c:

Go to the source code of this file.

Functions

int scram_SaltedPassword (const char *password, pg_cryptohash_type hash_type, int key_length, const char *salt, int saltlen, int iterations, uint8 *result, const char **errstr)
 
int scram_H (const uint8 *input, pg_cryptohash_type hash_type, int key_length, uint8 *result, const char **errstr)
 
int scram_ClientKey (const uint8 *salted_password, pg_cryptohash_type hash_type, int key_length, uint8 *result, const char **errstr)
 
int scram_ServerKey (const uint8 *salted_password, pg_cryptohash_type hash_type, int key_length, uint8 *result, const char **errstr)
 
char * scram_build_secret (pg_cryptohash_type hash_type, int key_length, const char *salt, int saltlen, int iterations, const char *password, const char **errstr)
 

Function Documentation

◆ scram_build_secret()

char* scram_build_secret ( pg_cryptohash_type  hash_type,
int  key_length,
const char *  salt,
int  saltlen,
int  iterations,
const char *  password,
const char **  errstr 
)

Definition at line 199 of file scram-common.c.

202 {
203  uint8 salted_password[SCRAM_MAX_KEY_LEN];
204  uint8 stored_key[SCRAM_MAX_KEY_LEN];
205  uint8 server_key[SCRAM_MAX_KEY_LEN];
206  char *result;
207  char *p;
208  int maxlen;
209  int encoded_salt_len;
210  int encoded_stored_len;
211  int encoded_server_len;
212  int encoded_result;
213 
214  /* Only this hash method is supported currently */
215  Assert(hash_type == PG_SHA256);
216 
217  if (iterations <= 0)
218  iterations = SCRAM_DEFAULT_ITERATIONS;
219 
220  /* Calculate StoredKey and ServerKey */
221  if (scram_SaltedPassword(password, hash_type, key_length,
222  salt, saltlen, iterations,
223  salted_password, errstr) < 0 ||
224  scram_ClientKey(salted_password, hash_type, key_length,
225  stored_key, errstr) < 0 ||
226  scram_H(stored_key, hash_type, key_length,
227  stored_key, errstr) < 0 ||
228  scram_ServerKey(salted_password, hash_type, key_length,
229  server_key, errstr) < 0)
230  {
231  /* errstr is filled already here */
232 #ifdef FRONTEND
233  return NULL;
234 #else
235  elog(ERROR, "could not calculate stored key and server key: %s",
236  *errstr);
237 #endif
238  }
239 
240  /*----------
241  * The format is:
242  * SCRAM-SHA-256$<iteration count>:<salt>$<StoredKey>:<ServerKey>
243  *----------
244  */
245  encoded_salt_len = pg_b64_enc_len(saltlen);
246  encoded_stored_len = pg_b64_enc_len(key_length);
247  encoded_server_len = pg_b64_enc_len(key_length);
248 
249  maxlen = strlen("SCRAM-SHA-256") + 1
250  + 10 + 1 /* iteration count */
251  + encoded_salt_len + 1 /* Base64-encoded salt */
252  + encoded_stored_len + 1 /* Base64-encoded StoredKey */
253  + encoded_server_len + 1; /* Base64-encoded ServerKey */
254 
255 #ifdef FRONTEND
256  result = malloc(maxlen);
257  if (!result)
258  {
259  *errstr = _("out of memory");
260  return NULL;
261  }
262 #else
263  result = palloc(maxlen);
264 #endif
265 
266  p = result + sprintf(result, "SCRAM-SHA-256$%d:", iterations);
267 
268  /* salt */
269  encoded_result = pg_b64_encode(salt, saltlen, p, encoded_salt_len);
270  if (encoded_result < 0)
271  {
272  *errstr = _("could not encode salt");
273 #ifdef FRONTEND
274  free(result);
275  return NULL;
276 #else
277  elog(ERROR, "%s", *errstr);
278 #endif
279  }
280  p += encoded_result;
281  *(p++) = '$';
282 
283  /* stored key */
284  encoded_result = pg_b64_encode((char *) stored_key, key_length, p,
285  encoded_stored_len);
286  if (encoded_result < 0)
287  {
288  *errstr = _("could not encode stored key");
289 #ifdef FRONTEND
290  free(result);
291  return NULL;
292 #else
293  elog(ERROR, "%s", *errstr);
294 #endif
295  }
296 
297  p += encoded_result;
298  *(p++) = ':';
299 
300  /* server key */
301  encoded_result = pg_b64_encode((char *) server_key, key_length, p,
302  encoded_server_len);
303  if (encoded_result < 0)
304  {
305  *errstr = _("could not encode server key");
306 #ifdef FRONTEND
307  free(result);
308  return NULL;
309 #else
310  elog(ERROR, "%s", *errstr);
311 #endif
312  }
313 
314  p += encoded_result;
315  *(p++) = '\0';
316 
317  Assert(p - result <= maxlen);
318 
319  return result;
320 }
int pg_b64_enc_len(int srclen)
Definition: base64.c:224
int pg_b64_encode(const char *src, int len, char *dst, int dstlen)
Definition: base64.c:49
unsigned char uint8
Definition: c.h:488
@ PG_SHA256
Definition: cryptohash.h:24
#define _(x)
Definition: elog.c:91
#define ERROR
Definition: elog.h:39
#define free(a)
Definition: header.h:65
#define malloc(a)
Definition: header.h:50
Assert(fmt[strlen(fmt) - 1] !='\n')
void * palloc(Size size)
Definition: mcxt.c:1210
#define sprintf
Definition: port.h:240
int scram_ServerKey(const uint8 *salted_password, pg_cryptohash_type hash_type, int key_length, uint8 *result, const char **errstr)
Definition: scram-common.c:161
int scram_SaltedPassword(const char *password, pg_cryptohash_type hash_type, int key_length, const char *salt, int saltlen, int iterations, uint8 *result, const char **errstr)
Definition: scram-common.c:35
int scram_ClientKey(const uint8 *salted_password, pg_cryptohash_type hash_type, int key_length, uint8 *result, const char **errstr)
Definition: scram-common.c:131
int scram_H(const uint8 *input, pg_cryptohash_type hash_type, int key_length, uint8 *result, const char **errstr)
Definition: scram-common.c:101
#define SCRAM_DEFAULT_ITERATIONS
Definition: scram-common.h:50
#define SCRAM_MAX_KEY_LEN
Definition: scram-common.h:30
static char * password
Definition: streamutil.c:53

References _, Assert(), elog(), ERROR, free, malloc, palloc(), password, pg_b64_enc_len(), pg_b64_encode(), PG_SHA256, scram_ClientKey(), SCRAM_DEFAULT_ITERATIONS, scram_H(), SCRAM_MAX_KEY_LEN, scram_SaltedPassword(), scram_ServerKey(), and sprintf.

Referenced by pg_be_scram_build_secret(), and pg_fe_scram_build_secret().

◆ scram_ClientKey()

int scram_ClientKey ( const uint8 salted_password,
pg_cryptohash_type  hash_type,
int  key_length,
uint8 result,
const char **  errstr 
)

Definition at line 131 of file scram-common.c.

134 {
135  pg_hmac_ctx *ctx = pg_hmac_create(hash_type);
136 
137  if (ctx == NULL)
138  {
139  *errstr = pg_hmac_error(NULL); /* returns OOM */
140  return -1;
141  }
142 
143  if (pg_hmac_init(ctx, salted_password, key_length) < 0 ||
144  pg_hmac_update(ctx, (uint8 *) "Client Key", strlen("Client Key")) < 0 ||
145  pg_hmac_final(ctx, result, key_length) < 0)
146  {
147  *errstr = pg_hmac_error(ctx);
148  pg_hmac_free(ctx);
149  return -1;
150  }
151 
152  pg_hmac_free(ctx);
153  return 0;
154 }
pg_hmac_ctx * pg_hmac_create(pg_cryptohash_type type)
Definition: hmac.c:77
const char * pg_hmac_error(pg_hmac_ctx *ctx)
Definition: hmac.c:306
void pg_hmac_free(pg_hmac_ctx *ctx)
Definition: hmac.c:289
int pg_hmac_update(pg_hmac_ctx *ctx, const uint8 *data, size_t len)
Definition: hmac.c:223
int pg_hmac_init(pg_hmac_ctx *ctx, const uint8 *key, size_t len)
Definition: hmac.c:138
int pg_hmac_final(pg_hmac_ctx *ctx, uint8 *dest, size_t len)
Definition: hmac.c:244

References pg_hmac_create(), pg_hmac_error(), pg_hmac_final(), pg_hmac_free(), pg_hmac_init(), and pg_hmac_update().

Referenced by calculate_client_proof(), and scram_build_secret().

◆ scram_H()

int scram_H ( const uint8 input,
pg_cryptohash_type  hash_type,
int  key_length,
uint8 result,
const char **  errstr 
)

Definition at line 101 of file scram-common.c.

103 {
104  pg_cryptohash_ctx *ctx;
105 
106  ctx = pg_cryptohash_create(hash_type);
107  if (ctx == NULL)
108  {
109  *errstr = pg_cryptohash_error(NULL); /* returns OOM */
110  return -1;
111  }
112 
113  if (pg_cryptohash_init(ctx) < 0 ||
114  pg_cryptohash_update(ctx, input, key_length) < 0 ||
115  pg_cryptohash_final(ctx, result, key_length) < 0)
116  {
117  *errstr = pg_cryptohash_error(ctx);
118  pg_cryptohash_free(ctx);
119  return -1;
120  }
121 
122  pg_cryptohash_free(ctx);
123  return 0;
124 }
int pg_cryptohash_update(pg_cryptohash_ctx *ctx, const uint8 *data, size_t len)
Definition: cryptohash.c:139
int pg_cryptohash_init(pg_cryptohash_ctx *ctx)
Definition: cryptohash.c:101
void pg_cryptohash_free(pg_cryptohash_ctx *ctx)
Definition: cryptohash.c:243
pg_cryptohash_ctx * pg_cryptohash_create(pg_cryptohash_type type)
Definition: cryptohash.c:74
int pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest, size_t len)
Definition: cryptohash.c:177
const char * pg_cryptohash_error(pg_cryptohash_ctx *ctx)
Definition: cryptohash.c:259

References pg_cryptohash_create(), pg_cryptohash_error(), pg_cryptohash_final(), pg_cryptohash_free(), pg_cryptohash_init(), and pg_cryptohash_update().

Referenced by calculate_client_proof(), scram_build_secret(), and verify_client_proof().

◆ scram_SaltedPassword()

int scram_SaltedPassword ( const char *  password,
pg_cryptohash_type  hash_type,
int  key_length,
const char *  salt,
int  saltlen,
int  iterations,
uint8 result,
const char **  errstr 
)

Definition at line 35 of file scram-common.c.

39 {
40  int password_len = strlen(password);
41  uint32 one = pg_hton32(1);
42  int i,
43  j;
45  uint8 Ui_prev[SCRAM_MAX_KEY_LEN];
46  pg_hmac_ctx *hmac_ctx = pg_hmac_create(hash_type);
47 
48  if (hmac_ctx == NULL)
49  {
50  *errstr = pg_hmac_error(NULL); /* returns OOM */
51  return -1;
52  }
53 
54  /*
55  * Iterate hash calculation of HMAC entry using given salt. This is
56  * essentially PBKDF2 (see RFC2898) with HMAC() as the pseudorandom
57  * function.
58  */
59 
60  /* First iteration */
61  if (pg_hmac_init(hmac_ctx, (uint8 *) password, password_len) < 0 ||
62  pg_hmac_update(hmac_ctx, (uint8 *) salt, saltlen) < 0 ||
63  pg_hmac_update(hmac_ctx, (uint8 *) &one, sizeof(uint32)) < 0 ||
64  pg_hmac_final(hmac_ctx, Ui_prev, key_length) < 0)
65  {
66  *errstr = pg_hmac_error(hmac_ctx);
67  pg_hmac_free(hmac_ctx);
68  return -1;
69  }
70 
71  memcpy(result, Ui_prev, key_length);
72 
73  /* Subsequent iterations */
74  for (i = 2; i <= iterations; i++)
75  {
76  if (pg_hmac_init(hmac_ctx, (uint8 *) password, password_len) < 0 ||
77  pg_hmac_update(hmac_ctx, (uint8 *) Ui_prev, key_length) < 0 ||
78  pg_hmac_final(hmac_ctx, Ui, key_length) < 0)
79  {
80  *errstr = pg_hmac_error(hmac_ctx);
81  pg_hmac_free(hmac_ctx);
82  return -1;
83  }
84 
85  for (j = 0; j < key_length; j++)
86  result[j] ^= Ui[j];
87  memcpy(Ui_prev, Ui, key_length);
88  }
89 
90  pg_hmac_free(hmac_ctx);
91  return 0;
92 }
unsigned int uint32
Definition: c.h:490
int j
Definition: isn.c:74
int i
Definition: isn.c:73
#define pg_hton32(x)
Definition: pg_bswap.h:121

References i, j, password, pg_hmac_create(), pg_hmac_error(), pg_hmac_final(), pg_hmac_free(), pg_hmac_init(), pg_hmac_update(), pg_hton32, and SCRAM_MAX_KEY_LEN.

Referenced by calculate_client_proof(), scram_build_secret(), and scram_verify_plain_password().

◆ scram_ServerKey()

int scram_ServerKey ( const uint8 salted_password,
pg_cryptohash_type  hash_type,
int  key_length,
uint8 result,
const char **  errstr 
)

Definition at line 161 of file scram-common.c.

164 {
165  pg_hmac_ctx *ctx = pg_hmac_create(hash_type);
166 
167  if (ctx == NULL)
168  {
169  *errstr = pg_hmac_error(NULL); /* returns OOM */
170  return -1;
171  }
172 
173  if (pg_hmac_init(ctx, salted_password, key_length) < 0 ||
174  pg_hmac_update(ctx, (uint8 *) "Server Key", strlen("Server Key")) < 0 ||
175  pg_hmac_final(ctx, result, key_length) < 0)
176  {
177  *errstr = pg_hmac_error(ctx);
178  pg_hmac_free(ctx);
179  return -1;
180  }
181 
182  pg_hmac_free(ctx);
183  return 0;
184 }

References pg_hmac_create(), pg_hmac_error(), pg_hmac_final(), pg_hmac_free(), pg_hmac_init(), and pg_hmac_update().

Referenced by scram_build_secret(), scram_verify_plain_password(), and verify_server_signature().