Android中AES实现可能出现的故障

时间:2015-12-29 08:18:37

标签: android cryptography aes cbc-mode aes-gcm

我尝试在Android中实施AES加密,它使用密码短语生成SecretKey。我传递了相同的byte[] 作为密码的初始化向量,以及在使用PBKDF2生成SecretKey时作为salt。

每次需要加密/解密时,用户都会提供密码。

截至目前,我只需要加密数据库中的一个值(如果这有任何区别)。

问题:

  1. 我想知道使用与IV和盐相同的byte[]是否会削弱加密效果?
  2. 是否有理由从CBC切换到GCM,然后是GCM提供的数据完整性功能?
  3. 我读过有关CBC易受BEAST攻击的消息,正在使用新的随机IV消息,如下所示,减轻了BEAST攻击?
  4. 当前源代码:

    public class AesEncryption {
        private static final int KEY_SIZE = 16;
        private static final int OUTPUT_KEY_LENGTH = 256;
        private static final int ITERATIONS = 1000;
    
        private String mPassphraseOrPin;
    
        public AesEncryption(String passphraseOrPin) {
            mPassphraseOrPin = passphraseOrPin;
        }
    
        public void encrypt(String id, String textToEncrypt) throws Exception {
            byte[] iv = getIv();
            SecretKey secretKey = generateKey(iv);
    
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));
    
            byte[] cipherText = cipher.doFinal(textToEncrypt.getBytes("utf-8"));
            byte[] ivCipherText = arrayConcat(iv, cipherText);
            String encryptedText = Base64.encodeToString(ivCipherText, Base64.NO_WRAP);
    
            storeEncryptedTextInDb(id, encryptedText);
        }
    
        public String decrypt(String id) throws Exception {
            String encryptedText = getEncryptedTextFromDb(id);
    
            byte[] ivCipherText = Base64.decode(encryptedText, Base64.NO_WRAP);
            byte[] iv = Arrays.copyOfRange(ivCipherText, 0, KEY_SIZE);
            byte[] cipherText = Arrays.copyOfRange(ivCipherText, KEY_SIZE, ivCipherText.length);
    
            SecretKey secretKey = generateKey(iv);
    
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
            String decrypted = new String(cipher.doFinal(cipherText), "utf-8");
    
            return decrypted;
        }
    
        public SecretKey generateKey(byte[] salt) throws Exception {
            SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
            KeySpec keySpec = new PBEKeySpec(mPassphraseOrPin.toCharArray(), salt, ITERATIONS, OUTPUT_KEY_LENGTH);
            SecretKey tmp = secretKeyFactory.generateSecret(keySpec);
            return new SecretKeySpec(tmp.getEncoded(), "AES");
        }
    
        private byte[] getIv() {
            byte[] salt = new byte[KEY_SIZE];
            new SecureRandom().nextBytes(salt);
            return salt;
        }
    
        private byte[] arrayConcat(byte[] one, byte[] two) {
            byte[] combined = new byte[one.length + two.length];
            for (int i = 0; i < combined.length; ++i) {
                combined[i] = i < one.length ? one[i] : two[i - one.length];
            }
            return combined;
        }
    }
    

1 个答案:

答案 0 :(得分:2)

  

我想知道是否使用与IV和盐相同的字节[]会削弱加密效果?

是的。

对于盐:如果你不随机化盐,那么攻击者可以预先计算一个带有密码和密码哈希的表。这被称为彩虹表。此外,如果任何人拥有相同的密码,它将导致相同的密钥。强烈建议每个用户生成一个salt,并且 - 如果可行的话 - 每次重新加密该值时都会生成一个新的盐。

对于IV:如果重新加密包含相同明文的起始块,则密文将重复块。攻击者可以使用它从中提取信息。简单的例子:加密&#34;是&#34;或&#34;否&#34;两次显然可以与第一次加密区别开来&#34;是&#34;然后&#34;不&#34;。通常,您应该生成随机IV并将其与密文一起存储。如果盐(以及密钥)是随机的,建议甚至。它当然取决于您的威胁模型,如果这会对现实世界产生影响。

  

是否有理由从CBC切换到GCM,然后是GCM提供的数据完整性功能?

GCM提供明文的完整性和真实性。从功能上讲,它只是带有身份验证标记的CTR模式下的AES。如果您需要明文的完整性和真实性(可能还有其他经过身份验证的数据或AAD),这取决于您的威胁模型。它不会添加任何功能。

如果您只是在保密数据之后,那么您可能不需要GCM。如果您想保护它免受攻击者所做的更改,那么您确实需要它。在这种情况下,您还需要防止重放攻击。

  

我读过关于CBC容易发生BEAST攻击,正在使用新的随机IV消息,如下所示,减轻了BEAST攻击?

BEAST攻击是针对SSL / TLS的基于浏览器的攻击。根据定义,它不适用于数据库加密,尤其是对于静态数据。可能会引发大量攻击,但BEAST依赖于TLS连接中的动态数据。

注意:

  • 基于长度的攻击经常被遗忘,因为密码/密码模式不能防止它们。它们可能适用于此。与CBC相比,GCM泄漏了更多关于明文长度的信息。

  • 攻击者查看某个值是否重新加密也可能会很有趣。

  • 1000不再被视为安全的迭代计数/工作因素。您可能希望升级它(并创建升级策略)。