# Does knowing common prefixes help crack blowfish?

I have strings that are if the form:

 {static data}{changing data}


The beginning static data part is around 20 characters and is common to all strings. The last part is around 5 characters and is different for each string.

The string is encrypted using blowfish (from xjava.security.Cipher) with a fixed initialization vector and a fixed key. Can the fact that the beginning data is unchanging be used as an effective exploit to help break the encryption?

-
What do you mean by unsalted blowfish? –  mikeazo Nov 22 '11 at 17:45
I think he is dealing with PHP and using the crypt(): us2.php.net/crypt –  woliveirajr Nov 22 '11 at 18:04
What are you doing? "Unsalted blowfish" is not a common term (Googles only find is your question). Are you using blowfish in ECB mode, or CBC mode with a constant initialization vector? –  Paŭlo Ebermann Nov 22 '11 at 18:49
@woliveirajr: PHP's crypt is a hash function (for passwords and the like), not encryption. The CRYPT_BLOWFISH variant it supports is actually bcrypt (not plain Blowfish), and automatically includes a salt (but one could pass a constant salt here). –  Paŭlo Ebermann Nov 22 '11 at 18:53
@ICR, What mode of operation? –  mikeazo Nov 23 '11 at 12:11

## migrated from security.stackexchange.comNov 22 '11 at 18:25

This question came from our site for Information security professionals.

For one, "salt" is not a commonly used term if you are encrypting; public data that is used to modify how the encryption is done is commonly termed an "IV" (Initialization Vector). However, "salt" is the common term for public data that modifies how a hash is generated. The distinction between "encrypting" and "hashing" is that hashing can't be undone; given a hash, it's impractical for anyone (even for someone with the key) to generate the original string.

I'll see if I can go through the various possibilities:

• If you are actually doing hashing (for example, hashing a password so that you can recognize it if someone enters it), well, what salt does is it protects in two different ways:

• If you have two different users which have the same password, differing salts will disguise the fact that the passwords are the same.
• It prevents an attacker from getting an attacking multiple passwords at once (for example, by hashing a test password, and seeing if that hash is anyone on the system).

Not doing salt isn't fatal, but generally it is easy enough to warrant the protection it does provide.

And, if you are using PHP's crypt() function (as woliveirajr guesses), well, they always provide a salt -- if you don't provide one, the crypt() function will pick one for you (which is a good thing). So, in this case, you don't have a problem at all.

In addition, having some fixed text at the start of the string you're hashing doesn't help the attacker at all (if it does, the hash function is seriously broken).

• If you are actually doing encryption (that is, you expect someone to be able to decrypt the encrypted string), well, you've got a problem. Most encryption mechanisms do take an IV, and bad things happen if you keep it constant; exactly what those bad things are depends on which 'encryption mode' you are using:

• If you use CBC mode (with a fixed IV), the attacker will be able to see if two encrypted messages are identical up to 8*N bytes in length (for any N). In your example (assuming the fixed part is exactly 20 bytes long), then this means that the attacker can tell if the first 4 bytes of the variable part of two different strings happen to be the same.

• If you use CTR mode (with a fixed IV), it gets a lot worse. The attacker is able to compute the exclusive-or of any two strings; this will likely allow him to deduce the value of the strings.

In both cases, the correct fix would be to generate distinct IVs, and include those in the encrypted messages.

Also, having some fixed text at the start of the string really doesn't affect the security. If you pick IVs correctly, it won't affect things at all; if you use a fixed IV, well, fixed text doesn't hurt much.

-
Although the original implementation of BCrypt auto generates a salt, the PHP implementation does not. In fact, the format of the salt selects the hashing algorithm used. From the PHP documentation; "If no salt is provided, PHP will auto-generate either a standard two character (DES) salt, or a twelve character (MD5), depending on the availability of MD5 crypt()." –  Jacco Nov 24 '11 at 12:57

There is some doubt as to whether the original poster actually means encryption or not. If they do, as pointed out "unsalted" is not relevant. However, for those wondering if actually encrypting data with a known prefix and short suffix is secure or not, the following is the answer.

This applies to any message taken from a small space (here the space is smaller because certain bytes are fixed, but it could be for other reasons). The security depends on the level of attack the adversary is able to perform:

• Ciphertexts only: it is secure (although exactly identical blocks can be observed)
• Access to an encryption oracle (no mode of operation): it is not secure. The adversary can perform an exhaustive search of all values
• Access to an encryption oracle (with a mode of operation): it is secure if the mode of operation is CPA-secure. For example, CBC where the oracle chooses the IV randomly is secure. CBC where the oracle takes the IV as a parameter passed in by the adversary is not secure.

Note: In all of the above, I am assuming a correct implementation (Poncho outlines cases where the implementation is wrong and how it could, e.g., lead to ciphertext-only attacks). Even for taking the IV as a parameter in CBC, I'm not implying that is a bad implementation; I am only trying to denote how much access the adversary has to the implementation. Do they have high-level API access or lower-level access to what should be "intermediate" values?

-

A block cipher like Blowfish is always used in some mode of operation, which says how to operate on texts longer than the block size.

All secure modes are using an initialization vector to make sure that even identical plain texts will give different ciphertexts. (ECB mode, which is not secure, does not use an initialization vector. I hope you are not using ECB mode.)

Depending on the mode, the initialization vector has to be either completely random (and not guessable before fixing the plaintext), for example in CBC mode, or simply non-repeating within the usage of one key (a nonce), like in CTR mode.

Re-using an initialization vector is generally a bad idea. For CTR-mode, it effectively transforms the cipher into a two-or-more-times-pad, generating the same key stream each time. XORing two ciphertexts give the same result as XORing two plaintexts, and if one of them is known, everything is known (other than the key). (The same applies to OFB mode).

For CBC-mode, especially when combined with fixed prefixes of the encrypted data, it leads to identical prefixes of the ciphertext - thus an attacker can see if two entries have the same plaintext, from only looking at the ciphertext.

In our example of 20+5 characters, as Blowfish has 64-bit (8 bytes) blocks (like DES/3DES), and I assume one-byte characters, your 20-character prefix corresponds to two and a half fixed blocks, i.e. four bytes to guess in the third block, with one byte remaining in the fourth block (suitably padded).

So any two entries with the same first four bytes of your changing data have an identical third block, too.

(CFB-mode behaves for the block after the fixed prefix, i.e. the third one, like CTR/CFB.)

Never use a fixed initialization vector for multiple messages with the same key.

If you can't afford storage of the initialization vector with the messages (which I doubt), you could use CTR mode with an initialization vector derived from some identifier of the database row, for example. (But don't use IVs which only differ in the last some bits, multiply them by some factor first.)

There is nothing Blowfish specific in here, other than Blowfish has 64-bit blocks. The same applies to AES (with 128-bit blocks).

-