117

I was messing around with bcrypt today and noticed something:

hashpw('testtdsdddddddddddddddddddddddddddddddddddddddddddddddsddddddddddddddddd', salt)
Output: '$2a$15$jQYbLa5m0PIo7eZ6MGCzr.BC17WEAHyTHiwv8oLvyYcg3guP5Zc1y'

hashpw('testtdsdddddddddddddddddddddddddddddddddddddddddddddddsdddddddddddddddddd', salt)
Output: '$2a$15$jQYbLa5m0PIo7eZ6MGCzr.BC17WEAHyTHiwv8oLvyYcg3guP5Zc1y'

Does bcrypt have a maximum password length?

John The Ripper
  • 129
  • 1
  • 10
d0ctor
  • 1,273
  • 2
  • 9
  • 7

3 Answers3

99

Yes, bcrypt has a maximum password length. The original article contains this:

the key argument is a secret encryption key, which can be a user-chosen password of up to 56 bytes (including a terminating zero byte when the key is an ASCII string).

So one could infer a maximum input password length of 55 characters (not counting the terminating zero). ASCII characters, mind you: a generic Unicode character, when encoded in UTF-8, can use up to four bytes; and the visual concept of a glyph may consist of an unbounded number of Unicode characters. You will save a lot of worries if you restrict your passwords to plain ASCII.

