2015-12-29 9 views
0

Я пытаюсь внедрить AES-шифрование на Android, в котором используется фраза для генерации SecretKey. Я передаю то же самое byte[] как вектор инициализации для шифров и как соль при создании SecretKey с PBKDF2.Возможные ошибки в реализации AES в Android

Ключевая фраза предоставляется пользователем каждый раз, когда требуется шифрование/дешифрование.

На данный момент мне нужно только зашифровать одно значение в моей базе данных (если это имеет значение).

Вопросы:

  1. Я интересно, если с помощью того же byte[] как IV и соль ослабляет шифрование?
  2. Есть ли причина переключиться с CBC на GCM, тогда функция GCM обеспечивает целостность данных?
  3. Я читал о том, что CBC подвержен атаке BEAST, использует новый случайный IV для каждого сообщения, как показано ниже, смягчает атаку BEAST?

Текущий исходный код:

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; 
    } 
} 
+0

Я предполагаю местную базу данных Android? –

+0

@MaartenBodewes да. Я собираюсь сохранить зашифрованный текст в SharedPreferences. –

+0

ОК, в этом случае нет никаких шансов на атаку в отношении данных, находящихся в пути (например, атаки CBC на оскорбление). К сожалению, я не могу выполнить полный обзор безопасности - ответ не тот. В целом, он окупается, чтобы посмотреть варианты защиты, предлагаемые самой платформой. –

ответ

2

Я интересно, если используется один и тот же байт [], как IV и соль ослабляет шифрование?

Да, так оно и есть.

Для соли: если вы не рандомизируете соль, злоумышленник может предварительно вычислить таблицу с паролями и хэшами паролей. Это называется радужным столом. Кроме того, если у кого-то есть тот же пароль, это приведет к тому же ключу. Настоятельно рекомендуется создавать соль для каждого пользователя и - если это возможно - новую соль при каждом повторном зашифровании значения.

Для IV: если вы повторно зашифруете стартовые блоки, содержащие один и тот же текст, тогда зашифрованный текст будет повторять блоки. Злоумышленник может использовать это для извлечения информации из этого. Простой пример: шифрование «Да» или «Нет» дважды будет четко различимым от первого шифрования «Да», а затем «Нет». Как правило, вы должны генерировать случайный IV и хранить его с помощью зашифрованного текста. Это рекомендуется даже, если соль (и, следовательно, ключ) рандомизирована. Конечно, это зависит от вашей модели угрозы, если это имеет значение в реальном мире.

Есть ли причина переключиться с CBC на GCM, кроме того, функция целостности данных GCM предоставляет?

GCM обеспечивает целостность и подлинность открытого текста. Функционально это просто AES в режиме CTR с тегом проверки подлинности. Это зависит от вашей модели угроз, если вам нужна целостность и подлинность открытого текста (и, возможно, дополнительные аутентифицированные данные или AAD). В противном случае он не добавит никакой функциональности.

Если вы только что сохранили свои конфиденциальные данные, вам может не понадобиться GCM. Если вы хотите защитить его от изменений, сделанных злоумышленником, тогда вам это нужно. В этом случае, однако, вам также необходимо защитить от повторных атак.

Я читал о том, что CBC подвержен атаке BEAST, использует новый случайный IV для сообщения, как показано ниже, смягчает атаку BEAST?

Атака BEAST - это атака с использованием браузера на основе SSL/TLS. По определению он не применяется к шифрованию базы данных, особенно в отношении данных в состоянии покоя. Целый ряд атак может быть поднят, но BEAST зависит от динамических данных в TLS-соединении.


Примечание: атаки, основанные

  • длины часто забывают, как шифры/шифр режимы не защищает от них. Они могут быть применимы ни к чему. GCM утечки немного больше информации о длине открытого текста по сравнению с CBC.

  • Для злоумышленника может быть интересно узнать, не зашифровано ли значение заново.

  • 1000 не считается надежным счетчиком итераций. Вы можете обновить его (и создать стратегию обновления).

+0

Большое спасибо @Maarten за очень информативный ответ. Поэтому я должен использовать случайную соль за зашифрованное значение и хранить ее вдоль зашифрованного текста? –

+2

Да. Я бы порекомендовал вам также кодировать что-то из индикатора версии, если вы хотите обновить его позже (например, используйте более высокий коэффициент работы). Либо выведите IV (как и ключ), либо сохраните его вместе, если у вас есть место для него. –

+0

Добавление версии - это хорошая идея. Шифрование с помощью следующего кода на старом устройстве Samsung S3 и коэффициент работы 1000 составили около 1200 миллисов. Есть ли значительная выгода для увеличения коэффициента работы? Если я его увеличу, мне определенно придется придумать некоторую стратегию, зависящую от характеристик устройства, и это добавит «дополнительную логику» к уже сложному алгоритму. Существует ли верхний предел для коэффициента работы, после чего коэффициент усиления считается минимальным? –