安卓使用基于密码的AES加密,每个消息使用一个密钥和随机IV

3
我目前正在Android上实现使用AES 256对称加密/解密,受这篇文章的启发:Java 256bit AES Encryption。我的实现目的是要加密数据库中的数据。
为了生成密钥,我使用以下构造函数,它接受一个char[]密码:
public Cryptography(char[] password) throws NoSuchAlgorithmException,
        InvalidKeySpecException, NoSuchPaddingException {

    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWITHSHA256AND256BITAES-CBC-BC");
    KeySpec spec = new PBEKeySpec(password, salt, 1024, 256);
    secretKey = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
    cipher = Cipher.getInstance(AES/CBC/PKCS5Padding);
}

当我在Android中启动我的Activity时,我初始化了一个新的Cryptography类实例,从而获得一个生成的密钥。盐是一个固定的随机字节数组,长度为16个字节。这意味着我总是得到相同的密钥。稍后会解释原因。
现在,在一个Activity中获取了一个对象后,我可以使用以下加密和解密方法,始终使用相同的密钥:
public byte[] encrypt(String cleartext) throws InvalidKeyException,
        IllegalBlockSizeException, BadPaddingException,
        UnsupportedEncodingException, InvalidParameterSpecException {

    cipher.init(Cipher.ENCRYPT_MODE, secretKey);

    byte[] encText = cipher.doFinal(cleartext.getBytes(CHARSET_NAME));
    byte[] iv = cipher.getParameters()
            .getParameterSpec(IvParameterSpec.class).getIV();

    byte[] enc = new byte[IV_SIZE + encText.length];

    for (int i = 0; i < enc.length; i++) {
        if (i < IV_SIZE)
            enc[i] = iv[i];
        else if (i < enc.length)
            enc[i] = encText[i - IV_SIZE];
    }

    return enc;
}

public String decrypt(byte[] encryptedText) throws InvalidKeyException,
        InvalidAlgorithmParameterException, UnsupportedEncodingException,
        IllegalBlockSizeException, BadPaddingException {

    byte[] iv = new byte[IV_SIZE];
    byte[] dec = new byte[encryptedText.length - IV_SIZE];

    for (int i = 0; i < encryptedText.length; i++) {
        if (i < IV_SIZE)
            iv[i] = encryptedText[i];
        else if (i < encryptedText.length)
            dec[i - IV_SIZE] = encryptedText[i];
    }

    cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));

    return new String(cipher.doFinal(dec), CHARSET_NAME);
}

正如您所看到的,每次加密消息时,我都会保存一个新的IV和密文。
总之:我在数据库表中的每个字段中使用一个加密密钥、一个随机盐和一个新的IV。
起初,我想每次加密数据库表中的一个字段时都生成一个新的密钥、一个新的盐和一个新的IV,并将所需的盐和IV与密文一起保存,或者至少对于一个表行。但我之所以像上面提到的那样做,是因为在Android设备上生成密钥需要太长时间了。我在模拟器上测试了它,但生成密钥大约需要两秒钟。这就是为什么我只在Activity启动时生成一个密钥。
所以最后我的问题是: 采用我的方法,仅使用一个密钥,但每条消息都使用新的随机IV,是否足够安全?目前,我没有看到其他方法可以在保持性能平衡的同时使其尽可能安全。
我希望我写的足够清楚,有人可以给我一些建议。
此致敬礼
xoidberg
1个回答

1

我相信这个问题对你(xoidberg)并不相关,但它可能对其他人有用。

据我了解 - 你使用盐来从密码创建一个(安全随机的)密钥。如果每个用户有一个随机(不同的)盐 - 就可以了。否则可能会有问题。

我相信这就是你所做的,所以它在我看来是可以的。

我想提一下,通常在保存某些值的哈希函数时(通常是密码),你会想要使用盐。像MD5或SHAs之类的哈希函数没有密钥,你必须添加随机性来达到此目的。这就是为什么你需要盐,并且在这种情况下通常需要为每个值使用随机盐(如果只保存具有相同盐的密码哈希,则可以检测出最常见的哈希并学习到具有最常见哈希的用户的密码是123456)。在你的情况下 - 每个用户都需要一个唯一的盐。

关于IV - 你确实需要每次都是随机的(所以没问题)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接