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.
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. The PBKDF has been set to use 16384 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.