加密算法在Android 2.1及2.1以上版本上提供不同的结果

时间:2013-05-03 11:37:48

标签: android encryption

在发布此问题之前,我已经搜索了很多。早期的代码是在非Android 4.2 / 2.1设备上工作。然后我用Google搜索并介绍了下面的代码行。这部分地解决了它,即它现在正在4.2设备上工作但不在Froyo上工作。

    if (android.os.Build.VERSION.SDK_INT >= JELLY_BEAN_4_2) {
    sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
} else {
    sr = SecureRandom.getInstance("SHA1PRNG");
}

以下给出的是我用于加密的类

    public class Encryption {
private final static String HEX = "0123456789ABCDEF";
private final static int JELLY_BEAN_4_2 = 17;
private final static byte[] key = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0 };

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

public static String decrypt(String seed, String encrypted)
        throws Exception {
    byte[] seedByte = seed.getBytes();
    System.arraycopy(seedByte, 0, Constants.SEED, 0,
            ((seedByte.length < 16) ? seedByte.length : 16));
    String base64 = new String(Base64.decode(encrypted, 0));
    byte[] rawKey = getRawKey(seedByte);
    byte[] enc = toByte(base64);
    byte[] result = decrypt(rawKey, enc);
    return new String(result);
}

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

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

private static byte[] getRawKey(byte[] seed) throws Exception {
    KeyGenerator kgen = KeyGenerator.getInstance("AES");
    SecureRandom sr = null;
    if (android.os.Build.VERSION.SDK_INT >= JELLY_BEAN_4_2) {
        sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
    } else {
        sr = SecureRandom.getInstance("SHA1PRNG");
    }
    sr.setSeed(seed);
    try {
        kgen.init(256, sr);
    } catch (Exception e) {
        // "This device doesn't suppor 256bits, trying 192bits.");
        try {
            kgen.init(192, sr);
        } catch (Exception e1) {
             Log.w(LOG,
             "This device doesn't suppor 192bits, trying 128bits.");
            kgen.init(128, sr);
        }
    }
    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 static void appendHex(StringBuffer sb, byte b) {
    sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
}

}

代码在非froyo设备上正常运行。但是在froyo上,加密产生的结果与非froyo设备不同。

1 个答案:

答案 0 :(得分:2)

你滥用伪随机数生成器,它的种子作为一个关键的派生函数 - 这真的是非常糟糕的风格。伪随机数生成器“SHA1PRNG”不是像AES那样的标准 - 因此您永远不知道您获得了什么实现。 另请参阅Is there a SHA1PRNG standard

难怪你得到不同的结果。获取基于给定种子的确定性结果不是您可以从伪随机数函数中获得的属性。

如果您想从密码中获取加密密钥,请使用Key Derivation Function之类的PKCS#5 / PBKDF2。 PBKDF2的实施是AFAIR包含在Bouncy Castle中。