However, there is a considerable amount of confusion on the actual limit. Some people believe that the "56 bytes" limit includes a 4-byte salt, leading to a lower limit of 51 characters. Other people point out that the algorithm, internally, manages things as 18 32-bit words, for a total of 72 bytes, so you could go to 71 characters (or even 72 if you don't manage strings with a terminating zero).

Actual implementations will have a limit which depends on what the implementer believed and enforced in all of the above. All decent implementations will allow you at least 50 characters. Beyond that, support is not guaranteed. If you need to support passwords longer than 50 characters, you can add a preliminary hashing step, as discussed in this question (but, of course, this means that you no longer compute "the" bcrypt, but a local variant, so interoperability goes down the drain).

Edit: it has been pointed out to me that although, from a cryptographer's point of view, the article is the ultimate reference, this is not necessarily how the designers thought about it. The "original" implementation could process up to 72 bytes. Depending on your stance on formalism, you may claim that the implementation is right and the article is wrong. Anyway, such is the current state of things that my advice remains valid: if you keep under 50 characters, you will be fine everywhere. (Of course it would have been better if the algorithm did not have a length limitation in the first place.)

Tom Leek
  • 168,808
  • 28
  • 337
  • 475
  • I see. I read an article ([here, actually](https://crackstation.net/hashing-security.htm#properhashing)) and it suggested using a server-side key along with the actual password and salt to generate the hash. What would you recommend as the key length, or for this use, should I just hash this first through something like crypt, then bcrypt? – d0ctor Jul 31 '13 at 13:38
  • 3
    An additional secret key is often called "peppering". The proper way is to compute a MAC on the password (with HMAC/SHA-256), using the secret key as MAC key; and then use the MAC output as "password" in bcrypt. HMAC/SHA-256 yields 32 bytes, which can be converted to 44 ASCII characters with Base64, within the limit of bcrypt. Moreover, HMAC will process arbitrarily long passwords, so that solves your password length issue as well. Be aware that using a key implies key management issues, which can be tricky (e.g. it interferes with backups and multi-frontend systems). – Tom Leek Jul 31 '13 at 13:50
  • 5
    Based on some testing just now, the Java bcrypt library [jBCrypt](http://www.mindrot.org/projects/jBCrypt/) has a 72 character limit. – Kenny Evitt Nov 10 '13 at 19:44
  • This is a thought and a question in same time: why not split the password whatever his length, into manageable lengths (72bytes (not 72 character)) and we hash each block with bcrypt, and we join back the results, it can be more longer, it may be ok, or we can hash that too with sha512. it's more slower, but applicable ! what do you think ? – Mohamed Allal May 07 '18 at 10:52
  • @TomLeek How's peppering supposed to work when [bcrypt apparently rejects passwords containing NUL bytes](https://crypto.stackexchange.com/q/90173/8287) (which a MAC is as liable to emit as any other)? – JamesTheAwesomeDude May 24 '21 at 17:39
  • @JamesTheAwesomeDude: You can compute an HMAC and then Base64-encode it (and perhaps discard any trailing equals signs). Base64-encoding increases the length by about a third, but you'll still be within 50 bytes as long as the hash-function output is at most 35 bytes long, which gives you lots of hash functions to choose from. – ruakh Feb 03 '22 at 09:11
43

tl;dr: BCrypt is limited to 72 bytes, not 56.


Background

BCrypt is limited to 72 bytes. The original paper also mentions the use of a null terminator. This means you would generally limited to:

  • 71 characters + 1 byte null terminator

But the BCrypt 2a revision specifies the use of UTF-8 encoding (while the original whitepaper refers to ASCII). When using UTF-8, one character doesn't mean one byte, e.g.:

  • Noël is four characters, but five bytes (N o e ¨ l)
  • is one character, but four bytes (F0 9F 92 A9)
  • M̡̢̛̖̗̘̙̜̝̞̟̠̀́̂̃̄̅̆̇̉̊̋̌̍̎̏̐̑̒̓̔̕̚ is one character, but 74 bytes (with the null terminator included)

So this throws a wrench into how many "characters" you're allowed.

Where does 55 or 56 come from then?

The original whitepaper mentions a maximum key length of 56 bytes:

Finally, the key argument is a secret encryption key, which can be a user-chosen password of up to 56 bytes (including a terminating zero byte when the key is an ASCII string).

This was a misunderstanding based on the Blowfish maximum recommended key size of 448 bits. (448 / 8 = 56 bytes). The Blowfish encryption algorithm, which bcrypt is derived from, has a maximum key size of 448 bits. From Bruce Schneier's original 1993 paper Description of a New Variable-Length Key, 64-Bit Block Cipher (Blowfish):

The block size is 64 bits, and the key can be any length up to 448 bits.

On the other hand, the bcrypt algorithm can (and does), support up to 72 bytes for the key, e.g.:

  • 71×8-bit character + 1× 8-bit null terminator

The 72-byte limit comes from the Blowfish P-Box size, which is 18 DWORDs (18×4 bytes = 72 bytes). From the original bcrypt whitepaper:

Blowfish is a 64-bit block cipher, structured as a 16-round Feistel network [14]. It uses 18 32-bit subkeys, P1, ..., P18, which it derives from the encryption key. The subkeys are known collectively as the P-Array

The canonical OpenBSD implementation will truncate any key that exceeds 72 bytes.

This means that if your UTF8 string that exceeds 72 bytes, it will be truncated to 72 bytes.

Warning:

  • this truncation will remove the null terminator
  • this truncation will even happen mid-character (for a multi-code point character)

For example, if your passwords ends with:

"…stapler"

the UTF-8 encoding for BCrypt will be:

    ══╤══╤═══╤═══╤═══╤═══╤═══╤═════╤═════╤═════╗        
... 63│64│ 65│ 66│ 67│ 68│ 69│ 70  │ 71  │ 72  ║ 73   74
    s │ t│ a │ p │ l │ e │ r │ 0xF0│ 0x9F│ 0x92║ 0xA9 \0
    ══╧══╧═══╧═══╧═══╧═══╧═══╧═════╧═════╧═════╝
                                               |
                                            cutoff

This means that in the canonical OpenBSD implementation, the bytes are cut off inside the middle of a character (even if it leaves you an invalid utf-8 byte sequence):

    ══╤══╤═══╤═══╤═══╤═══╤═══╤═════╤═════╤═════╗
... 63│64│ 65│ 66│ 67│ 68│ 69│ 70  │ 71  │ 72  ║
    s │ t│ a │ p │ l │ e │ r │ 0xF0│ 0x9F│ 0x92║
    ══╧══╧═══╧═══╧═══╧═══╧═══╧═════╧═════╧═════╝

Get rid of maximum length

In recent years, it has been recognized as a good idea that a password hashing algorithm shouldn't have any maximum limit. But there's a problem with allowing a client to use an unlimited password:

  • it introduces a denial of service attack by someone submitting a multi-gigabyte password.

This is why it's now becoming common to pre-hash a user's password with something like SHA2-256. The resulting base-64 encoded string, e.g.:

n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=

will only ever be 44 ASCII characters (45 with the null terminator).

This is the approach taken by Dropbox, and is included in bcrypt.net:

BCrypt.EnhancedHashPassword("correct battery horse staple Noël  M̡̢̛̖̗̘̙̜̝̞̟̠̀́̂̃̄̅̆̇̉̊̋̌̍̎̏̐̑̒̓̔̕̚");

This means that your expensive hashing algorithm won't cause you a denial of service.

Beware of unsalted pre-hashing (aka Password Shucking)

In the last few years a ..."weakness"... has come up with pre-hashing a password:

hash = bcrypt(sha256("Tr0ub4dor&3"));

The issue is that you are effectively turning your code into something like:

hash = bcrypt("SEhuFRToQjRv9AWx5F9EBZroJhnyMG+Z0JQNyzhukfc=");

At first you might not see a problem. In order to bruteforce the final bcrypt hash they still have to know your password:

  • $2a$15$0l9xFKCmFa4rK2jp.otOKO6c2DQToijZ2IB5kvjA3hfqpT.XLK49S
    • SEhuFRToQjRv9AWx5F9EBZroJhnyMG+Z0JQNyzhukfc=
      • Tr0ub4dor&3

The issue is that attackers aren't going to try every possible combination of letters, numbers and symbols. Attackers are going to be using dictionary attacks, and passwords from previous breeches. So rather than trying every possible password, they're going to focus on trying previous breached ones. E.g.:

  • hunter2
  • correct horse battery staple
  • password1

Now imagine they start including a breech that didn't contain raw passwords, but instead was the SHA-256 of user passwords:

  • f52fbd32b2b3b86ff88ef6c490628285f482af15ddcb29541f94bcf526a3f6c7
  • c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a
  • 0b14d501a594442a01c6859541bcb3e8164d183d32937b851835442f69d5c94e

It turns out that they got a match with:

  • 48486e1514e842346ff405b1e45f44059ae82619f2306f99d0940dcb386e91f7

They don't know what the password is, but do know that it was hashed with SHA-256 - an extraordinarily fast hashing algorithm. They will then spend all their energy now trying to bruteforce:

  • 48486e1514e842346ff405b1e45f44059ae82619f2306f99d0940dcb386e91f7

back into

  • "Tr0ub4dor&3"

It's not a weakness - but a shortcut. Like all dictionary attacks are a shortcut.

The answer, like everything else, is to use a salted prehash, for example:

hash = bcryt(hmac_sha256(salt, password));

And make the salt you pre-hash with the same salt that you generated for the bcrypt.

Ian Boyd
  • 2,125
  • 1
  • 21
  • 13
22

Yes, BCrypt has an upper limit of 72 characters. It's a limitation by the Blowfish cipher itself. One way to work around it is by using SHA-256 first and then BCrypt the result. In your case it would be something like

hashpw(sha256('pass'), salt)
Adi
  • 43,808
  • 16
  • 135
  • 167
  • 14
    According to http://stackoverflow.com/a/16597402/313113 **"You're not really going to help people much who use long passwords by hashing first. Some groups you can definitely help. Some you can definitely hurt."** –  Jul 07 '14 at 12:43
  • 4
    It's better to warn that it's too long and then truncate it. – OrangeDog Jul 26 '16 at 16:50
  • why that? for people using long word lists sha256 is still great. and you could even go with sha384 and base91 as input to get even more bytes and you still wont surpass what even very long wordlist-type passwords have of entropy. or you could go sha512, base91 that, truncate 7 characters and still have almost 472 bits of entropy left. and especially with wordlist passwords gaining popularity because it's a nice way to create secure but still memorable pws sites should be prepared for long passwords. – My1 Dec 19 '16 at 00:32
  • See https://security.stackexchange.com/a/184090/11051 for an explanation why using `sha256()` might not be good idea here ("Password Shucking"). Use HMAC-SHA256 instead. – Mikko Rantalainen Apr 21 '22 at 12:38