PostgreSQL Source Code  git master
scram-common.c File Reference
#include "postgres.h"
#include "common/base64.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.

Macros

#define HMAC_IPAD   0x36
 
#define HMAC_OPAD   0x5C
 

Functions

void scram_HMAC_init (scram_HMAC_ctx *ctx, const uint8 *key, int keylen)
 
void scram_HMAC_update (scram_HMAC_ctx *ctx, const char *str, int slen)
 
void scram_HMAC_final (uint8 *result, scram_HMAC_ctx *ctx)
 
void scram_SaltedPassword (const char *password, const char *salt, int saltlen, int iterations, uint8 *result)
 
void scram_H (const uint8 *input, int len, uint8 *result)
 
void scram_ClientKey (const uint8 *salted_password, uint8 *result)
 
void scram_ServerKey (const uint8 *salted_password, uint8 *result)
 
char * scram_build_secret (const char *salt, int saltlen, int iterations, const char *password)
 

Macro Definition Documentation

◆ HMAC_IPAD

#define HMAC_IPAD   0x36

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

Referenced by scram_HMAC_init().

◆ HMAC_OPAD

#define HMAC_OPAD   0x5C

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

Referenced by scram_HMAC_init().

Function Documentation

◆ scram_build_secret()

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

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

References Assert, elog, ERROR, free, malloc, palloc(), 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().

194 {
195  uint8 salted_password[SCRAM_KEY_LEN];
196  uint8 stored_key[SCRAM_KEY_LEN];
197  uint8 server_key[SCRAM_KEY_LEN];
198  char *result;
199  char *p;
200  int maxlen;
201  int encoded_salt_len;
202  int encoded_stored_len;
203  int encoded_server_len;
204  int encoded_result;
205 
206  if (iterations <= 0)
207  iterations = SCRAM_DEFAULT_ITERATIONS;
208 
209  /* Calculate StoredKey and ServerKey */
210  scram_SaltedPassword(password, salt, saltlen, iterations,
211  salted_password);
212  scram_ClientKey(salted_password, stored_key);
213  scram_H(stored_key, SCRAM_KEY_LEN, stored_key);
214 
215  scram_ServerKey(salted_password, server_key);
216 
217  /*----------
218  * The format is:
219  * SCRAM-SHA-256$<iteration count>:<salt>$<StoredKey>:<ServerKey>
220  *----------
221  */
222  encoded_salt_len = pg_b64_enc_len(saltlen);
223  encoded_stored_len = pg_b64_enc_len(SCRAM_KEY_LEN);
224  encoded_server_len = pg_b64_enc_len(SCRAM_KEY_LEN);
225 
226  maxlen = strlen("SCRAM-SHA-256") + 1
227  + 10 + 1 /* iteration count */
228  + encoded_salt_len + 1 /* Base64-encoded salt */
229  + encoded_stored_len + 1 /* Base64-encoded StoredKey */
230  + encoded_server_len + 1; /* Base64-encoded ServerKey */
231 
232 #ifdef FRONTEND
233  result = malloc(maxlen);
234  if (!result)
235  return NULL;
236 #else
237  result = palloc(maxlen);
238 #endif
239 
240  p = result + sprintf(result, "SCRAM-SHA-256$%d:", iterations);
241 
242  /* salt */
243  encoded_result = pg_b64_encode(salt, saltlen, p, encoded_salt_len);
244  if (encoded_result < 0)
245  {
246 #ifdef FRONTEND
247  free(result);
248  return NULL;
249 #else
250  elog(ERROR, "could not encode salt");
251 #endif
252  }
253  p += encoded_result;
254  *(p++) = '$';
255 
256  /* stored key */
257  encoded_result = pg_b64_encode((char *) stored_key, SCRAM_KEY_LEN, p,
258  encoded_stored_len);
259  if (encoded_result < 0)
260  {
261 #ifdef FRONTEND
262  free(result);
263  return NULL;
264 #else
265  elog(ERROR, "could not encode stored key");
266 #endif
267  }
268 
269  p += encoded_result;
270  *(p++) = ':';
271 
272  /* server key */
273  encoded_result = pg_b64_encode((char *) server_key, SCRAM_KEY_LEN, p,
274  encoded_server_len);
275  if (encoded_result < 0)
276  {
277 #ifdef FRONTEND
278  free(result);
279  return NULL;
280 #else
281  elog(ERROR, "could not encode server key");
282 #endif
283  }
284 
285  p += encoded_result;
286  *(p++) = '\0';
287 
288  Assert(p - result <= maxlen);
289 
290  return result;
291 }
void scram_H(const uint8 *input, int len, uint8 *result)
Definition: scram-common.c:147
static char password[100]
Definition: streamutil.c:53
int pg_b64_encode(const char *src, int len, char *dst, int dstlen)
Definition: base64.c:49
unsigned char uint8
Definition: c.h:357
void scram_SaltedPassword(const char *password, const char *salt, int saltlen, int iterations, uint8 *result)
Definition: scram-common.c:104
void scram_ServerKey(const uint8 *salted_password, uint8 *result)
Definition: scram-common.c:173
#define malloc(a)
Definition: header.h:50
#define sprintf
Definition: port.h:194
#define ERROR
Definition: elog.h:43
void scram_ClientKey(const uint8 *salted_password, uint8 *result)
Definition: scram-common.c:160
#define free(a)
Definition: header.h:65
#define Assert(condition)
Definition: c.h:739
#define SCRAM_DEFAULT_ITERATIONS
Definition: scram-common.h:46
int pg_b64_enc_len(int srclen)
Definition: base64.c:224
void * palloc(Size size)
Definition: mcxt.c:949
#define elog(elevel,...)
Definition: elog.h:228
#define SCRAM_KEY_LEN
Definition: scram-common.h:23

