Java的SimpleCrypto类的加密/解密生产ColdFusion的9和Java不同的结果(安卓) [英] Java SimpleCrypto Class for encryption / decryption producing different results in Coldfusion 9 and Java (Android)

查看:412
本文介绍了Java的SimpleCrypto类的加密/解密生产ColdFusion的9和Java不同的结果(安卓)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用广泛使用的SimpleCrypto Java类加密的字符串的Java(Android版)以及字符串中的ColdFusion 9(反之亦然)进行解密。我已经进口了完全相同的SimpleCrypto类为ColdFusion和称它是这样的:

 < CFSET的myKey =苹果>
< CFSCRIPT>
    SC =的CreateObject(Java的,SimpleCrypto)的init()。
    加密= sc.encrypt(的myKey,约翰);
< / CFSCRIPT>
&所述; cfdump变种=#加密#>
 

在与苹果的密钥加密字符串约翰则输出这CF:9E90A36325AE4F4F7352D6469A7068A2

当我在Android中使用完全相同的类:

 字符串键=苹果;
尝试 {
    sEncrypted = SimpleCrypto.encrypt(键,约翰);
    Log.d(TAG,sEncrypted);
 }赶上(例外五){
     e.printStackTrace();
 }
 

日志输出:CBE2ADDBA9882F545DFEC1700E7CD518

不用说,我要去疯狂,因为这些结果是不同的。有谁知道为什么用完全相同的code中的ColdFusion和Java会产生不同的结果?任何帮助将大大AP preciated。

下面是源$ C ​​$下SimpleCrypto.java:

 进口java.security.SecureRandom中;

进口javax.crypto.Cipher中;
进口javax.crypto.KeyGenerator;
进口javax.crypto.SecretKey;
进口javax.crypto.spec.SecretKeySpec;

/ **
 * 用法:
 *< pre>
 *字符串加密= SimpleCrypto.encrypt(masterpassword和明文)
 * ...
 *字符串明文= SimpleCrypto.decrypt(masterpassword和密码)
 *< / pre>
 * @author ferenc.hechler
 * /

公共类SimpleCrypto {

    公共静态字符串加密(字符串种子,字符串明文)抛出异常{
            byte []的rawKey = getRawKey(seed.getBytes());
            byte []的结果=加密(rawKey,cleartext.getBytes());
            返回toHex(结果);
    }

    公共静态字符串解密(字符串种子,字符串加密)抛出异常{
            byte []的rawKey = getRawKey(seed.getBytes());
            byte []的ENC = toByte(加密);
            byte []的结果=解密(rawKey,ENC);
            返回新的字符串(结果);
    }

    私有静态的byte [] getRawKey(byte []的种子)抛出异常{
            的KeyGenerator kgen = KeyGenerator.getInstance(AES);
            SecureRandom的SR = SecureRandom.getInstance(SHA1PRNG);
            sr.setSeed(种子);
        kgen.init(128,SR); // 192和256位可能无法使用
        SecretKey的SKEY = kgen.generateKey();
        byte []的原料= skey.getEn codeD();
        回归原始;
    }


    私有静态byte []的加密(byte []的原料,byte []的明确)抛出异常{
        SecretKeySpec skeySpec =新SecretKeySpec(原AES);
            密密码= Cipher.getInstance(AES);
        cipher.init(Cipher.ENCRYPT_MODE,skeySpec);
        byte []的加密= cipher.doFinal(清晰);
            返回加密;
    }

    私有静态的byte []解密(byte []的原料,byte []的加密)抛出异常{
        SecretKeySpec skeySpec =新SecretKeySpec(原AES);
            密密码= Cipher.getInstance(AES);
        cipher.init(Cipher.DECRYPT_MODE,skeySpec);
        byte []的解密= cipher.doFinal(加密);
            返回解密;
    }

    公共静态字符串toHex(字符串TXT){
            返回toHex(txt.getBytes());
    }
    公共静态字符串fromHex(十六进制字符串){
            返回新的String(toByte(十六进制));
    }

    公共静态的byte [] toByte(字符串十六进制串){
            INT的len = hexString.length()/ 2;
            byte []的结果=新的字节[长度];
            的for(int i = 0; I< LEN;我++)
                    结果[I] = Integer.valueOf(hexString.substring(2 * I,2 * I + 2),16).byteValue();
            返回结果;
    }

    公共静态字符串toHex(byte []的BUF){
            如果(BUF == NULL)
                    返回 ;
            StringBuffer的结果=新的StringBuffer(2 * buf.length);
            的for(int i = 0; I< buf.length;我++){
                    appendHex(结果,BUF [I]);
            }
            返回result.toString();
    }
    私人最终静态字符串HEX =0123456789ABCDEF;
    私有静态无效appendHex(StringBuffer的某人,字节B){
            sb.append(HEX.charAt((B>> 4)及为0x0F))。追加(HEX.charAt(B&安培;为0x0F));
    }

}
 

解决方案

getRawKey()方法是有缺陷的。它使用的实例的SecureRandom ,而不是一个密钥导出函数(KDF)。

