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

时间:2012-02-21 23:00:44

标签: android security aes password-protection encryption-symmetric

我目前正在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类的新实例,因此获得了生成的密钥。 salt是一个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。

总之:我在数据库表中使用ONE加密密钥,ONE random salt和new IV for EVERY字段。

首先,我想在每次加密数据库表中的一个字段时生成一个带有新盐和新IV的新密钥,并将所需的盐和IV与密文一起保存,或者至少保存一个表行。但我之所以这样做的原因是,因为在Android设备上生成密钥需要花费很多时间。我在模拟器上测试过,但生成密钥花了大约两秒钟。这就是我在Activity启动时只生成一个键的原因。

最后我的问题: 通过我的方法,只使用一个密钥就足够安全,但每条消息都有新的随机IV?目前,我没有看到另一种方法,即通过保持与性能的平衡来使其尽可能安全。

我希望我写的很清楚,有人可以给我一些建议。

亲切的问候

xoidberg

1 个答案:

答案 0 :(得分:1)

我认为这个问题与你无关(xoidberg),但它可能与其他人有关。

根据我的理解 - 您使用salt从密码创建(安全随机)密钥。如果每个用户都有一个随机(不同)的盐 - 没关系。否则可能会有问题。

我相信这就是你所做的,所以看来(对我来说)没问题。

我只想提一下,通常你想在保存某些值的哈希函数(通常是密码)时使用salt。像MD5或SHA这样的散列函数没有密钥,您必须为此添加随机性。这就是为什么你需要盐,这就是为什么在这种情况下你通常需要为每个值提供随机盐(如果你只是用相同的盐保存密码哈希,可以检测最常见的哈希并了解用户的密码)最常见的哈希是123456)。在您的情况下 - 每个用户都需要一个独特的盐。

关于IV - 你每次都需要一个随机的(所以没关系)。