1

この質問を投稿する前に、たくさん検索しました。以前のコードは、Android 4.2/2.1 以外のデバイスで動作していました。次に、以下のコード行をグーグルで紹介しました。これで部分的には解決しました。つまり、現在 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 デバイスとは暗号化の結果が異なります。

4

1 に答える 1

3

疑似乱数ジェネレーターを誤用しており、キー派生関数としてのシードです。これは本当に悪いスタイルです。疑似乱数ジェネレーター「SHA1PRNG」は、AES のような標準ではないため、どのような実装が得られるかはわかりません。SHA1PRNG 標準はありますか?も参照してください。

異なる結果が得られても不思議ではありません。特定のシードに基づいて決定論的な結果を取得することは、疑似乱数関数から期待できるプロパティではありません。

パスワードから暗号化キーを導出する場合は、PKCS #5 / PBKDF2 などのキー導出関数を使用してください。PBKDF2 の実装は、Bouncy Castle に含まれる AFAIR です。

于 2013-05-03T15:25:46.070 に答える