4

我有在 ColdFusion 中加密的数据,我需要能够使用 Java 解密和加密到相同的确切值。我希望有人可以帮助我解决这个问题。除了实际的 PasswordKey 之外,我将指定 ColdFusion 中使用的所有内容,出于安全目的,我必须对其保密。PasswordKey 的长度为 23 个字符。它使用大小写字母、数字以及 + 和 = 符号。我知道这是很多问题,但任何帮助将不胜感激。

我尝试使用我在网上找到的 Java 加密示例,并将下面的行替换为我们的 CF 应用程序中使用的 23 个字符:

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

但我得到了错误:

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

CF 代码为:

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>
4

4 回答 4

2

您的密钥很可能是 Base64 编码的密钥(23 个字符应解码为大约 16 个字节,这是 AES 的 128 位密钥的正确长度)。

因此,在您的 java 代码中,首先通过 Base64 解码器运行您的密钥字符串,以获得 AES 算法的适当长度(16 个字节)的字节 []。

于 2012-06-13T14:57:33.863 回答
2

128 但 AES 加密支持 16 字节的密钥密钥大小。
16 * 8 = 128 位,即使在示例中,密钥也是 16 字节。

听起来你的密钥在 Base64 中,所以使用 Base64.decode(key or key.getBytes()) 来获取字节数组,检查它的 16 个字节,否则通过填充使其成为 16 个字节。

于 2012-06-13T14:58:21.253 回答
1

感谢大家的帮助。我想发布我的最终解决方案供其他人使用。我包括我的整个加密包代码减去特定的密码密钥(再次为了安全起见)。此代码创建与问题中列出的 CF 代码相同的十六进制字符串,并将其解密回正确的英文文本字符串。

我在 stackoverflow 上的其他问题中找到了bytesToHexand hexStringToByteArray函数,所以我也分别感谢用户 mayWeCouldStealAVan 和 Dave L.。我想我会研究其他 base 64 编码器/解码器,以防来自 sun 的编码器/解码器不可用,但这肯定适用于现在。再次感谢。

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; 
    } 

}
于 2012-06-13T17:04:18.253 回答
0

AES 加密仅支持 128 位、192 位或 256 位的密钥大小。

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

您不能只取任何字节数组并将其用作 AES 密钥。在您在上面看到的示例代码中,该示例巧妙地使用了 16 个字符,对应于 128 位密钥。

这是因为 1 个字符或者更确切地说 1 个字节对应 8 位。

一个 16 值的字节数组将对应于16 * 8 = 128 bits

23 个字符 = 23 * 8 = 184 bits,因此它是无效的密钥大小。

您需要 16 个字符、24 个字符或 32 个字符。

话虽如此,仅使用字符进行 AES 加密是非常不安全的。请务必使用适当且安全的随机密钥进行加密。

要生成安全且随机的 AES 密钥:

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

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

于 2012-06-13T14:54:12.120 回答