◆ scram_ClientKey()

void scram_ClientKey ( const uint8 salted_password,
uint8 result 
)

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

References scram_HMAC_final(), scram_HMAC_init(), scram_HMAC_update(), and SCRAM_KEY_LEN.

Referenced by calculate_client_proof(), and scram_build_secret().

161 {
162  scram_HMAC_ctx ctx;
163 
164  scram_HMAC_init(&ctx, salted_password, SCRAM_KEY_LEN);
165  scram_HMAC_update(&ctx, "Client Key", strlen("Client Key"));
166  scram_HMAC_final(result, &ctx);
167 }
void scram_HMAC_final(uint8 *result, scram_HMAC_ctx *ctx)
Definition: scram-common.c:85
void scram_HMAC_init(scram_HMAC_ctx *ctx, const uint8 *key, int keylen)
Definition: scram-common.c:35
void scram_HMAC_update(scram_HMAC_ctx *ctx, const char *str, int slen)
Definition: scram-common.c:75
#define SCRAM_KEY_LEN
Definition: scram-common.h:23

◆ scram_H()

void scram_H ( const uint8 input,
int  len,
uint8 result 
)

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

References pg_sha256_final(), pg_sha256_init(), and pg_sha256_update().

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

148 {
149  pg_sha256_ctx ctx;
150 
151  pg_sha256_init(&ctx);
152  pg_sha256_update(&ctx, input, len);
153  pg_sha256_final(&ctx, result);
154 }
void pg_sha256_init(pg_sha256_ctx *context)
Definition: sha2.c:268
void pg_sha256_update(pg_sha256_ctx *context, const uint8 *data, size_t len)
Definition: sha2.c:465
void pg_sha256_final(pg_sha256_ctx *context, uint8 *digest)
Definition: sha2.c:566

◆ scram_HMAC_final()

void scram_HMAC_final ( uint8 result,
scram_HMAC_ctx ctx 
)

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

References scram_HMAC_ctx::k_opad, pg_sha256_final(), pg_sha256_init(), pg_sha256_update(), SCRAM_KEY_LEN, SHA256_HMAC_B, and scram_HMAC_ctx::sha256ctx.

