Trouble setting up password based encryption

The following code is what I have constructed based on what I see in the example of password based encryption in the JCE reference manual.

I get an IO exception on the "keyGen.init(PBEps);" statement.

PBEParameterSpec PBEps =new javax.crypto.spec.PBEParameterSpec(salt, count);

String pws =new String("somearbitrarypword");

char[] pwb = pws.toCharArray();

PBEKeySpec PBEks =new javax.crypto.spec.PBEKeySpec(pwb);

byte[] cipherText =null;

Cipher cNew =null;

try{

javax.crypto.KeyGenerator keyGen = javax.crypto.KeyGenerator.getInstance("DES","SunJCE");

keyGen.init(PBEps);

javax.crypto.SecretKey theKey = keyGen.generateKey();

Cipher c = Cipher.getInstance("PBEWithMD5AndDES");

c.init(Cipher.ENCRYPT_MODE,theKey,PBEps);

AlgorithmParameters algParams = c.getParameters();

byte[] eaParams = algParams.getEncoded();

cipherText = c.doFinal("This is just an example".getBytes());

AlgorithmParameters newAlgParams = AlgorithmParameters.getInstance("PBEWithMD5AndDES");;

newAlgParams.init(eaParams);

cNew = Cipher.getInstance("PBEWithMD5AndDES");

cNew.init(Cipher.DECRYPT_MODE,theKey,PBEps);

}catch (java.security.NoSuchAlgorithmException nsae){

}catch (javax.crypto.NoSuchPaddingException nspe){

}catch (java.security.InvalidKeyException ivke){

}catch (javax.crypto.BadPaddingException bpe){

}catch (javax.crypto.IllegalBlockSizeException ibse){

}catch (java.security.NoSuchProviderException nspe){

}catch (java.security.InvalidAlgorithmParameterException iape){

}catch (java.io.IOException ioe){}

I need the encryption and decryption parameters to be persistent from one session of my program to the next. I thought I could do this by storing the three key data items (salt, count and password) in an RDBMS. Then, I should be able to set up the parameter spec and key spec as shown before the try/catch block, and then use these to set up the key and cipher objects.

I haven't quite figured out if there is really a need for, or benefit from, using the AlgorithmParameters with the eaParams objects in this effort. I haven't quite figured out their use either. I am thinking I may be able to get away with not using them since I can set up a cipher object, both on the first session of my program, and re-establish it in subsequent sessions, simply by using the approach I am trying of creating the parameter and key specification parameters to set up my cipher object.

What have I missed?

Thanks,

Ted

[3829 byte] By [Ted_Byersa] at [2007-10-2 12:50:53]
# 1

Your passphrase use looks wrong. When using PBE I use something along the lines of

public PBEEncryptDataString(String passphrase, byte[] salt, int iterationCount, String characterEncoding) throws EncryptionException

