/* * Verify a plaintext password against a SCRAM verifier. This is used when * performing plaintext password authentication for a user that has a SCRAM * verifier stored in pg_authid. */ bool scram_verify_plain_password(const char *username, const char *password, const char *verifier) { char *encoded_salt; char *salt; int saltlen; int iterations; uint8 salted_password[SCRAM_KEY_LEN]; uint8 stored_key[SCRAM_KEY_LEN]; uint8 server_key[SCRAM_KEY_LEN]; uint8 computed_key[SCRAM_KEY_LEN]; char *prep_password = NULL; pg_saslprep_rc rc; if (!parse_scram_verifier(verifier, &iterations, &encoded_salt, stored_key, server_key)) { /* * The password looked like a SCRAM verifier, but could not be parsed. */ ereport(LOG, (errmsg("invalid SCRAM verifier for user \"%s\"", username))); return false; } salt = palloc(pg_b64_dec_len(strlen(encoded_salt))); saltlen = pg_b64_decode(encoded_salt, strlen(encoded_salt), salt); if (saltlen == -1) { ereport(LOG, (errmsg("invalid SCRAM verifier for user \"%s\"", username))); return false; } /* Normalize the password */ rc = pg_saslprep(password, &prep_password); if (rc == SASLPREP_SUCCESS) password = prep_password; /* Compute Server Key based on the user-supplied plaintext password */ scram_SaltedPassword(password, salt, saltlen, iterations, salted_password); scram_ServerKey(salted_password, computed_key); if (prep_password) pfree(prep_password); /* * Compare the verifier's Server Key with the one computed from the * user-supplied password. */ return memcmp(computed_key, server_key, SCRAM_KEY_LEN) == 0; }
/* * Calculate ClientKey or ServerKey. */ void scram_ClientOrServerKey(const char *password, const char *salt, int saltlen, int iterations, const char *keystr, uint8 *result) { uint8 keybuf[SCRAM_KEY_LEN]; scram_HMAC_ctx ctx; scram_SaltedPassword(password, salt, saltlen, iterations, keybuf); scram_HMAC_init(&ctx, keybuf, SCRAM_KEY_LEN); scram_HMAC_update(&ctx, keystr, strlen(keystr)); scram_HMAC_final(result, &ctx); }