Referenced by build_server_final_message(), calculate_client_proof(), scram_ClientKey(), scram_SaltedPassword(), scram_ServerKey(), verify_client_proof(), and verify_server_signature().

86 {
88 
89  pg_sha256_final(&ctx->sha256ctx, h);
90 
91  /* H(K XOR opad, tmp) */
95  pg_sha256_final(&ctx->sha256ctx, result);
96 }
unsigned char uint8
Definition: c.h:357
pg_sha256_ctx sha256ctx
Definition: scram-common.h:53
void pg_sha256_init(pg_sha256_ctx *context)
Definition: sha2.c:268
void pg_sha256_update(pg_sha256_ctx *context, const uint8 *data, size_t len)
Definition: sha2.c:465
uint8 k_opad[SHA256_HMAC_B]
Definition: scram-common.h:54
void pg_sha256_final(pg_sha256_ctx *context, uint8 *digest)
Definition: sha2.c:566
#define SHA256_HMAC_B
Definition: scram-common.h:26
#define SCRAM_KEY_LEN
Definition: scram-common.h:23

◆ scram_HMAC_init()

void scram_HMAC_init ( scram_HMAC_ctx ctx,
const uint8 key,
int  keylen 
)

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

References HMAC_IPAD, HMAC_OPAD, i, scram_HMAC_ctx::k_opad, pg_sha256_final(), pg_sha256_init(), pg_sha256_update(), SCRAM_KEY_LEN, SHA256_HMAC_B, and scram_HMAC_ctx::sha256ctx.

Referenced by build_server_final_message(), calculate_client_proof(), scram_ClientKey(), scram_SaltedPassword(), scram_ServerKey(), verify_client_proof(), and verify_server_signature().

36 {
37  uint8 k_ipad[SHA256_HMAC_B];
38  int i;
39  uint8 keybuf[SCRAM_KEY_LEN];
40 
41  /*
42  * If the key is longer than the block size (64 bytes for SHA-256), pass
43  * it through SHA-256 once to shrink it down.
44  */
45  if (keylen > SHA256_HMAC_B)
46  {
47  pg_sha256_ctx sha256_ctx;
48 
49  pg_sha256_init(&sha256_ctx);
50  pg_sha256_update(&sha256_ctx, key, keylen);
51  pg_sha256_final(&sha256_ctx, keybuf);
52  key = keybuf;
53  keylen = SCRAM_KEY_LEN;
54  }
55 
56  memset(k_ipad, HMAC_IPAD, SHA256_HMAC_B);
57  memset(ctx->k_opad, HMAC_OPAD, SHA256_HMAC_B);
58 
59  for (i = 0; i < keylen; i++)
60  {
61  k_ipad[i] ^= key[i];
62  ctx->k_opad[i] ^= key[i];
63  }
64 
65  /* tmp = H(K XOR ipad, text) */
68 }
unsigned char uint8
Definition: c.h:357
pg_sha256_ctx sha256ctx
Definition: scram-common.h:53
void pg_sha256_init(pg_sha256_ctx *context)
Definition: sha2.c:268
#define HMAC_OPAD
Definition: scram-common.c:27
void pg_sha256_update(pg_sha256_ctx *context, const uint8 *data, size_t len)
Definition: sha2.c:465
uint8 k_opad[SHA256_HMAC_B]
Definition: scram-common.h:54
#define HMAC_IPAD
Definition: scram-common.c:26
void pg_sha256_final(pg_sha256_ctx *context, uint8 *digest)
Definition: sha2.c:566
int i
#define SHA256_HMAC_B
Definition: scram-common.h:26
#define SCRAM_KEY_LEN
Definition: scram-common.h:23

◆ scram_HMAC_update()

void scram_HMAC_update ( scram_HMAC_ctx ctx,
const char *  str,
int  slen 
)

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

References pg_sha256_update(), and scram_HMAC_ctx::sha256ctx.