根据不同的执行情况,过setSeed()方法要么种子的添加到当前的状态,或将其用作唯一的种子的。甲骨文提供者在Java SE 7和之前将使用它作为单一的种子,其他供应商如在Android的最新版本基于OpenSSL的可能只是种子添加到状态。

此外,SHA1PRNG的具体实施并没有得到很好的界定。所以不同的提供者可使用不同的实现。请使用随机数生成的SecureRandom 实例而已。

如果您有密码,请使用基于密码的密钥导出函数,如PBKDF2将其转换为一个合适的密钥。如果你有足够的熵一个秘密,你可以尝试,并找到一把钥匙基于密钥导出函数(KBKDF)的实现,例如香港民主促进会在充气城堡。

除了密钥推导,还有编码/与样品code以及解码的问题。不要使用它,这是一个可怕的例子。

I am trying to use the widely used SimpleCrypto java class to encrypt a string in Java (Android) and decrypt the string in ColdFusion 9 (and vice versa). I have imported the exact same SimpleCrypto class into ColdFusion and called it like this:

<cfset myKey = "apple">
<cfscript>
    sc = createObject("java", "SimpleCrypto").init();
    encrypted = sc.encrypt(myKey, "john");
</cfscript>
<cfdump var="#encrypted#">

When encrypting the string "john" with a key of "apple" it outputs this in CF: 9E90A36325AE4F4F7352D6469A7068A2

When I use the EXACT SAME class in Android:

String key = "apple";    
try {
    sEncrypted = SimpleCrypto.encrypt(key, "john");
    Log.d(TAG, sEncrypted);
 } catch (Exception e) {
     e.printStackTrace();
 }

The log outputs: CBE2ADDBA9882F545DFEC1700E7CD518

Needless to say, I'm going bonkers because these results are different. Does anyone know why using the same exact code in ColdFusion and Java would produce different results? Any help would be greatly appreciated.

Here is the source code for SimpleCrypto.java:

import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

/**
 * Usage:
 * <pre>
 * String crypto = SimpleCrypto.encrypt(masterpassword, cleartext)
 * ...
 * String cleartext = SimpleCrypto.decrypt(masterpassword, crypto)
 * </pre>
 * @author ferenc.hechler
 */

public class SimpleCrypto {

    public static String encrypt(String seed, String cleartext) throws Exception {
            byte[] rawKey = getRawKey(seed.getBytes());
            byte[] result = encrypt(rawKey, cleartext.getBytes());
            return toHex(result);
    }

    public static String decrypt(String seed, String encrypted) throws Exception {
            byte[] rawKey = getRawKey(seed.getBytes());
            byte[] enc = toByte(encrypted);
            byte[] result = decrypt(rawKey, enc);
            return new String(result);
    }

    private static byte[] getRawKey(byte[] seed) throws Exception {
            KeyGenerator kgen = KeyGenerator.getInstance("AES");
            SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
            sr.setSeed(seed);
        kgen.init(128, sr); // 192 and 256 bits may not be available
        SecretKey skey = kgen.generateKey();
        byte[] raw = skey.getEncoded();
        return raw;
    }


    private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encrypted = cipher.doFinal(clear);
            return encrypted;
    }

    private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.DECRYPT_MODE, skeySpec);
        byte[] decrypted = cipher.doFinal(encrypted);
            return decrypted;
    }

    public static String toHex(String txt) {
            return toHex(txt.getBytes());
    }
    public static String fromHex(String hex) {
            return new String(toByte(hex));
    }

    public static byte[] toByte(String hexString) {
            int len = hexString.length()/2;
            byte[] result = new byte[len];
            for (int i = 0; i < len; i++)
                    result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue();
            return result;
    }

    public static String toHex(byte[] buf) {
            if (buf == null)
                    return "";
            StringBuffer result = new StringBuffer(2*buf.length);
            for (int i = 0; i < buf.length; i++) {
                    appendHex(result, buf[i]);
            }
            return result.toString();
    }
    private final static String HEX = "0123456789ABCDEF";
    private static void appendHex(StringBuffer sb, byte b) {
            sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f));
    }

}

解决方案

The getRawKey() method is flawed. It uses an instance of SecureRandom instead of a key derivation function (KDF).

Depending on the implementation, the setSeed() method will either add the seed to the current state or it will use it as the only seed. The Oracle provider in Java SE 7 and before will use it as the single seed, other providers such as those based on OpenSSL in the latest versions of Android may simply add the seed to the state.

Furthermore, the exact implementation of "SHA1PRNG" has not been well defined. So different providers may use a different implementations. Please use SecureRandom instances for random number generation only.

If you have a password, use a Password Based Key Derivation Function such as PBKDF2 to convert it to a suitable key. If you have a secret with enough entropy, you could try and find an implementation of a Key Based Key Derivation Function (KBKDF), for instance HKDF in Bouncy Castle.

Besides the key derivation, there are encoding/decoding issues with that sample code as well. Don't use it, it is a terrible example.

这篇关于Java的SimpleCrypto类的加密/解密生产ColdFusion的9和Java不同的结果(安卓)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