class PG::Scram

The client side of SCRAM-SHA-256 (RFC 5802, RFC 7677), as PostgreSQL runs it: without channel binding (n,,), and with the user name left empty, since the server takes the startup message's.

s = PG::Scram.new("pencil", nonce: "rOprNGfwEbeRWgbNEkqO", user: "user")
s.client_first   # => "n,,n=user,r=rOprNGfwEbeRWgbNEkqO"

The password is used as it is: SASLprep, which PostgreSQL applies when the password is valid for it, changes only passwords with characters beyond ASCII that it maps or forbids, so such a password may be refused.

src/scram.qz:13

Constants

MECHANISM: String

The mechanism's name, as the server lists it.

src/scram.qz:15

MAX_ITERATIONS: Int

The most PBKDF2 rounds a server may ask for, unless the connection says otherwise (max_scram_iterations): the server is not trusted before its signature is checked, and a huge count would keep the client hashing (PostgreSQL's default is 4096; from PostgreSQL 16 an administrator may raise scram_iterations).

src/scram.qz:22

BLOCKING_ITERATIONS: Int

Above this many rounds, the hashing runs on a helper thread (Task.blocking), so that the worker's other tasks go on meanwhile.

src/scram.qz:26

Class methods

def self.new(password: String, nonce: String? = …, user: String = …, max_iterations: Int = …) -> PG::Scram

A new exchange for password, with a random 18-byte nonce unless one is given (tests).

src/scram.qz:38

def self.salted_password(password: String, salt: Bytes, rounds: Int) -> Bytes

PBKDF2-HMAC-SHA-256 of the password: on a helper thread when the count is large (password and salt are immutable, so the block may take them there).

src/scram.qz:96

Methods

def client_first -> String

The first message: the GS2 header and the bare part.

src/scram.qz:46

def client_final(server_first: String) -> String

The final message, answering the server's first message. Raises PG::AuthenticationError when that message is malformed or its nonce does not extend this client's.

src/scram.qz:51

def verify(server_final: String) -> Void

Checks the server's final message, which proves that the server knows the password too. Raises PG::AuthenticationError when it does not, or reports an error (e=).

src/scram.qz:78

def verified? -> Bool

Whether #verify checked the server's signature: until then the server has not proved that it knows the password.

src/scram.qz:91