ddn.crypto.kdf.bcrypt_pbkdf
bcrypt_pbkdf: the OpenBSD bcrypt-based password-based key derivation function.
bcrypt_pbkdf is a PBKDF2-style construction around the "bcrypt hash" (EksBlowfish with a fixed cost) rather than HMAC. OpenSSH uses it to derive the cipher key and IV for encrypted openssh-key-v1 private key files; see OpenSSH PROTOCOL.key and bcrypt_pbkdf(3) from OpenBSD.
The bcrypt hash function is derived from the bcrypt password hashing function with the following modifications (quoting the OpenBSD reference):
- The input password and salt are preprocessed with SHA-512.
- The output length is expanded to 256 bits.
- The magic string to be encrypted is lengthened and modified
to "OxychromaticBlowfishSwatDynamite".
- The hash function performs 64 rounds of initial state
expansion.
One deviation from PBKDF2: instead of outputting key material linearly, the bytes of the per-block outputs are interleaved (striped) across the whole derived key, so assembling any subkey requires computing the entirety of the key material.
The Blowfish core here is a private EksBlowfish implementation, separate from the deprecated legacy Blowfish data-encryption cipher (ddn.crypto.legacy.cipher.blowfish): bcrypt uses Blowfish strictly as a one-way compression schedule over 64-bit blocks, which carries none of the 64-bit-block encryption risk that deprecates legacy Blowfish for data.
Constant-time note: the key schedule and Feistel rounds are branch-free; the only secret-dependent data flow is S-box indexing (memory access), which is inherent to Blowfish and identical in the OpenBSD reference. Secret intermediates are wiped with secureZero on every exit path.
Copyright
Types 2
bcrypt_pbkdf implementation (OpenBSD bcrypt_pbkdf(3)).
Example:
auto kdf = new BcryptPbkdf(16);
auto keyMaterial = kdf.derive(passphraseBytes, saltBytes, 48);private size_t _roundsubyte[] derive(const(ubyte)[] secret, const(ubyte)[] salt,
size_t length)Derives key material using the constructor's round count.ubyte[] derive(const(ubyte)[] secret, const(ubyte)[] salt,
size_t length, KDFParams params)Derives key material, letting params.iterations override the constructor's round count (zero means "unset").ubyte[] deriveRounds(const(ubyte)[] pass,
const(ubyte)[] salt, size_t keylen, size_t rounds) staticubyte[] sha512(const(ubyte)[] data) staticComputes SHA-512 of data and returns the fresh digest.this(size_t rounds)Constructs a BcryptPbkdf with a fixed round count.Self-contained EksBlowfish ("expensive key setup") state: the Blowfish P-array and S-boxes plus the key-schedule variants bcrypt needs. Kept private and separate from the deprecated legacy Blowfish block cipher; this type never encrypts user data.
private uint[18] pprivate uint[256][4] suint stream2word(scope const(ubyte)[] data, ref uint j) static @safe pure nothrow @nogcReads the next big-endian 32-bit word from data, cycling j over the buffer (Blowfish_stream2word).void expand0state(scope const(ubyte)[] key) @safe pure nothrow @nogcPlain key expansion from the current state (Blowfish_expand0state): XORs the cycled key into the P-array, then repeatedly enciphers the chained (l) register pair to replace the P-array and S-boxes.void expandState(scope const(ubyte)[] key, scope const(ubyte)[] data) @safe pure nothrow @nogcSalted key expansion (Blowfish_expandstate): XORs the cycled key into the P-array, then evolves the (l) register pair, mixing one word of data into each register per step, to replace the P-array an...void encipherBlock(ref uint xl, ref uint xr) @safe pure nothrow @nogcEncrypts one 64-bit block in place with the 16-round Feistel network (Blowfish_encipher).uint f(uint x) @safe pure nothrow @nogcThe Blowfish F function: ((S0[a] + S1[b] ^ S2[c]) + S3[d]).Functions 2
ubyte[bcryptPbkdfBlock] bcryptHash(const(ubyte)[] sha2pass,
const(ubyte)[] sha2salt) @safe nothrowOne bcrypt hash evaluation: 32 output bytes from 64-byte SHA-512 compressed password and salt images.ubyte[] sha512Of(const(ubyte)[] data)Test-only SHA-512 helper (the class member is private).Variables 6
bcryptPbkdfBlock = 32Hash size of the inner bcrypt hash and the KDF block size in bytes.
bcryptPbkdfMaxKey = 1024Maximum derived key length in bytes (32 * 32, the reference bound; OpenSSH only ever needs 48).
bcryptPbkdfMaxSalt = 1 << 20Maximum accepted salt length in bytes (the reference bound).
bcryptMagic = "OxychromaticBlowfishSwatDynamite"The magic constant encrypted by the bcrypt hash.
uint[18] INIT_Puint[256][4] INIT_S