[Anti-SOP4J] Jasypt: A Misleading Library

5 Mar

This is NOT a Flame!

I am not trying to flame or overly criticize the efforts of Daniel Fernández or the Jasypt team. I think their goal is a GREAT one, and their efforts are appreciated (~8,000 lines of Java, and ~13,500 lines of comments)! However, libraries like this worry me, and they should worry you too. Why? Because it seems to me from the documentation and code that the authors do not completely understand cryptography and have not gotten their efforts peer reviewed.

[Note: I disclosed this post to Daniel in advance of publishing it because I consider that the proper thing to do with security relating findings. As such Daniel and I have shared a few emails discussing this post. While he is not, and does not claim to be, a cryptography expert, he is MUCH more knowledgeable about cryptography than the code and documentation would initially indicate.]

Why Should I Believe You?

You shouldn’t! You should read this blog. You should read the works of more knowledgeable people like Nate Lawson. You should read the works of more experienced people like Coda Hale. You should read the works of more knowledgeable and experienced people like D.J. Bernstein. Then with a grain of salt you can consider what I say (I have a PhD in Cryptography and 10 years industry experience, but know little compared to the folks linked above.) and form your own opinion.

You Need to Know Something About Cryptography

The goal of Jasypt, as stated on their site, is to allow “the developer to add basic encryption capabilities to his/her projects with minimum effort, and without the need of having deep knowledge on how cryptography works.” On the surface it appears as though jasypt achieves this goal; however, when one dives into the documentation and implementation a few errors are found which, in my opinion, bring into question the security of the entire library.

What makes this library potentially dangerous is that someone not well versed in cryptography and the “gotchas” of cryptography will assume they are “being secure” by using such a library. In reality they’ve potentially opened themselves up to weaknesses they don’t even know exist. The unfortunate truth is that you need to have more than just a casual knowledge of cryptography if you plan on using it securely. If you plan on implementing a cryptographic library that hides details, then you need to be an expert in cryptography AND get your work reviewed by people more knowledgeable and experienced than yourself. It does not appear that has been done with this library, yet it seems to have a fairly wide acceptance and integration into other projects. [Note: Again from my emails with Daniel, there has been more peer review of this library than the documentation would lead you to believe.]

In the next few sections I will describe the issues I’ve found with this library. Two important statements before I continue: 1) I’ve probably missed other deficiencies in this library, if you find additional ones please leave a comment; 2) all is not lost, most of the issues can be easily fixed. [Note: The timing attack has already have been fixed.]

Hashing != Encryption

One of the first examples on the homepage of jasypt is the following [Note: the homepage has recently changed to use the StrongPasswordEncryptor as the example on the homepage]:

BasicPasswordEncryptor passwordEncryptor = new BasicPasswordEncryptor();
String encryptedPassword = passwordEncryptor.encryptPassword(userPassword);

if (passwordEncryptor.checkPassword(inputPassword, encryptedPassword)) {
  // correct!
} else {
  // bad login!
}

This seems straightforward enough. However, it shows a lack of the basic primitives of cryptography. Encryption, by definition, is “two-way” meaning that whatever is encrypted can be decrypted. (For a more rigorous and precise definition of Encryption and Decryption, see The Handbook of Applied Cryptography, Chapter 1.) When you dig into the code of BasicPasswordEncryptor you see that in fact they are actually using a hash function, not encryption at all.


Am I being pedantic or overly academic, I don’t think so. Because the next example on the homepage is this:
BasicTextEncryptor textEncryptor = new BasicTextEncryptor();
textEncryptor.setPassword(myEncryptionPassword);

String myEncryptedText = textEncryptor.encrypt(myText);

String plainText = textEncryptor.decrypt(myEncryptedText);

When you dig into the code behind BasicTextEncryptor you find that it actually uses an encryption algorithm. At the very least this presents confusion. Developers might believe that a BasicPasswordEncryptor and a BasicTextEncryptor do the same thing when in fact they do not.

[From Daniel: The reason the word “encryption” is used there is basically marketing. Jasypt is not a library created for the security expert, but for the average developer. And a good percent of the average developers think of “password encryption” and not of “password hashing”. This is a term they usually understand better. And it is probably the way they searched it in Google when they reached the jasypt website.]


