- Key rotation - allowing a security manager to generate a new keystore and rekey all documents as needed.
- Keystore password stored on remotely.
- Keystore password > 25 chars.
If an attacker was to mount a brute force attack then they would have to first break the PBE on the keystore, then they would have to break the 2048 bit RSA wrapping the keys.
The keystore generation program will generate a keystore with a specified number of AES 256 bit keys. This number of keys will need to be substantially large to accommodate a unique key for each document. We use will use 50000. This should provide a set of keys randomly distributed within the keyspace.
Given that there is a possibility of an attack against two or more encrypted documents we will ensure that no two documents are encrypted with the same key.
Each document will be encrypted with a randomly selected key from this pool. Allowing that the password based encryption of the keystore is breakable, I decided to use the keywrap classes to encrypt each secret key.
If you make the assumption that a keystore's PBE can be broken, then it would be relatively trivial to write a program to attempt to decrypt the files with the secret keys. We need a way to lock this keystore specifically to our code. To do this we will end up storing the RSA private key used to wrap the AES keys in our program as a byte array. This will lock this keystore to the code used to decrypt the files. Thus the attacker will have to grab the classes as well as the encrypted files and the keystore.
Below are the relevant parts of our keystore generator.
...snip... String keyStoreEntryAlias = null; // Change the output file location to where ever you want to store the new KeyStore File keyStoreOutputFile = new File(keyStoreName); KeyStore keyStore = null; try { // NOTE: This creates numKeys of random SecretKey. If you lose the keystore and you have used it // to encrypt some file you are HOSED. DO NOT lose the KeyStore file that is // generated from this program. Keep a second copy on a CD and put it in a safe. // // We are using the AES encryption algorithm to represent our SecretKey // Create an empty keyStore keyStore = KeyStore.getInstance("JCEKS"); keyStore.load(null, password); //create RsaEncrypter with nulls to use the embedded keys. RsaEncrypter rsaEncrypter = new RsaEncrypter(null, null); PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(rsaEncrypter.getPrivateKey().getEncoded()); String privateKeyStr = Base64.encodeToString(privateKeySpec.getEncoded(), true); System.out.println( "PrivateKey: \n\r" + privateKeyStr ); // to output embedded private key with some massaging. add quotes take off [] System.out.println( "Embedded PrivateKey: \n\r" + Arrays.toString(privateKeyStr.toCharArray())) ; X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(rsaEncrypter.getPublicKey().getEncoded()); String publicKeyStr = Base64.encodeToString(publicKeySpec.getEncoded(), true); System.out.println( "PublicKey: \n\r" + publicKeyStr ); // to output embedded public key with some massaging. add quotes take off [] System.out.println( "Embedded PublicKey: \n\r" + Arrays.toString(publicKeyStr.toCharArray()) ); for (int i=0; i<> { KeyGenerator keyGen = KeyGenerator.getInstance("AES"); keyGen.init(256); SecretKey key = keyGen.generateKey(); byte[] wrappedKey = rsaEncrypter.wrapKey(key); //System.out.println( "NakedKey: " + key.getEncoded()); //System.out.println("WrappedKey: " + wrappedKey.toString()); SecretKeySpec skWrapSpec = new SecretKeySpec(wrappedKey, "AES"); //create a alias for the key keyStoreEntryAlias = (String)RandomStringUtils.randomAlphanumeric(16); // test to see if key alias already exists if (! keyStore.containsAlias(keyStoreEntryAlias) ) { // Add our secret key as an entry in the empty keyStore KeyStore.SecretKeyEntry skEntry = new KeyStore.SecretKeyEntry(skWrapSpec); keyStore.setEntry(keyStoreEntryAlias, skEntry, new KeyStore.PasswordProtection(password)); } } // Write the keyStore to disk. FileOutputStream fos = new FileOutputStream(keyStoreOutputFile); keyStore.store(fos, password); System.out.println("AES 256 Key store created with " + keyStore.size() + " random RSA wrapped SecretKeys. \r\n"); System.out.println("Alg --- Aliases --- \r\n"); Enumeration aliases = keyStore.aliases(); StringBuffer buf = new StringBuffer(""); while (aliases.hasMoreElements()) { String keyName = (String)aliases.nextElement(); SecretKey theKey = (SecretKey)keyStore.getKey(keyName,password); String keyStr = ""; String algorithm = theKey.getAlgorithm(); if (verbose) { keyStr = Base64.encodeToString(theKey.getEncoded()); } buf.append( algorithm ).append(" ").append(keyName).append("| ") buf.append( keyStr ).append("\r\n-----------------------\r\n"); } System.out.println( buf.toString() ); System.out.println("File is: \"" + keyStoreOutputFile.getCanonicalPath() + "\""); } catch (Exception e) { System.out.println("Error: " + e); e.printStackTrace(); } ...snip... Stay tuned ... I will reveal the RSAEncrypter and AESEcrypter source to show you how the wrapping and unwrapping occurs. If you are looking for more information on the key wrapping technique these references may help. http://www.faqs.org/rfcs/rfc3394.html http://www.java2s.com/Code/Java/Security/WrapAndUnwrapKey.htm http://books.google.com/books?id=WLLAD2FKH3IC&pg=PA50&lpg=PA50&dq=key+Wrapping+java&source=web&ots=O9EnrPo8xB&sig=8UuFnc04iXEhBqeduJLKZU46MFk&hl=en&sa=X&oi=book_result&resnum=3&ct=result These two don't use the KeyWrap technique but they are similar. http://www-users.york.ac.uk/~mal503/lore/pkencryption.htm http://www.junkheap.net/content/public_key_encryption_java
No comments:
Post a Comment