Problem Encrypting/Decrypting

Hi all,

I'm a bit of a newb in java development, and having some trouble getting an implementation of symmetric encryption working. Basically, the design for the program I'm building uses the following encryption paradigm:

1. User enters username/password

2. System checks DB for salt associated with that username (caveat-only 1 user expected per installation)

3. System takes password, hashes it using default Sun SHA-512 message digest to build a decryption key

4. System uses decryption key created in step 3 to decrypt an authentication string stored in the DB using PBEwithMD5andDES.

So, steps 1-3 work. Step 4 is having issues. Right now, I have a test program which takes a default password, hashes it, builds cipher objects using the hash, and then attempts to encrypt then decrypt the string. (This is basically just a proof-of-concept to prove that I can reliably decrypt data.) The problem is that when I decrypt the byte array, I don't get the original byte array I encrypted.

For reference, here is my encryption/decryption cipher routines that I'm using. I made a local cipher class which creates two JCE cypher objects, one for encryption and one for decryption, based on the same salt, iteration count, and password. I based this code off of the sample PBE code found here:

http://java.sun.com/j2se/1.5.0/docs/guide/security/jce/JCERefGuide.html#PBEEx

My cipher class:

package zen.client.authentication;

public class Cipher {

byte[] key;

javax.crypto.Cipher Encrypter;

javax.crypto.Cipher Decrypter;

public Cipher(byte[] encryptionKey, byte[] salt)

{

// Declare encryption structures

javax.crypto.spec.PBEKeySpec pbeKeySpec;

javax.crypto.spec.PBEParameterSpec pbeParamSpec;

javax.crypto.SecretKeyFactory keyFac;

int iterationCount = 55;

// use the hashed encryption key as our "password"

key = encryptionKey;

// Initialize the ciphers for encryption and decryption

try {

Encrypter = javax.crypto.Cipher.getInstance("PBEWithMD5AndDES");

Decrypter = javax.crypto.Cipher.getInstance("PBEWithMD5AndDES");

// Create PBE parameter set

pbeParamSpec = new javax.crypto.spec.PBEParameterSpec(salt, iterationCount);

// Convert key SecretKey object

pbeKeySpec = new javax.crypto.spec.PBEKeySpec(key.toString().toCharArray());

keyFac = javax.crypto.SecretKeyFactory.getInstance("PBEWithMD5AndDES");

javax.crypto.SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec);

// Initialize PBE Cipher with key and parameters

Encrypter.init(javax.crypto.Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec);

Decrypter.init(javax.crypto.Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec);

}

catch (Exception e){

e.printStackTrace();

}

}

public byte[] encrypt(String text){

byte[] test = null;

byte[] test2 = text.getBytes();

System.out.println("Cleartext Original: " + text);

System.out.println("Cleartext in bytes: " + bytes_to_byte_string(test2));

System.out.println("Cleartext in chars: " + bytes_to_char_string(test2));

// Encrypt using Encrypter

try{

test = Encrypter.doFinal(text.getBytes());

}

catch (Exception e){

e.printStackTrace();

}

System.out.println("Ciphertext in bytes: " + bytes_to_byte_string(test));

System.out.println("Ciphertext in chars: " + bytes_to_char_string(test));

return test;

}

public String decrypt(byte[] data){

byte[] test = null;

System.out.println("Encrypted bytes:" + bytes_to_byte_string(data));

System.out.println("Encrypted chars:" + bytes_to_char_string(data));

// Decrypt using Encrypter

try{

test = Decrypter.doFinal(data);

}

catch (Exception e){

e.printStackTrace();

}

System.out.println("Unencrypted bytes:" + bytes_to_byte_string(test));

System.out.println("Unencrypted chars:" + bytes_to_char_string(test));

return bytes_to_char_string(test);

}

private String bytes_to_byte_string(byte[] input)

{

StringBuffer text = new StringBuffer();

// Iterate through the bytes and append to the string buffer

for (int i = 0; i < input.length; i++)

text.append(input[ i ]);

// Return the resulting string

return text.toString();

}

private String bytes_to_char_string(byte[] input)

{

StringBuffer text = new StringBuffer();

// Iterate through the bytes and append to the string buffer

for (int i = 0; i < input.length; i++)

text.append((char)input[ i ]);

// Return the resulting string

return text.toString();

}

}

Also for reference, here is my test program which uses this class:

package zen.client.authentication;

