Passwords test values
Passwords that registration and login read differently: cut after 72 bytes, trimmed, unnormalised or miscounted. 17 values, each with what it breaks and what a correct application does instead.
Type them one at a time with AltShiftN
in the palette, or take them all into a script with nkb emit passwords.
Step 1: register with 72 letters a and a 1
passwords/bcrypt-cut-registerpair 1 of 2 Two passwords that differ after byte 72
- 73 graphemes
- 73 code points
- 73 bytes
- 73 UTF-16 units
- What it breaks
- Step 1 of the 72-byte test: register a new account with this password of 73 bytes. Newer libraries such as Go x/crypto, Spring Security and bcrypt 5 for Python refuse it, and an application that does not catch that shows an error page already here.
- What a correct application does
- Registered, or refused with a message that names the length limit.
Step 2: log in with 72 letters a and a 2
passwords/bcrypt-cut-loginpair 2 of 2 Two passwords that differ after byte 72
- 73 graphemes
- 73 code points
- 73 bytes
- 73 UTF-16 units
- What it breaks
- Step 2: log in to the account from step 1 with this password, which differs only in its 73rd byte. A bcrypt hash that reads only the first 72 bytes, as in PHP, BCrypt.Net, jBCrypt, bcryptjs and pgcrypto, cannot tell the two apart.
- What a correct application does
- Login refused, because this is not the password the account was registered with.
Step 1: register with 36 Polish letters and a 1
passwords/bytes-not-chars-registerpair 1 of 2 Two Polish passwords that differ after byte 72
- 37 graphemes
- 37 code points
- 73 bytes
- 37 UTF-16 units
- What it breaks
- Step 1 of the same test in Polish: 37 characters, under any limit counted in characters, and 73 bytes in UTF-8, because each l with stroke takes two bytes.
- What a correct application does
- Registered.
Step 2: log in with 36 Polish letters and a 2
passwords/bytes-not-chars-loginpair 2 of 2 Two Polish passwords that differ after byte 72
- 37 graphemes
- 37 code points
- 73 bytes
- 37 UTF-16 units
- What it breaks
- Step 2: log in with this password, which differs only in its last character. A limit of 64 or 72 characters does not stop a hash that reads 72 bytes from cutting it.
- What a correct application does
- Login refused.
Step 1: register with a password that ends with a space
passwords/trailing-space-registerpair 1 of 2 Password with and without a trailing space
- ends with a space
- 15 graphemes
- 15 code points
- 15 bytes
- 15 UTF-16 units
- What it breaks
- Step 1 of the trimming test: register with a password that ends with a space. A layer that trims input stores the password without it.
- What a correct application does
- Registered, with the space kept as part of the password.
Step 2: log in with the same password without the space
passwords/trailing-space-loginpair 2 of 2 Password with and without a trailing space
- 14 graphemes
- 14 code points
- 14 bytes
- 14 UTF-16 units
- What it breaks
- Step 2: log in with the password from step 1 without its last space, then once more with the space. Registration and login that trim differently let only one of the two in.
- What a correct application does
- Only the password with the space opens the account, or both do because both sides trim.
Step 1: register with composed Polish letters
passwords/nfc-nfd-registerpair 1 of 2 Composed and decomposed forms of one password
- 9 graphemes
- 9 code points
- 13 bytes
- 9 UTF-16 units
- What it breaks
- Step 1 of the normalisation test: register with Polish letters written as single characters, the form a keyboard types.
- What a correct application does
- Registered.
Step 2: log in with the same letters decomposed
passwords/nfc-nfd-loginpair 2 of 2 Composed and decomposed forms of one password
- 9 graphemes
- 12 code points
- 16 bytes
- 12 UTF-16 units
- What it breaks
- Step 2: log in with the same word written as base letters followed by combining accents. It looks identical, and hashing libraries take the bytes as given, so only an application that normalises the password lets it in.
- What a correct application does
- Login succeeds, because the password is normalised to NFC before it is hashed.
Sixteen spaces
passwords/spaces-only- starts with a space
- ends with a space
- 16 graphemes
- 16 code points
- 16 bytes
- 16 UTF-16 units
- What it breaks
- Passes a minimum length of 8, 12 or 15 characters and holds nothing a user could remember. A layer that trims input turns it into an empty password.
- What a correct application does
- Refused with the reason stated, or accepted and kept exactly, never trimmed to an empty password.
Four key emoji
passwords/emoji-four- 4 graphemes
- 4 code points
- 16 bytes
- 8 UTF-16 units
- What it breaks
- Four characters that String.length in JavaScript, .NET and Java counts as eight, because each takes two UTF-16 units, while Python, PostgreSQL and NIST SP 800-63B count four. A page and a server written in different languages disagree about the minimum length.
- What a correct application does
- Counted as four characters on the page and on the server, and accepted or refused the same way by both.
Passphrase of 64 characters with spaces
passwords/passphrase-64- 64 graphemes
- 64 code points
- 64 bytes
- 64 UTF-16 units
- What it breaks
- NIST SP 800-63B asks verifiers to accept at least 64 characters and the space, and a form with a maxlength of 20 or 32, or a rule against spaces, refuses the passphrase users are told to choose.
- What a correct application does
- Accepted in full, and the same passphrase opens the account afterwards.
Common password that meets the usual rules
passwords/composition-ok- 10 graphemes
- 10 code points
- 10 bytes
- 10 UTF-16 units
- What it breaks
- Has an upper-case letter, a digit and a symbol, so it passes the usual composition rules, and appears more than 500,000 times in the Pwned Passwords list of breached passwords.
- What a correct application does
- Refused as a common or breached password, with the reason stated.
Keyboard walk that meets the usual rules
passwords/breached-but-valid- 10 graphemes
- 10 code points
- 10 bytes
- 10 UTF-16 units
- What it breaks
- A keyboard pattern with a capital letter, digits and a symbol: it passes composition rules and appears more than 150,000 times in the Pwned Passwords list.
- What a correct application does
- Refused as a common or breached password, with the reason stated.
Password of 100 characters
passwords/login-maxlength- 100 graphemes
- 100 code points
- 100 bytes
- 100 UTF-16 units
- What it breaks
- Registration accepts 100 characters while the login field has a lower maxlength, often 64, so the browser silently drops the rest and the user can never log in.
- What a correct application does
- The same password works on the registration, login and password change forms, or all three refuse it with the same limit stated.
Password in Cyrillic
passwords/cyrillic- 9 graphemes
- 9 code points
- 15 bytes
- 9 UTF-16 units
- What it breaks
- NIST SP 800-63B asks verifiers to accept Unicode. A rule that allows only ASCII refuses it, or registration accepts it and an older layer in a single-byte encoding stores something else.
- What a correct application does
- Accepted, and the same password opens the account afterwards.
Password with angle brackets
passwords/angle-bracket- 12 graphemes
- 12 code points
- 12 bytes
- 12 UTF-16 units
- What it breaks
- Request validation in ASP.NET on .NET Framework refuses a form value with a less-than sign followed by a letter, so a valid password ends at an error page.
- What a correct application does
- Accepted like any other printing ASCII character.
Password with a plus and a percent sign
passwords/plus-and-percent- 11 graphemes
- 11 code points
- 11 bytes
- 11 UTF-16 units
- What it breaks
- In a form-encoded body a plus means a space and %41 means A. A client that builds the body by hand without encoding sends Pa ssA-42, so the page and that client store different passwords.
- What a correct application does
- Stored and checked exactly as typed, through every client.
Pairs
Each pair is two of the values above, worth typing side by side: into two fields, or into one field twice. AltShiftN types them in turn, and the palette says which half of a pair comes next.
Two passwords that differ after byte 72
passwords/bcrypt-cutpair 1 of 2 Step 1: register with 72 letters a and a 1
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1- 73 graphemes
- 73 code points
- 73 bytes
- 73 UTF-16 units
pair 2 of 2 Step 2: log in with 72 letters a and a 2
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa2- 73 graphemes
- 73 code points
- 73 bytes
- 73 UTF-16 units
- What it breaks
- Step 3 of the 72-byte test: if the second password opened the account, the system hashes only the first 72 bytes and two different passwords open it. An error page at step 1 means the library refuses long passwords and the application does not handle it.
- What a correct application does
- Login with the second password refused, and registration with the first accepted or refused with the limit stated.
Two Polish passwords that differ after byte 72
passwords/bytes-not-charspair 1 of 2 Step 1: register with 36 Polish letters and a 1
łłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłł1- 37 graphemes
- 37 code points
- 73 bytes
- 37 UTF-16 units
pair 2 of 2 Step 2: log in with 36 Polish letters and a 2
łłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłł2- 37 graphemes
- 37 code points
- 73 bytes
- 37 UTF-16 units
- What it breaks
- Step 3: if the second password opened the account, the length check counts characters while the hash counts bytes, so a password in Polish, Cyrillic or Chinese is cut far earlier than its length suggests.
- What a correct application does
- Login with the second password refused.
Password with and without a trailing space
passwords/trailing-spacepair 1 of 2 Step 1: register with a password that ends with a space
Secret-pass-42- 15 graphemes
- 15 code points
- 15 bytes
- 15 UTF-16 units
pair 2 of 2 Step 2: log in with the same password without the space
Secret-pass-42- 14 graphemes
- 14 code points
- 14 bytes
- 14 UTF-16 units
- What it breaks
- Step 3: if only one of the two logins works and it is not the one with the space, registration and login trim differently, and a user who set the space is locked out.
- What a correct application does
- Only the password with the space opens the account, or both do because both sides trim.
Composed and decomposed forms of one password
passwords/nfc-nfdpair 1 of 2 Step 1: register with composed Polish letters
Zażółć-42- 9 graphemes
- 9 code points
- 13 bytes
- 9 UTF-16 units
pair 2 of 2 Step 2: log in with the same letters decomposed
Zażółć-42- 9 graphemes
- 12 code points
- 16 bytes
- 12 UTF-16 units
- What it breaks
- Step 3: NIST SP 800-63B asks verifiers to normalise passwords to NFC. Without it, the same password typed on one system and pasted from another does not match.
- What a correct application does
- Both forms open the account.