Referenced by build_server_final_message(), calculate_client_proof(), scram_ClientKey(), scram_SaltedPassword(), scram_ServerKey(), verify_client_proof(), and verify_server_signature().

76 {
77  pg_sha256_update(&ctx->sha256ctx, (const uint8 *) str, slen);
78 }
unsigned char uint8
Definition: c.h:357
pg_sha256_ctx sha256ctx
Definition: scram-common.h:53
void pg_sha256_update(pg_sha256_ctx *context, const uint8 *data, size_t len)
Definition: sha2.c:465

◆ scram_SaltedPassword()

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

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

References i, pg_hton32, scram_HMAC_final(), scram_HMAC_init(), scram_HMAC_update(), and SCRAM_KEY_LEN.

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

107 {
108  int password_len = strlen(password);
109  uint32 one = pg_hton32(1);
110  int i,
111  j;
112  uint8 Ui[SCRAM_KEY_LEN];
113  uint8 Ui_prev[SCRAM_KEY_LEN];
114  scram_HMAC_ctx hmac_ctx;
115 
116  /*
117  * Iterate hash calculation of HMAC entry using given salt. This is
118  * essentially PBKDF2 (see RFC2898) with HMAC() as the pseudorandom
119  * function.
120  */
121 
122  /* First iteration */
123  scram_HMAC_init(&hmac_ctx, (uint8 *) password, password_len);
124  scram_HMAC_update(&hmac_ctx, salt, saltlen);
125  scram_HMAC_update(&hmac_ctx, (char *) &one, sizeof(uint32));
126  scram_HMAC_final(Ui_prev, &hmac_ctx);
127  memcpy(result, Ui_prev, SCRAM_KEY_LEN);
128 
129  /* Subsequent iterations */
130  for (i = 2; i <= iterations; i++)
131  {
132  scram_HMAC_init(&hmac_ctx, (uint8 *) password, password_len);
133  scram_HMAC_update(&hmac_ctx, (const char *) Ui_prev, SCRAM_KEY_LEN);
134  scram_HMAC_final(Ui, &hmac_ctx);
135  for (j = 0; j < SCRAM_KEY_LEN; j++)
136  result[j] ^= Ui[j];
137  memcpy(Ui_prev, Ui, SCRAM_KEY_LEN);
138  }
139 }
static char password[100]
Definition: streamutil.c:53
unsigned char uint8
Definition: c.h:357
#define pg_hton32(x)
Definition: pg_bswap.h:121
unsigned int uint32
Definition: c.h:359
void scram_HMAC_final(uint8 *result, scram_HMAC_ctx *ctx)
Definition: scram-common.c:85
void scram_HMAC_init(scram_HMAC_ctx *ctx, const uint8 *key, int keylen)
Definition: scram-common.c:35
void scram_HMAC_update(scram_HMAC_ctx *ctx, const char *str, int slen)
Definition: scram-common.c:75
int i
#define SCRAM_KEY_LEN
Definition: scram-common.h:23

◆ scram_ServerKey()

void scram_ServerKey ( const uint8 salted_password,
uint8 result 
)

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

References scram_HMAC_final(), scram_HMAC_init(), scram_HMAC_update(), and SCRAM_KEY_LEN.

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

174 {
175  scram_HMAC_ctx ctx;
176 
177  scram_HMAC_init(&ctx, salted_password, SCRAM_KEY_LEN);
178  scram_HMAC_update(&ctx, "Server Key", strlen("Server Key"));
179  scram_HMAC_final(result, &ctx);
180 }
void scram_HMAC_final(uint8 *result, scram_HMAC_ctx *ctx)
Definition: scram-common.c:85
void scram_HMAC_init(scram_HMAC_ctx *ctx, const uint8 *key, int keylen)
Definition: scram-common.c:35
void scram_HMAC_update(scram_HMAC_ctx *ctx, const char *str, int slen)
Definition: scram-common.c:75
#define SCRAM_KEY_LEN
Definition: scram-common.h:23