- Generate 16-byte Seed using CSPRNG or a source of truly random numbers.
- Output Seed for a user and/or a program to store.
- Ask user for master password MasterPassword and Identifier (see section III). Load Seed from storage or ask user to input it.
- Calculate 16-byte string CP where:
CP := scrypt(MasterPassword)
with constant salt "Generapasswordus" and user-provided cost parameters. - XOR each byte of CP with each byte of Seed:
Key := CP ⊕ Seed
to acquire 16-byte Key. - Calculate derived stream:
DerivedStream := PBKDF2-HMAC-SHA256(Key, Identifier)
with 1 iteration (using Key as key, Identifier as salt). - Encode DerivedStream as described in a section IV and output it.
- Ask user for two strings: account name (e.g. email, login) Name and place identifier (e.g. website address) Place, and one 32-bit integer Counter encoded into 4 bytes in big endian byte order.
- Treat Alphabet, a user-specified alphabet for encoding derived password (see section IV), as an array of bytes.
- Treat AlphabetByteLength, NameByteLength, PlaceByteLength as 32-bit integer, representing byte lengths of the respective inputs, encoded into 4 bytes in big endian byte order.
- Concatenate values and separator characters (shown in quotes) in the
following way:
Identifier :=
AlphabetByteLength || ":" || Alphabet || "," ||
NameByteLength || ":" || Name || "," ||
PlaceByteLength || ":" || Place || "," ||
Counter
- Treat DerivedStream from section II as a stream of pseudorandom bytes. Treat Alphabet, a user-specified encoding alphabet of maximum 256 characters, as an array of characters and AlphabetLength as the length of this array. DerivedPasswordLength is the user-specified length of derived password.
- Calculate UpperBound as:
UpperBound := 256 − (256 mod AlphabetLength)
- Treat each byte of DerivedStream that is less than UpperBound,
modulo AlphabetLength, as an index into Alphabet array and
append the value at this index to DerivedPassword until its length
reaches DerivedPasswordLength:
while (length of DerivedPassword) < DerivedPasswordLength do
b := next byte of DerivedStream
if b < UpperBound then
append to DerivedPassword value of Alphabet[b mod AlphabetLength]
end if
end while - Output DerivedPassword as the final derived password string.
- Ask user for old master password MasterPasswordold and new master password MasterPasswordnew. Load Seed from storage or ask user to input it.
- Calculate two 16-byte strings CPold and
CPnew where:
CPold := scrypt(MasterPasswordold)
with constant salt "Generapasswordus" and user-provided cost parameters.
CPnew := scrypt(MasterPasswordnew) - XOR each byte of CPold with each byte of
CPnew:
Diff := CPold ⊕ CPnew
to acquire 16-byte difference Diff. - XOR each byte of Seed with each byte of Diff:
Seednew := Seed ⊕ Diff
- Output Seednew as a new seed. Tell the user to use MasterPasswordnew and Seednew from now on.
- Destroy Seed if the program stores it, or tell the user to destroy it.
- Append to Seed 1-byte checksum:
SeedWithChecksum := Seed || CRC-8(Seed)
to acquire 17-byte array. - Encode SeedWithChecksum in Base-32:
EncodedSeed := base32(SeedWithChecksum)
to acquire 28-character string. (Base-32 encoding uses alphabet specified in RFC-4648: "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567", or in lower letter case). - Split EncodedSeed into 7 groups of 4 characters each separated with space and output the result.
Decoding must accept characters in any letter case and ignore characters outside of the Base-32 alphabet (including space). Decoders must verify the checksum.
- Character encoding is UTF-8.
- Maximum number of characters in Alphabet is 256.