Skip to content

Cryptography

expitau edited this page Dec 9, 2022 · 1 revision

Requirements and Justification

In order for Passbirb to generate secure passwords, the following requirements must be met

  • The generated hashes must be preimage resistant
  • The generated hashes must preserve the entropy of the master password
  • The algorithm should take a relatively long time to compute, and require a large pool of memory.
  • The generated passwords must be exactly 20 characters long, and contain at least one of each of the following
    • An uppercase character
    • A lowercase characters
    • A digit
    • A symbol in '!@#$%^&*_-+='

Additionally, Argon2 requires that the salt passed to it be indistinguishable from random noise.

Argon2 meets most of these requirements out of the box, in particular when preventing brute-force and rainbow table attacks. SHA256 is used to create an indistinguishable but still deterministic salt. After the password is generated it is encoded as base64 (base85 provides more entropy, but special characters may not meet all password policies), the first 4 characters are optionally discarded to ensure that the output meets the password requirements.

Algorithm

Passbirb uses a combination of Argon2 and SHA256 to generate irreversible, entropy-preserving passwords. The following is a pseudocode snippet of the algorithm.

# User-provided inputs
Master_Key = "Top_Secret_Master_Password_123"
Salt = "wikipedia:1" # Website top-level domain + counter recommended, but not required.

Salt_Hash = Base64Encode(SHA256(Salt)) # Encoded as Base64 to preserve entropy in Argon2 node bindings

# Additional options:
#   parallelism    -  4 threads
#   tagLength      -  15 bytes
#   memorySizeKb   -  1024kB
#   iterations     -  20 iterations
#   version        -  0x13 (current version)
#   key            -  None
#   associatedData -  None
#   hashType       -  Argon2id version
Hash_Key = Argon2(password=Master_Key, salt=Salt_Hash)
Password = FormatPassword(key=Hash_Key)

# Non-cryptographic formatting of password
def FormatPassword(key):
    # Get base64 encoding of the key
    key = Base64Encode(key) # 15 bytes -> 20 base64 characters

    # Some websites don't allow characters like '/', use Base64URL instead.
    key = Replace_Characters(key, '+', '-')
    key = Replace_Characters(key, '/', '_')

    # Satisfy password requirements in first 4 characters if not already met in last 16 characters
    if NUMBER_CHAR not in key[4..]:
        key[0] = '1'
    if LOWERCASE_CHAR not in key[4..]:
        key[1] = 'a'
    if UPPERCASE_CHAR not in key[4..]:
        key[2] = 'A'
    if SPECIAL_CHAR not in key[4..]:
        key[3] = '-'
    
    return key
Clone this wiki locally