As well as supplying Cryptosense Analyzer to our customers so they can test their applications, we frequently apply the tool ourselves to widely-used open source software including the Java JDK. The Oracle Critical Patch Update (CPU) of 17th October contained patches for two CVEs discovered at Cryptosense in collaboration with our partners at University of Venice Ca’ Foscari.
The recent edition (no. 15) of hacker magazine POC||GTFO features a nice article on cracking JKS Java keystores. JKS is the default keystore in all current versions of Java and still the only kind available in several widely-used application frameworks, despite issues with its security.
The keystore works by password-based encryption (PBE): you supply a password and the private keys are encrypted under a key derived from that password. There are just two problems: the encryption is not real encryption and the key derivation is extremely weak. The PBE works by applying the hash function SHA-1 to the password (and a salt) to generate a keystream, and XORing the resulting stream against the key.
Unchanged default access passwords are a pervasive problem in computer security. A recent high-profile example is the Mirai botnet that spread by using 61 common default login credentials.
In programs using crypto, passwords are often used to generate cryptographic keys. For example, they are used to generate the “key encrypting keys” that are used to protect private keys stored in keystores, or the master key used to protect persistent application data written to storage.
Unfortunately, these passwords are susceptible to the same problem: they have de facto “default values”, often coming from HOWTOs for setup. For example, the password “changeit” figures in several guides for configuring TLS private keys for Java web applications. We trace these passwords using our Analyzer tool, and we encounter a substantial number of “changeit”s in the wild.
Sometimes default crypto credentials are even easier to exploit. In the recent Primefaces bug, many applications were using the default password (“primefaces”) to generate the encryption key. This would lead to secret values encoded in encrypted URLs being leaked, and unlike access passwords, there would be no log to show that attack was being made.
Application frameworks can sometimes make it unnecessarily complicated to change default passwords, but still there’s little point encrypting if the password is unchanged. Our Analyzer tool checks crypto passwords against a dictionary of known defaults and common weak passwords.
Updated October 2020
In previous posts we looked at the security of the JKS and JCEKS Java Keystores implemented in the default (Oracle) JCE/JCA crypto provider. Here we’ll take a look at what’s offered by BouncyCastle, a widely-used open-source alternative.
Like the Oracle provider, keystores in BC rely on password-based encryption for confidentiality, i.e. deriving an encryption key from a password and then using that to encrypt the keys for writing to a file. BC offers three keystore types: BKS (bouncy castle keystore), BCFKS (BouncyCastle FIPS keystore), UBER, and a PKCS#12 compatible keystore for interoperability.
Here we summarize the encryption used in each keystore to protect private key values. Behaviour on certificates can be different, and some keystores also allow symmetric keys to be stored – more on this later. In addition to private key value encryption, UBER has an extra layer of encryption for the whole keystore, which means that all metadata around the keys and certificates will also be encrypted. Below the table, we’ll step through the analysis.
|UBER (keys)||PBEWithSHAAnd3-KeyTripleDES-CBC||Random(1024, 2047)||160b||168b|
|UBER (store)||PBEWithSHAAndTwofish-CBC||Random(1024, 2047)||160b||256b|
|BCFKS||PBKDF2 with AES-CCM||51200||512b||256b|
BKS uses triple-DES encryption, which is deprecated for most applications but not considered desperately insecure (it can still be used, for example, in PCI DSS environments). One reason for deprecation is that it has a 64-bit blocksize, which is not enough for high-volume applications. Here we’re only encrypting a private key so this shouldn’t matter. The key is derived following the method from PKCS#12v1.0, which is also deprecated (PKCS#12v1.1, from July 2014 recommends using only PBKDF2, which is defined in PKCS#5v2.1). The PBKDFs use a random salt, as we would expect. Note that the number of iterations of the PBKDF is a random value between 1024 and 2047. This is an unusual construct, and it’s hard to say how this offers extra security since the number of iterations also is recorded in clear in the file, along with the salt. In any case, 2047 is considered quite a low number of iterations for modern applications.
UBER uses encryption similar to BKS for the private key values. It uses the same PBKDF and iteration count, but a different cipher (Twofish), for encrypting the whole keystore. Twofish was an unchosen finalist for the AES competition and so received a fair amount of cryptanalytic attention in the late 90’s. No significant weaknesses have been found.
BCPKCS12 also uses the old PBKDF (from PKCS#12v1.0). Since 2017, it uses a fixed 51200 iterations in the key derivation function.
BC FIPS Keystore (BCFKS)
The FIPS version of Bouncy Castle includes a new keystore, BCFKS, which uses PBKDF2 with HMAC SHA512 for password based key derivation and AES CCM for encryption. Since 2017, the PBKDF has been set to use 51200 iterations.
Apart from protecting the confidentiality of the value of private keys, keystores can also protect integrity, i.e. you can make a password-based MAC of the whole keystore and then check it hasn’t been tampered with.
To do this, BKS and the PKCS#12 keystore create an HMAC using a key derived using the same PKCS#5v1.0 PBKDF as used for encryption. However UBER does something a little strange. Since it has already used the second keystore-wide password to encrypt the whole keystore, it simply calculates a SHA-1 hash of the keystore before encryption and uses this to check integrity after decryption has happened. This MAC-then-encrypt approach is generally considered a bad idea, since it can lead to attacks if, for example, there is a perceptible difference in behaviour (an error message, or execution time) between a decryption that fails because the padding is invalid, or a decryption that fails because the SHA-1 hash is invalid (a so-called padding oracle attack).
Update March 2018
Note that early versions of BouncyCastle BKS (before v1.47) had a 20 bit HMAC key meaning that a functioning integrity password could be easily guessed. This issue only affects the integrity MAC, and would not help in obtaining the keys use to protect private keys.
Traps for the unwary
There are few more messy details around BC and Oracle Java keystores, in particular around their encryption of public-key certificates and their behaviour when given null or empty string passwords. We cover that and more in our Java Crypto Whitepaper
If you write a Java application that uses cryptography, chances are you’ll have to store some cryptographic keys. The Java crypto APIs provide an abstraction for dealing with this called keystores. In this post, we’re going to look into how Java keystores are protected when written out as files.
In fact there are several kinds of Java keystore, and different Java crypto providers implement them in different ways, resulting in files that are more or less resistant to attack. For example, in the Sun crypto provider, there is the “JKS” old-style Sun keystore, the “JCEKS” new(-ish) style Sun keystore, and a PKCS12 compatible keystore. Other providers like BouncyCastle offer their own variations.
When it comes to protecting fields containing the keys, all of these keystores function by some kind of password-based encryption (PBE). If an encryption password is given (and it’s not always mandatory to do so), this is used to derive a key that’s then used to encrypt the file containing the serialization of the keys.
Hold the Salt
In the old-style Sun JKS keystore, the PBE method is somewhat unconventional. Individual keys are XORed against a keystream derived by applying SHA-1 repeatedly to the password and a 20 byte salt. Only one SHA-1 application is required to derive the first keystream byte. Since DER encoded keys contain a lot of structure in their first bytes, we can work out what the first few bytes of the hashed password must be, which makes a dictionary-based cracker highly efficient.
As a final quirk, an integrity signature is calculated over the encrypted keystore by hashing the password, the keystore, and the US-ASCII string “Mighty Aphrodite”. Nobody seems to know why, but perhaps it dates the design back to 1995, when the Woody Allen film of the same name was in the cinemas, and the first Java beta release was made. Hence the Botticelli Venus above (and note the perfect logarithmic spiral of the curl on her right shoulder).
It should be clear that you must not use these legacy techniques to protect real keys in today’s environments. It’s one of the keystore-related weaknesses we detect with our Java Crypto App Tracer, and we come across it it quite often. There’s simply a lot of Java code in production that has not been audited for crypto security since it was written 15 years ago or more.
More Keystore Attacks
You can find out more about keystore security and other Java crypto security issues in our free whitepaper.
To find these and other crypto security issues in Java applications, you can use our Analyzer software.