public class TestClass2 {

public static void main(String[] args) {

// TODO Auto-generated method stub

Cipher authCipher;

byte[] random_number = {

(byte)0xc7, (byte)0x73, (byte)0x21, (byte)0x8c,

(byte)0x7e, (byte)0xc8, (byte)0xee, (byte)0x99

};

String pass1 = "password";

StringBuffer pw1 = new StringBuffer().append(pass1);

byte[] result1 = null;

String encryptionString = "ZoMg It wOrKs9{?^j$Q}]|2";

String authenticationText = "ZoMg It wOrKs";

try{

// Build a MessageDigest (1-way hash) object

java.security.MessageDigest md1 = java.security.MessageDigest.getInstance("SHA-512");

java.security.MessageDigest md2 = java.security.MessageDigest.getInstance("SHA-512");

// Initialize MD object

md1.reset();

// Add the password to the MD object via the update method

md1.update(pw1.toString().getBytes());

// Add the salt as well to further randomize the result

md1.update(random_number);

// Complete the encryption and return the result

result1 = md1.digest();

}

catch (Exception e){

e.printStackTrace();

}

// Create authentication cipher with this key

authCipher = new Cipher(result1, random_number);

// Encrypt Encryption String using authentication cipher

byte[] encryptedData = authCipher.encrypt(encryptionString);

// Decrypt Encryption String using authentication cipher

String decryptedString = authCipher.decrypt(encryptedData);

/*

// Parse the Authentication Text

String authText = decryptedEncryptionString.substring(0, 12);

// Check to see if we've matched the Authentication Text

if (authText.equals(authenticationText))

// User is authenticated.

System.out.println("It works!");

else

System.out.println("It failed!"); */

}

}

Any help anyone could provide for figuring out why the decryption mechanism isn't working would be appreciated. Right now my guesses are:

1. Something is wrong with the "PBEWithMD5AndDES" algorithm I'm using (I tried downloading bouncycastle's implementation, but I can't get it to work)

2. I didn't initialize the decryption cipher correctly (although both ciphers take the exact same parameters)

3. I *have* to use the same cipher for encryption & decryption, I just have to reinitialize it for encryption/decryption every time I need to use it.

Thanks for any help you can provide.

[7444 byte] By [novakoma] at [2007-11-27 6:30:53]
# 1

Please use the [ code ] tags so we can read your code.

You're doing a ton of work to your password which duplicates the work that PBEWith... is doing. In fact, you've made PBEWith pointless.

But the real problem, I suspect, is this:Decrypter.init(javax.crypto.Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec);

I suspect your Decrypter doesn't want to be initialized in ENcrypt mode...

The following code works for me:package javaforum;

public class Cipher {

String key;

javax.crypto.Cipher Encrypter;

javax.crypto.Cipher Decrypter;

public Cipher(String inKey, byte[] salt) {

// Declare encryption structures

javax.crypto.spec.PBEKeySpec pbeKeySpec;

javax.crypto.spec.PBEParameterSpec pbeParamSpec;

javax.crypto.SecretKeyFactory keyFac;

int iterationCount = 55;

// use the hashed encryption key as our "password"

key = inKey;

// Initialize the ciphers for encryption and decryption

try {

Encrypter = javax.crypto.Cipher.getInstance("PBEWithMD5AndDES");

Decrypter = javax.crypto.Cipher.getInstance("PBEWithMD5AndDES");

// Create PBE parameter set

pbeParamSpec = new javax.crypto.spec.PBEParameterSpec(salt, iterationCount);

// Convert key SecretKey object

pbeKeySpec = new javax.crypto.spec.PBEKeySpec(inKey.toCharArray());

keyFac = javax.crypto.SecretKeyFactory.getInstance("PBEWithMD5AndDES");

javax.crypto.SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec);

// Initialize PBE Cipher with key and parameters

Encrypter.init(javax.crypto.Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec);

Decrypter.init(javax.crypto.Cipher.DECRYPT_MODE, pbeKey, pbeParamSpec);

}

catch (Exception e) {

e.printStackTrace();

}

}

public byte[] encrypt(String text) {

try {

return Encrypter.doFinal(text.getBytes());

}

catch (Exception e) {

e.printStackTrace();

return null;

}

}

public String decrypt(byte[] data) {

try {

return new String(Decrypter.doFinal(data));

}

catch (Exception e) {

e.printStackTrace();

return null;

}

}

public static void main(String[] args) {

Cipher authCipher;

byte[] random_number = { (byte) 0xc7, (byte) 0x73, (byte) 0x21, (byte) 0x8c,

(byte) 0x7e, (byte) 0xc8, (byte) 0xee, (byte) 0x99 };

String pass1 = "password";

String encryptionString = "ZoMg It wOrKs9{?^j$Q}]|2";

// Create authentication cipher with this key

authCipher = new Cipher(pass1, random_number);

// Encrypt Encryption String using authentication cipher

byte[] encryptedData = authCipher.encrypt(encryptionString);

// Decrypt Encryption String using authentication cipher

String decryptedString = authCipher.decrypt(encryptedData);

System.out.println("plaintext: ["+encryptionString+"]");

System.out.println("decrypted: ["+decryptedString+"]");

}

}

G

ggaineya at 2007-7-12 17:55:38 > top of Java-index,Security,Cryptography...
# 2
Wow, I feel dumb. I plead newb! Many, many thanks. Copy/paste error Go!Apologies for the lack of [ code ] tags, I'll fix that in the future.
novakoma at 2007-7-12 17:55:38 > top of Java-index,Security,Cryptography...
# 3

> Wow, I feel dumb. I plead newb! Many, many thanks.

> Copy/paste error Go!

He who Lives by the Cut-Buffer, DIES by the Cut-Buffer. :) No worries - been there, done that, wasted lotsandlotsandLOTS of debug time finding it...

> pologies for the lack of [ code ] tags, I'll fix that

> in the future.

Outstanding, thanks.

G

ggaineya at 2007-7-12 17:55:38 > top of Java-index,Security,Cryptography...