How can this be fixed? To start, renaming the PasswordEncryptor classes to something more appropriate like PasswordHasher or PasswordDigester would be a good start. Also, I would question why there is both a BasicPasswordEcnryptor and a StrongPasswordEncryptor? If the goal of this library is to prevent users from having to learn about cryptography, then why provide a choice? The differences are clearly documented (MD5, 8 byte salt, and 1K iterations for Basic and SHA-256, 16 byte salt, and 100K iterations for Strong), but now the user must know something about hash functions, salts, and the impact of iterations. This seems to go against the goal of the library.

Timing Attacks

I am not, and will never claim to be, an expert on timing attacks. They are subtle yet devastating attacks that pop up once you think you’ve done everything correctly (Nate Lawson’s talk, Coda Hale’s blog on the issue I’m about to describe, DJB on cache-timing attacks on AES, etc). This is where peer review is a must to ensure a properly formed library. Someone like DJ Bernstein can probably find numerous timing attacks in the Jasypt code. I only looked for, and found, one of the most classic… comparing hash results.

If you look at the code for StandardByteDigester you will find the following lines at the end of the matches() method:


// Digest the message with the extracted digest.
final byte[] encryptedMessage = digest(message, salt);

// If, using the same salt, digests match, then messages too.
return (Arrays.equals(encryptedMessage, digest));

The equals() method for the Arrays class is used to compare the two digests (incorrectly labeled as an “encrypted message”) to see if they are the same. The problem with using this method is that it opens the library up to a timing attack. This is the same bug found in the MessageDigest.isEqual(). Essentially an attacker can work byte-by-byte to discover the digest of the password.

It should be noted that the way in which Jasypt uses this method I believe to be safe. However, as it is a public method, a developer can choose to use it in any way he/she wants. And considering this library is intended to be used by people not well versed in cryptography, I think it should be fixed.

[From Daniel: So the only vulnerable scenario would be one in which this matches(message, digest) method is called being the message argument the one considered secret, and in the specific case that what the attacker is trying to obtain is a suitable hash that matches (incl. salt and iteration) the hash that would be produced for such secret message. Given this, I will admit that it would obviously be better if I change that line of code for a time-constant function, which I will do just in case.]

Fixing this particular issue is easy, just use MessageDigest.isEqual(). However, as is often true with attacks/issues, where there is one there are many. I would recommend again that this code be peer reviewed by folks who are more knowledgeable and experienced than myself. [Note: this was fixed in version 1.9.2.]

Weak Default Algorithms

MD5 is the default hash function for the BasicPasswordEncryptor. This is a poor default choice as MD5 is dead. In 2004 an attack by Xiaoyun Wang and Hongbo Yu was published that showed MD5 to not be collision resistant. In 2013 Xie Tao, Fanbao Liu, and Dengguo Feng published an attack against MD5 that reduced the complexity of the attack to a mere 2^18 operations. Unfortunately, MD5 is the chosen algorithm for the BasicPasswordEncryptor.

DES is the default algorithm for the BasicTextEncryptor. This is also a poor default choice as DES is dead as well. Unfortunately, only Triple-DES (and MD5) are being used in the StrongTextEncryptor. There is really no reason to use either MD5 or DES (or Triple-DES) when SHA-2/3 and AES exist.

With a library like Jasypt, the user expects the library to make the correct choices. That is the purpose of the library: “allow the developer to add basic encryption capabilities to his/her projects with minimum effort, and without the need of having deep knowledge on how cryptography works.” However, expecting the developer to pick the algorithm to use defeats the purpose of this library and forces the developer to know something about cryptography.


[From Daniel: Jasypt allows you to use ANY hash function or encryption algorithm implemented in your JVM security providers. The only thing you have to do is use jasypt’s “standard” digesters and encryptors and not the “easy wrappers” in the utils package, and then configure the algorithm of your choice.]

Conclusion

Daniel Fernández and the Jasypt team have the best of intentions with the Jasypt library. Unfortunately, the library has the deficiencies I enumerated in this post(and probably more than what I’ve documented here) and usually that is not a big issue with a library, but for a cryptographic library it is very troublesome. Using a cryptographic (or any security related library) library that has flaws lulls one into a false sense of security. The consumer feels that they are being secure, yet they are not.

One Reply to “[Anti-SOP4J] Jasypt: A Misleading Library”

  1. Thanks Bill for taking my comments into account, and for taking the time of discussing your article with me.

    Just as a further clarification on the timing attack issue, jasypt's password matching and general hashing operations were not affected by it. Anyway, as you note, this behaviour has been modified in Jasypt 1.9.2 just in case, in order to cover those unintended scenarios you talk about.

    Regards,
    Daniel.

Leave a Reply

Your email address will not be published. Required fields are marked *