PostgreSQL Source Code  git master
scram-common.h File Reference
#include "common/cryptohash.h"
#include "common/sha2.h"
Include dependency graph for scram-common.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define SCRAM_SHA_256_NAME   "SCRAM-SHA-256"
 
#define SCRAM_SHA_256_PLUS_NAME   "SCRAM-SHA-256-PLUS" /* with channel binding */
 
#define SCRAM_KEY_LEN   PG_SHA256_DIGEST_LENGTH
 
#define SHA256_HMAC_B   PG_SHA256_BLOCK_LENGTH
 
#define SCRAM_RAW_NONCE_LEN   18
 
#define SCRAM_DEFAULT_SALT_LEN   16
 
#define SCRAM_DEFAULT_ITERATIONS   4096
 

Functions

int scram_SaltedPassword (const char *password, const char *salt, int saltlen, int iterations, uint8 *result, const char **errstr)
 
int scram_H (const uint8 *str, int len, uint8 *result, const char **errstr)
 
int scram_ClientKey (const uint8 *salted_password, uint8 *result, const char **errstr)
 
int scram_ServerKey (const uint8 *salted_password, uint8 *result, const char **errstr)
 
char * scram_build_secret (const char *salt, int saltlen, int iterations, const char *password, const char **errstr)
 

Macro Definition Documentation

◆ SCRAM_DEFAULT_ITERATIONS

#define SCRAM_DEFAULT_ITERATIONS   4096

Definition at line 47 of file scram-common.h.

◆ SCRAM_DEFAULT_SALT_LEN

#define SCRAM_DEFAULT_SALT_LEN   16

Definition at line 41 of file scram-common.h.

◆ SCRAM_KEY_LEN

#define SCRAM_KEY_LEN   PG_SHA256_DIGEST_LENGTH

Definition at line 24 of file scram-common.h.

◆ SCRAM_RAW_NONCE_LEN

#define SCRAM_RAW_NONCE_LEN   18

Definition at line 34 of file scram-common.h.

◆ SCRAM_SHA_256_NAME

#define SCRAM_SHA_256_NAME   "SCRAM-SHA-256"

Definition at line 20 of file scram-common.h.

◆ SCRAM_SHA_256_PLUS_NAME

#define SCRAM_SHA_256_PLUS_NAME   "SCRAM-SHA-256-PLUS" /* with channel binding */

Definition at line 21 of file scram-common.h.

◆ SHA256_HMAC_B

#define SHA256_HMAC_B   PG_SHA256_BLOCK_LENGTH

Definition at line 27 of file scram-common.h.

Function Documentation

◆ scram_build_secret()

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

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