{

try

{

PBEParameterSpec params = new PBEParameterSpec(salt, iterationCount);

KeySpec keySpec = new PBEKeySpec(passphrase.toCharArray());

SecretKey key = SecretKeyFactory.getInstance(ALGORITHM, PROVIDER).generateSecret(keySpec);

sabre150a at 2007-7-13 10:02:46 > top of Java-index,Security,Cryptography...
# 2

Sorry, I missed out par of the code.

public PBEEncryptDataString(String passphrase, byte[] salt, int iterationCount, String characterEncoding) throws EncryptionException

{

assert(passphrase != null);

assert(passphrase.length() >= 6);

assert(salt != null);

assert((iterationCount > 6) && (iterationCount < 20));

assert(characterEncoding != null);

try

{

PBEParameterSpec params = new PBEParameterSpec(salt, iterationCount);

KeySpec keySpec = new PBEKeySpec(passphrase.toCharArray());

SecretKey key = SecretKeyFactory.getInstance(ALGORITHM, PROVIDER).generateSecret(keySpec);

this.characterEncoding = characterEncoding;

this.encryptCipher = Cipher.getInstance(ALGORITHM, PROVIDER);

this.encryptCipher.init(javax.crypto.Cipher.ENCRYPT_MODE, key, params);

sabre150a at 2007-7-13 10:02:46 > top of Java-index,Security,Cryptography...
# 3

Thanks sabre150.

Here is my test code, somewhat simplified from yours.

PBEps = new javax.crypto.spec.PBEParameterSpec(salt, count);

String pws = new String("somearbitrarypword");

javax.crypto.spec.PBEKeySpec keySpec = new javax.crypto.spec.PBEKeySpec(pws.toCharArray());

byte[] cipherText = null;

Cipher cNew = null;

try {

SecretKey key = SecretKeyFactory.getInstance("PBEWithMD5AndDES", "SunJCE").generateSecret(keySpec);

Cipher c = Cipher.getInstance("PBEWithMD5AndDES");

c.init(Cipher.ENCRYPT_MODE,key,PBEps);

cipherText = c.doFinal("This is just an example".getBytes());

cNew = Cipher.getInstance("PBEWithMD5AndDES");

cNew.init(Cipher.DECRYPT_MODE,key,PBEps);

byte[] decryptedText = cNew.doFinal(cipherText);

String tmp1 = new String(cipherText);

String tmp2 = new String(decryptedText);

String tmp = tmp1 + " = " + tmp2;

PlainTextArea.setText(tmp);

} catch (java.security.NoSuchAlgorithmException nsae) {

} catch (java.security.InvalidKeyException ivke) {

} catch (java.security.NoSuchProviderException nspe) {

} catch (java.security.spec.InvalidKeySpecException ivkse){

} catch (javax.crypto.NoSuchPaddingException nspe) {

} catch (java.security.InvalidAlgorithmParameterException iape) {

} catch (javax.crypto.IllegalBlockSizeException ibse) {

} catch (javax.crypto.BadPaddingException bpe) {

}

The simplifications include removal of your assertions since the passphrase, salt and iteration count will be read from a database table.

My test program appears to work as I expected.

If I am not mistaken, the fact I can initialize a Cipher with the same key and parameter spec I used for the first one means that I can store the passphrase, salt and parameter spec data in an RDBMS, and recreate all of these objects in a second session using my program as they were in the first session using my program.

Is there anything to be gained, in terms of strengthening the security (confidentiality) of the data, by creating a second key and cipher using a different encryption algorithm, and then using the first only to wrap and unwrap the key that is used with the second cipher to encrypt the data?

Is "PBEWithMD5AndDES"as good as it gets for password based encryption, or are there better options with the providers provided in the SDK? Where can I find a list of the providers available in the SDK? I ask because in I have seen several references in the security documents from the SDK to different providers (e.g. "SunJCE", "SunJSSE"). Is there a table or list, somewhere on the web, or, better, on Sun's site, that lists all of the options available in the SDK in decreasing order of strength?

Thanks

Ted

Ted_Byersa at 2007-7-13 10:02:46 > top of Java-index,Security,Cryptography...
# 4

You can use AES with PBE if you use BouncyCastle provider. I use ythe following to see what is available

import java.security.*;

import java.util.Enumeration;

import javax.swing.*;

import javax.swing.tree.*;

import java.awt.*;

import java.util.*;

public class ListAlgorithms extends JFrame

{

private void getNodes(DefaultMutableTreeNode providerNode, Provider provider, Set<Provider.Service> used, String title, String target)

{

DefaultMutableTreeNode node = new DefaultMutableTreeNode(title);

for (Provider.Service service : provider.getServices())

{

if (!used.contains(service) && target.equalsIgnoreCase(service.getType()))

{

used.add(service);

DefaultMutableTreeNode algNode = new DefaultMutableTreeNode(service.getAlgorithm());

node.add(algNode);

algNode.add(new DefaultMutableTreeNode("class : " + service.getClassName()));

}

}

if (node.getChildCount() != 0)

{

providerNode.add(node);

}

}

private ListAlgorithms()

{

super("JCE Algorithms");

setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

DefaultMutableTreeNode root = new DefaultMutableTreeNode("Providers");

DefaultTreeModel treeModel = new DefaultTreeModel(root);

for (Provider provider : java.security.Security.getProviders())

{

DefaultMutableTreeNode providerNode = new DefaultMutableTreeNode(provider);

root.add(providerNode);

Set<Provider.Service> used = new HashSet<Provider.Service>();

getNodes(providerNode, provider, used, "Cipher", "cipher");

getNodes(providerNode, provider, used, "Key Agreement", "keyagreement");

getNodes(providerNode, provider, used, "Key Generator", "keygenerator");

getNodes(providerNode, provider, used, "Key Pair Generator", "keypairgenerator");

getNodes(providerNode, provider, used, "Key Factory", "keyfactory");

getNodes(providerNode, provider, used, "Secret Key Factory", "secretkeyfactory");

getNodes(providerNode, provider, used, "Mac", "mac");

getNodes(providerNode, provider, used, "Message Digest", "messagedigest");

getNodes(providerNode, provider, used, "Signature", "signature");

getNodes(providerNode, provider, used, "Algorithm Paramater", "algorithmparameters");

getNodes(providerNode, provider, used, "Algorithm Paramater Generator", "algorithmparametergenerator");

getNodes(providerNode, provider, used, "Key Store", "keystore");

getNodes(providerNode, provider, used, "Secure Random", "securerandom");

getNodes(providerNode, provider, used, "Certificate Factory", "certificatefactory");

getNodes(providerNode, provider, used, "Certificate Store", "certstore");

getNodes(providerNode, provider, used, "Key Manager Factory", "KeyManagerFactory");

getNodes(providerNode, provider, used, "Trust Manager Factory", "TrustManagerFactory");

getNodes(providerNode, provider, used, "SSL Context", "SSLContext");

getNodes(providerNode, provider, used, "Sasl Server Factory", "SaslServerFactory");

getNodes(providerNode, provider, used, "Sasl Client Factory", "SaslClientFactory");

{

DefaultMutableTreeNode node = new DefaultMutableTreeNode("Other");

for (Provider.Service service : provider.getServices())

{

if (!used.contains(service))

{

DefaultMutableTreeNode serviceNode = new DefaultMutableTreeNode(service.getType() + " : " + service.getAlgorithm());

node.add(serviceNode);

serviceNode.add(new DefaultMutableTreeNode("class : " + service.getClassName()));

}

}

if (node.getChildCount() != 0)

providerNode.add(node);

}

}

JTree tree = new JTree(treeModel);

tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);

tree.setEditable(false);

JScrollPane pane = new JScrollPane(tree);

pane.setPreferredSize(new Dimension(200, 200));

getContentPane().add(pane);

pack();

}

public static void main(String[] args)

{

Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

System.out.println("Providers -");

for (Provider provider : java.security.Security.getProviders())

{

System.out.println("" + provider.getName());

for (Enumeration en = provider.propertyNames(); en.hasMoreElements();)

{

String alg = (String)en.nextElement();

if (alg.toLowerCase().matches(".*pbe.*") && (alg.toLowerCase().matches(".*aes.*") || alg.toLowerCase().matches(".*blowfish.*")))

//if (alg.matches("(?i)Cipher.*rc2.*"))

System.out.println("Alg = " + alg);

}

}

new ListAlgorithms().setVisible(true);

}

}

sabre150a at 2007-7-13 10:02:46 > top of Java-index,Security,Cryptography...