views:

330

answers:

1

* sweet - thanks to Edward Smith for the CF Technote that indicated the key from ColdFusion was Base64 encoded. See generateKey() for the 'fix'

My task is to use Java 1.4.2 to match the results a given ColdFusion code sample for encryption.

Known/given values:

  • A 24-byte key
  • A 16-byte salt (IVorSalt)
  • Encoding is Hex
  • Encryption algorithm is AES/CBC/PKCS5Padding
  • A sample clear-text value
  • The encrypted value of the sample clear-text after going through the ColdFusion code

Assumptions:

  • Number of iterations not specified in the ColdFusion code so I assume only one iteration
  • 24-byte key so I assume 192-bit encryption

Given/working ColdFusion encryption code sample:

<cfset ThisSalt = "16byte-salt-here">
<cfset ThisAlgorithm = "AES/CBC/PKCS5Padding">
<cfset ThisKey = "a-24byte-key-string-here">
<cfset thisAdjustedNow = now()>
<cfset ThisDateTimeVar = DateFormat( thisAdjustedNow , "yyyymmdd" )>
<cfset ThisDateTimeVar = ThisDateTimeVar & TimeFormat( thisAdjustedNow , "HHmmss" )>
<cfset ThisTAID = ThisDateTimeVar & "|" & someOtherData>
<cfset ThisTAIDEnc = Encrypt( ThisTAID , ThisKey , ThisAlgorithm , "Hex" , ThisSalt)>

My Java 1.4.2 encryption/decryption code swag:

package so.example;

import java.security.*;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.*;

public class SO_AES192 {

private static final String _AES = "AES";
private static final String _AES_CBC_PKCS5Padding = "AES/CBC/PKCS5Padding";
private static final String KEY_VALUE = "a-24byte-key-string-here";
private static final String SALT_VALUE = "16byte-salt-here";
private static final int ITERATIONS = 1;

private static IvParameterSpec ivParameterSpec;

public static String encryptHex(String value) throws Exception {
    Key key = generateKey();

    Cipher c = Cipher.getInstance(_AES_CBC_PKCS5Padding);
    ivParameterSpec = new IvParameterSpec(SALT_VALUE.getBytes());
    c.init(Cipher.ENCRYPT_MODE, key, ivParameterSpec);

    String valueToEncrypt = null;
    String eValue = value;
    for (int i = 0; i < ITERATIONS; i++) {
//            valueToEncrypt = SALT_VALUE + eValue; // pre-pend salt - Length > sample length
        valueToEncrypt =  eValue;     // don't pre-pend salt  Length = sample length
        byte[] encValue = c.doFinal(valueToEncrypt.getBytes());
        eValue =  Hex.encodeHexString(encValue);
    }
    return eValue;
}

public static String decryptHex(String value) throws Exception {
    Key key = generateKey();

    Cipher c = Cipher.getInstance(_AES_CBC_PKCS5Padding);
    ivParameterSpec = new IvParameterSpec(SALT_VALUE.getBytes());
    c.init(Cipher.DECRYPT_MODE, key, ivParameterSpec);

    String dValue = null;
    char[] valueToDecrypt = value.toCharArray();
    for (int i = 0; i < ITERATIONS; i++) {
        byte[] decordedValue = Hex.decodeHex(valueToDecrypt);
        byte[] decValue = c.doFinal(decordedValue);
//            dValue = new String(decValue).substring(SALT_VALUE.length()); // when salt is pre-pended
        dValue = new String(decValue);   // when salt is not pre-pended
        valueToDecrypt = dValue.toCharArray();
    }
    return dValue;
}

private static Key generateKey() throws Exception {
    // Key key = new SecretKeySpec(KEY_VALUE.getBytes(), _AES); // this was wrong
    Key key = new SecretKeySpec(new BASE64Decoder().decodeBuffer(keyValueString), _AES); // had to un-Base64 the 'known' 24-byte key.
    return key;
}

}

I cannot create a matching encrypted value nor decrypt a given encrypted value. My guess is it's something to do with how I'm handling the initial vector/salt.

I'm not very crypto-savvy but I'm thinking I should be able to take the sample clear-text and produce the same encrypted value in Java as ColdFusion produced. I am able to encrypt/decrypt my own data with my Java code (so I'm consistent) but I cannot match nor decrypt the ColdFusion sample encrypted value.

I have access to a local webservice that can test the encrypted output. The given ColdFusion output sample passes/decrypts fine (of course). If I try to decrypt the same sample with my Java code (using the actual key and salt) I get a "Given final block not properly padded" error. I get the same net result when I pass my attempt at encryption (using the actual key and salt) to the test webservice.

Any Ideas?

+4  A: 

Is the value in the Coldfusion ThisKey:

<cfset ThisKey = "a-24byte-key-string-here">

The exact same string that is returned from the java generateKey() function? I believe they need to be to be the same string for the generated encrypted text to be the same.

To use a fixed key like that in CF, you may need to follow this from the CF technote on strong encryption:

You may want to generate your own key for two reasons:

  1. You want to match the details of other encryption software.
  2. You want to increase the resistance to cracking of your encrypted data by pattern-oriented cryptanalysis techniques.

For example, to create a 32-byte key to use with the AES algorithm with the hex value:

8738fed68e7677d374e0946c8f7bd3bb4f50f23717f9f3667b2419483959039c

you would use the ColdFusion functions BinaryDecode and ToBase64 to create the key:

<cfset myKey =
ToBase64(BinaryDecode("8738fed68e7677d374e0946c8f7bd3bb4f50f23717f9f3667b2419483959039c","Hex")>
<cfset encrypted =Encrypt(myString, myKey, "AES")>

EDIT: Just realized that the key (as you mentioned in your comment) is base64, so if the "generateKey" method in Java looks like:

private static Key generateKey() throws Exception {
final byte[] decodedKey = new BASE64Decoder().decodeBuffer(KEY_VALUE);
final Key key = new SecretKeySpec(decodedKey, _AES);
return key;
}

You should be golden.

Edward M Smith
Thanks man -- The generateKey() method creates a Key object that contains the Algorithm "AES" and a byte array from the known key so it matches. BUT...apparently the sample key (passed in a word doc was bas64 encoded and had to be un-encoded before I could use it. I made the change and updated the sample Java code. All is well in the world... for now...
JohnTheBarber