2016-04-24 2 views
0

Я пытаюсь заставить Keystore помочь мне сгенерировать ключ для шифрования AES и использовать его для шифрования обычного текста, который я вставляю. Итак, вот мои коды. Я вызываю метод createKey() только один раз в методе onCreate() другого действия, а затем многократно вызываю метод printCipherText() одним и тем же ключом и тем же открытым текстом. Странная вещь: каждый раз, когда я вызываю метод printCipherText(), я получаю другой результат. Я использую один и тот же ключевой псевдоним и тот же самый открытый текст, но почему каждый раз я получаю разный шифрованный текст?Android AES (с Keystore) производит различные шифрованные тексты с одним и тем же простым текстом

public class KeyCreatorClass { 

    KeyStore keyStore; 
    KeyGenerator keyGenerator; 
    Cipher cipher; 

    public void createKey(String keyAlias) { //I call this method only once in the onCreate() method of another activity, with keyAlias "A" 
     try { 
      keyStore = KeyStore.getInstance("AndroidKeyStore"); 
      keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore"); 
      cipher = Cipher.getInstance("AES/CBC/PKCS7Padding"); 
      keyStore.load(null); 
      keyGenerator.init(
        new KeyGenParameterSpec.Builder(keyAlias, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) 
         .setBlockModes(KeyProperties.BLOCK_MODE_CBC) 
         .setUserAuthenticationRequired(false) 
         .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7) 
         .setRandomizedEncryptionRequired(false) 
         .build()); 
      keyGenerator.generateKey(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    public String printCipherText(String keyAlias, String plainText){ //I call this method many times with the same keyAlias "A" and same plaintext in the same activity 
     try { 
      keyStore.load(null); 
      SecretKey key = (SecretKey) keyStore.getKey(keyAlias, null); 
      cipher.init(Cipher.ENCRYPT_MODE, key); 
      return byteToHex(cipher.doFinal(plainText.getBytes())); 
     }catch(Exception e){ 
      e.printStackTrace(); 
     } 
     return "BUG"; 
    } 

    private String byteToHex(byte[] byteArray){ 
     StringBuilder buf = new StringBuilder(); 
     for (byte b : byteArray) 
      buf.append(String.format("%02X", b)); 
     String hexStr = buf.toString(); 
     return hexStr; 
    } 
} 
+0

Во всех этих случаях вы получаете исходный текст обратно при расшифровке? – MikeC

+0

Спасибо, я думаю, что @Artjom B. просто решил мою проблему –

ответ

3

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

Поскольку IV генерируется случайным образом, вам нужен тот же IV, который использовался во время шифрования также во время дешифрования. IV не должен быть секретным, но он должен быть непредсказуемым (каким он есть). Один из распространенных способов - записать его перед зашифрованным текстом и прочитать его во время дешифрования. Он всегда имеет ту же длину, что и размер блока. Этот размер составляет 16 байт для AES.

+0

Большое вам спасибо! Кстати, можете ли вы привести пример «общего пути» использования IV? –

+1

В вашем случае простой 'return byteToHex (cipher.getIV()) + byteToHex (cipher.doFinal (plainText.getBytes()));' должен работать другим способом с использованием подстроки во время дешифрования. Если вы хотите, чтобы ваше шифрование работало для больших данных, вы должны использовать потоки. –

Смежные вопросы