kei23th
kei23th

Reputation: 283

How can I encrypt a string in Java to be the exact same as it is encrypted in ColdFusion?

I have data encrypted in ColdFusion that I need to be able to decrypt and encrypt to the same exact value using Java. I was hoping someone may be able to help me with this. I will specify everything used in ColdFusion except for the actual PasswordKey, which I must keep secret for security purposes. The PasswordKey is 23 characters long. It uses upper and lowercase letters, numbers, and the + and = signs. I know this is a lot to ask, but any help would be greatly appreciated.

I tried using a Java encryption example I found online and just replacing the line below with the 23 characters used in our CF app:

private static final byte[] keyValue = new byte[] {'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y' };` 

But I get the error:

java.security.InvalidKeyException: Invalid AES key length: 23 bytes

The CF code is:

Application.PasswordKey = "***********************";
Application.Algorithm = "AES";
Application.Encoding = "hex";

<cffunction name="encryptValue" access="public" returntype="string">
        <cfargument name="strEncryptThis" required="yes">

        <cfreturn Encrypt(TRIM(strEncryptThis), Application.PasswordKey, Application.Algorithm, Application.Encoding)>
</cffunction>


<cffunction name="decryptValue" access="public" returntype="string">
    <cfargument name="strDecryptThis" required="yes">

    <cfreturn Decrypt(TRIM(strDecryptThis), Application.PasswordKey, Application.Algorithm, Application.Encoding)>
</cffunction>

Upvotes: 4

Views: 4293

Answers (4)

kei23th
kei23th

Reputation: 283

Thank you everyone for your help. I wanted to post my final solution for others to use. I am including my entire encryption package code minus the specific password key (again for security). This code creates the same hex string as the CF code listed in the question, and decrypts it back to the proper english text string.

I found the bytesToHex and hexStringToByteArray functions in other question on stackoverflow, so my thanks to users maybeWeCouldStealAVan and Dave L. respectively also. I think I will look into other base 64 encoders/decoders in case the one from sun is ever made unavailable, but this definitely works for now. Thanks again.

package encryptionpackage;

import java.security.*;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.Cipher; 
import javax.crypto.spec.SecretKeySpec;
import sun.misc.*;

public class encryption 
{
    // Note: The full CF default is "AES/ECB/PKCS5Padding"
    private static final String ALGORITHM = "AES";
    // The 24 character key from my CF app (base64 encoded)
    // typically generated with:  generateSecretKey("AES") 
    private static final String passKey = "***********************"; 

     public static String encrypt(String valueToEnc) throws Exception 
     {
        Key key = generateKey();
        Cipher c = Cipher.getInstance(ALGORITHM);
        c.init(Cipher.ENCRYPT_MODE, key);
        byte[] encValue = c.doFinal(valueToEnc.getBytes());
        String encryptedValue = bytesToHex(encValue);
        return encryptedValue;
    }

    public static String decrypt(String encryptedValue) throws Exception 
    {
        Key key = generateKey();
        Cipher c = Cipher.getInstance(ALGORITHM);
        c.init(Cipher.DECRYPT_MODE, key);
        byte[] decordedValue = hexStringToByteArray(encryptedValue);
        byte[] decValue = c.doFinal(decordedValue);
        String decryptedValue = new String(decValue);
        return decryptedValue;
    }

    private static Key generateKey() throws Exception 
    {
          byte[] keyValue;
          keyValue = new BASE64Decoder().decodeBuffer(passKey);
        Key key = new SecretKeySpec(keyValue, ALGORITHM);

        return key;
    }

    public static String bytesToHex(byte[] bytes) 
    { 
        final char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; 
        char[] hexChars = new char[bytes.length * 2]; 
        int v; 
        for ( int j = 0; j < bytes.length; j++ ) 
        { 
            v = bytes[j] & 0xFF; 
            hexChars[j * 2] = hexArray[v >>> 4]; 
            hexChars[j * 2 + 1] = hexArray[v & 0x0F]; 
        } 
        return new String(hexChars); 
    } 

    public static byte[] hexStringToByteArray(String s) 
    { 
        int len = s.length(); 
        byte[] data = new byte[len / 2]; 
        for (int i = 0; i < len; i += 2) 
        { 
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) 
                                 + Character.digit(s.charAt(i+1), 16)); 
        } 
        return data; 
    } 

}

Upvotes: 1

maaz
maaz

Reputation: 4493

128 but AES Encryption supports key key size of 16 bytes.
16 * 8 = 128 bits, even in the example the key is 16 bytes.

Sounds like your key is in Base64 so use Base64.decode(key or key.getBytes()) to get the byte array, check its in 16 bytes otherwise make it 16 bytes by padding.

Upvotes: 2

jtahlborn
jtahlborn

Reputation: 53694

Your secret key is most likely a Base64 encoded key (23 chars should decode to about 16 bytes, which is the right length for a 128 bit key for AES).

So, in your java code, first run your secret key string through a Base64 decoder to get a byte[] of the appropriate length (16 bytes) for the AES algorithm.

Upvotes: 2

Lai Xin Chu
Lai Xin Chu

Reputation: 2482

AES Encryption only supports a key-size of 128 bits, 192 bits or 256 bits.

http://en.wikipedia.org/wiki/Advanced_Encryption_Standard

You can't just take any byte array and use it as an AES key. In the sample code you see above, the example cleverly used 16 characters, which corresponds to a 128-bit key.

This is because 1 character or rather 1 byte corresponds to 8 bits.

A 16-value byte array will then correspond to 16 * 8 = 128 bits

23 characters = 23 * 8 = 184 bits, thus it is an invalid key-size.

You need either 16 characters, 24 characters, or 32 characters.

That being said, using merely characters for AES encryption is extremely insecure. Do use a proper and secure random key for encrypt purposes.

To generate a secure and random AES key:

SecureRandom random = new SecureRandom();
byte [] secret = new byte[16];
random.nextBytes(secret);

http://docs.oracle.com/javase/6/docs/api/java/security/SecureRandom.html

Upvotes: 0

Related Questions