В настоящее время я внедряю симметричное шифрование / расшифровку с использованием AES 256 на Android, вдохновленное этим сообщением: 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. Я инициализирую новый экземпляр своего класса криптографии и, следовательно, получаю сгенерированный ключ.Соль - это фиксированный случайный байт [] из 16 байтов.Это значит, что я всегда получаю один и тот же ключ.Причина этого позже.
Теперь, после того как я получил объект в одном действии, я могу использовать следующие методы шифрования и дешифрования с всегда одним и тем же ключом:
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