197 {
198  uint8 salted_password[SCRAM_KEY_LEN];
199  uint8 stored_key[SCRAM_KEY_LEN];
200  uint8 server_key[SCRAM_KEY_LEN];
201  char *result;
202  char *p;
203  int maxlen;
204  int encoded_salt_len;
205  int encoded_stored_len;
206  int encoded_server_len;
207  int encoded_result;
208 
209  if (iterations <= 0)
210  iterations = SCRAM_DEFAULT_ITERATIONS;
211 
212  /* Calculate StoredKey and ServerKey */
213  if (scram_SaltedPassword(password, salt, saltlen, iterations,
214  salted_password, errstr) < 0 ||
215  scram_ClientKey(salted_password, stored_key, errstr) < 0 ||
216  scram_H(stored_key, SCRAM_KEY_LEN, stored_key, errstr) < 0 ||
217  scram_ServerKey(salted_password, server_key, errstr) < 0)
218  {
219  /* errstr is filled already here */
220 #ifdef FRONTEND
221  return NULL;
222 #else
223  elog(ERROR, "could not calculate stored key and server key: %s",
224  *errstr);
225 #endif
226  }
227 
228  /*----------
229  * The format is:
230  * SCRAM-SHA-256$<iteration count>:<salt>$<StoredKey>:<ServerKey>
231  *----------
232  */
233  encoded_salt_len = pg_b64_enc_len(saltlen);
234  encoded_stored_len = pg_b64_enc_len(SCRAM_KEY_LEN);
235  encoded_server_len = pg_b64_enc_len(SCRAM_KEY_LEN);
236 
237  maxlen = strlen("SCRAM-SHA-256") + 1
238  + 10 + 1 /* iteration count */
239  + encoded_salt_len + 1 /* Base64-encoded salt */
240  + encoded_stored_len + 1 /* Base64-encoded StoredKey */
241  + encoded_server_len + 1; /* Base64-encoded ServerKey */
242 
243 #ifdef FRONTEND
244  result = malloc(maxlen);
245  if (!result)
246  {
247  *errstr = _("out of memory");
248  return NULL;
249  }
250 #else
251  result = palloc(maxlen);
252 #endif
253 
254  p = result + sprintf(result, "SCRAM-SHA-256$%d:", iterations);
255 
256  /* salt */
257  encoded_result = pg_b64_encode(salt, saltlen, p, encoded_salt_len);
258  if (encoded_result < 0)
259  {
260  *errstr = _("could not encode salt");
261 #ifdef FRONTEND
262  free(result);
263  return NULL;
264 #else
265  elog(ERROR, "%s", *errstr);
266 #endif
267  }
268  p += encoded_result;
269  *(p++) = '$';
270 
271  /* stored key */
272  encoded_result = pg_b64_encode((char *) stored_key, SCRAM_KEY_LEN, p,
273  encoded_stored_len);
274  if (encoded_result < 0)
275  {
276  *errstr = _("could not encode stored key");
277 #ifdef FRONTEND
278  free(result);
279  return NULL;
280 #else
281  elog(ERROR, "%s", *errstr);
282 #endif
283  }
284 
285  p += encoded_result;
286  *(p++) = ':';
287 
288  /* server key */
289  encoded_result = pg_b64_encode((char *) server_key, SCRAM_KEY_LEN, p,
290  encoded_server_len);
291  if (encoded_result < 0)
292  {
293  *errstr = _("could not encode server key");
294 #ifdef FRONTEND
295  free(result);
296  return NULL;
297 #else
298  elog(ERROR, "%s", *errstr);
299 #endif
300  }
301 
302  p += encoded_result;
303  *(p++) = '\0';
304 
305  Assert(p - result <= maxlen);
306 
307  return result;
308 }
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:439
#define _(x)
Definition: elog.c:89
#define ERROR
Definition: elog.h:33
#define elog(elevel,...)
Definition: elog.h:218
#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:1068
#define sprintf
Definition: port.h:227
int scram_SaltedPassword(const char *password, const char *salt, int saltlen, int iterations, uint8 *result, const char **errstr)
Definition: scram-common.c:35
int scram_H(const uint8 *input, int len, uint8 *result, const char **errstr)
Definition: scram-common.c:100
int scram_ClientKey(const uint8 *salted_password, uint8 *result, const char **errstr)
Definition: scram-common.c:129
int scram_ServerKey(const uint8 *salted_password, uint8 *result, const char **errstr)
Definition: scram-common.c:158
#define SCRAM_DEFAULT_ITERATIONS
Definition: scram-common.h:47
#define SCRAM_KEY_LEN
Definition: scram-common.h:24
static char * password
Definition: streamutil.c:53

References _, Assert(), elog, ERROR, free, malloc, palloc(), password, pg_b64_enc_len(), pg_b64_encode(), scram_ClientKey(), SCRAM_DEFAULT_ITERATIONS, scram_H(), SCRAM_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,
uint8 result,
const char **  errstr 
)

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

131 {
133 
134  if (ctx == NULL)
135  {
136  *errstr = pg_hmac_error(NULL); /* returns OOM */
137  return -1;
138  }
139 
140  if (pg_hmac_init(ctx, salted_password, SCRAM_KEY_LEN) < 0 ||
141  pg_hmac_update(ctx, (uint8 *) "Client Key", strlen("Client Key")) < 0 ||
142  pg_hmac_final(ctx, result, SCRAM_KEY_LEN) < 0)
143  {
144  *errstr = pg_hmac_error(ctx);
145  pg_hmac_free(ctx);
146  return -1;
147  }
148 
149  pg_hmac_free(ctx);
150  return 0;
151 }
@ PG_SHA256
Definition: cryptohash.h:24
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(), pg_hmac_update(), PG_SHA256, and SCRAM_KEY_LEN.

Referenced by calculate_client_proof(), and scram_build_secret().

◆ scram_H()

int scram_H ( const uint8 str,
int  len,
uint8 result,
const char **  errstr 
)

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

101 {
102  pg_cryptohash_ctx *ctx;
103 
105  if (ctx == NULL)
106  {
107  *errstr = pg_cryptohash_error(NULL); /* returns OOM */
108  return -1;
109  }
110 
111  if (pg_cryptohash_init(ctx) < 0 ||
112  pg_cryptohash_update(ctx, input, len) < 0 ||
113  pg_cryptohash_final(ctx, result, SCRAM_KEY_LEN) < 0)
114  {
115  *errstr = pg_cryptohash_error(ctx);
116  pg_cryptohash_free(ctx);
117  return -1;
118  }
119 
120  pg_cryptohash_free(ctx);
121  return 0;
122 }
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
const void size_t len

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

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

◆ scram_SaltedPassword()

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

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

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

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

◆ scram_ServerKey()

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

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

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

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

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