Class JKS


public class JKS

This is an implementation of Sun's proprietary key store algorithm, called "JKS" for "Java Key Store". This implementation was created entirely through reverse-engineering.

The format of JKS files is, from the start of the file:

  1. Magic bytes. This is a four-byte integer, in big-endian byte order, equal to 0xFEEDFEED.
  2. The version number (probably), as a four-byte integer (all multibyte integral types are in big-endian byte order). The current version number (in modern distributions of the JDK) is 2.
  3. The number of entrires in this keystore, as a four-byte integer. Call this value n
  4. Then, n times:
    1. The entry type, a four-byte int. The value 1 denotes a private key entry, and 2 denotes a trusted certificate.
    2. The entry's alias, formatted as strings such as those written by DataOutput.writeUTF(String).
    3. An eight-byte integer, representing the entry's creation date, in milliseconds since the epoch.

      Then, if the entry is a private key entry:

      1. The size of the encoded key as a four-byte int, then that number of bytes. The encoded key is the DER encoded bytes of the EncryptedPrivateKeyInfo structure (the encryption algorithm is discussed later).
      2. A four-byte integer, followed by that many encoded certificates, encoded as described in the trusted certificates section.

      Otherwise, the entry is a trusted certificate, which is encoded as the name of the encoding algorithm (e.g. X.509), encoded the same way as alias names. Then, a four-byte integer representing the size of the encoded certificate, then that many bytes representing the encoded certificate (e.g. the DER bytes in the case of X.509).

  5. Then, the signature.

(See this file for some idea of how I was able to figure out these algorithms)

Decrypting the key works as follows:

  1. The key length is the length of the ciphertext minus 40. The encrypted key, ekey, is the middle bytes of the ciphertext.
  2. Take the first 20 bytes of the encrypted key as a seed value, K[0].
  3. Compute K[1] ... K[n], where |K[i]| = 20, n = ceil(|ekey| / 20), and K[i] = SHA-1(UTF-16BE(password) + K[i-1]).
  4. key = ekey ^ (K[1] + ... + K[n]).
  5. The last 20 bytes are the checksum, computed as H = SHA-1(UTF-16BE(password) + key). If this value does not match the last 20 bytes of the ciphertext, output FAIL. Otherwise, output key.

The signature is defined as SHA-1(UTF-16BE(password) + US_ASCII("Mighty Aphrodite") + encoded_keystore) (yup, Sun engineers are just that clever).

(Above, SHA-1 denotes the secure hash algorithm, UTF-16BE the big-endian byte representation of a UTF-16 string, and US_ASCII the ASCII byte representation of the string.)

The source code of this class should be available in the file

Constructor Summary
Method Summary
 java.util.Enumeration engineAliases()
 boolean engineContainsAlias(java.lang.String alias)
 void engineDeleteEntry(java.lang.String alias)
    engineGetCertificate(java.lang.String alias)
 java.lang.String engineGetCertificateAlias( cert)
   [] engineGetCertificateChain(java.lang.String alias)
 java.util.Date engineGetCreationDate(java.lang.String alias)
    engineGetKey(java.lang.String alias, char[] password)
 boolean engineIsCertificateEntry(java.lang.String alias)
 boolean engineIsKeyEntry(java.lang.String alias)
 void engineLoad( in, char[] passwd)
 void engineSetCertificateEntry(java.lang.String alias, cert)
 void engineSetKeyEntry(java.lang.String alias, byte[] encodedKey,[] certChain)
 void engineSetKeyEntry(java.lang.String alias, key, char[] passwd,[] certChain)
 int engineSize()
 void engineStore( out, char[] passwd)
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Constructor Detail


public JKS()
Method Detail


public engineGetKey(java.lang.String alias,
                                      char[] password)
Specified by:
engineGetKey in class


public[] engineGetCertificateChain(java.lang.String alias)
Specified by:
engineGetCertificateChain in class


public engineGetCertificate(java.lang.String alias)
Specified by:
engineGetCertificate in class


public java.util.Date engineGetCreationDate(java.lang.String alias)
Specified by:
engineGetCreationDate in class


public void engineSetKeyEntry(java.lang.String alias,
                              char[] passwd,
                    [] certChain)
Specified by:
engineSetKeyEntry in class


public void engineSetKeyEntry(java.lang.String alias,
                              byte[] encodedKey,
                    [] certChain)
Specified by:
engineSetKeyEntry in class


public void engineSetCertificateEntry(java.lang.String alias,
Specified by:
engineSetCertificateEntry in class


public void engineDeleteEntry(java.lang.String alias)
Specified by:
engineDeleteEntry in class


public java.util.Enumeration engineAliases()
Specified by:
engineAliases in class


public boolean engineContainsAlias(java.lang.String alias)
Specified by:
engineContainsAlias in class


public int engineSize()
Specified by:
engineSize in class


public boolean engineIsKeyEntry(java.lang.String alias)
Specified by:
engineIsKeyEntry in class


public boolean engineIsCertificateEntry(java.lang.String alias)
Specified by:
engineIsCertificateEntry in class


public java.lang.String engineGetCertificateAlias( cert)
Specified by:
engineGetCertificateAlias in class


public void engineStore( out,
                        char[] passwd)
Specified by:
engineStore in class


public void engineLoad( in,
                       char[] passwd)
Specified by:
engineLoad in class