У цій відповіді я вирішу підходити до основної теми "Простий приклад шифрування / розшифрування Java AES", а не до конкретного питання налагодження, тому що я думаю, що це принесе користь більшості читачів.
Це простий підсумок моєї публікації в блозі про шифрування AES на Java, тому я рекомендую прочитати його, перш ніж щось впроваджувати. Однак я все ж надам простий приклад для використання та дам деякі вказівки, на що слідкувати.
У цьому прикладі я виберу використовувати автентифіковане шифрування в режимі Galois / Counter або GCM . Причина полягає в тому, що в більшості випадків ви хочете чесність та справжність у поєднанні з конфіденційністю (детальніше читайте у блозі ).
Підручник з шифрування / розшифрування AES-GCM
Ось етапи, необхідні для шифрування / дешифрування за допомогою AES-GCM за допомогою архітектури криптографії Java (JCA) . Не змішуйте з іншими прикладами , оскільки тонкі відмінності можуть зробити ваш код абсолютно незахищеним.
1. Створити ключ
Оскільки це залежить від вашого випадку використання, я вважаю найпростіший випадок: випадковий секретний ключ.
SecureRandom secureRandom = new SecureRandom();
byte[] key = new byte[16];
secureRandom.nextBytes(key);
SecretKey secretKey = SecretKeySpec(key, "AES");
Важливо:
2. Створіть вектор ініціалізації
Вектор ініціалізації (IV) використовується для того , що той же самий секретний ключ буде створювати різні тексти шифрів .
byte[] iv = new byte[12]; //NEVER REUSE THIS IV WITH SAME KEY
secureRandom.nextBytes(iv);
Важливо:
3. Шифруйте за допомогою IV та Key
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv); //128 bit auth tag length
cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);
byte[] cipherText = cipher.doFinal(plainText);
Важливо:
- використовувати 16-байтний / 128-бітний тег аутентифікації (використовується для перевірки цілісності / справжності)
- тег аутентифікації буде автоматично доданий до тексту шифру (у реалізації JCA)
- Оскільки GCM веде себе як потіковий шифр, не потрібні додаткові прокладки
- використовувати
CipherInputStream
при шифруванні великих фрагментів даних
- хочете перевірити додаткові (несекретні) дані, якщо вони були змінені? Тут ви можете використовувати пов’язані дані з
cipher.updateAAD(associatedData);
Більше.
3. Серіалізувати до єдиного повідомлення
Просто додайте IV та шифротекст. Як було сказано вище, IV не потрібно бути таємним.
ByteBuffer byteBuffer = ByteBuffer.allocate(iv.length + cipherText.length);
byteBuffer.put(iv);
byteBuffer.put(cipherText);
byte[] cipherMessage = byteBuffer.array();
Необов’язково кодуйте Base64, якщо вам потрібно представлення рядків. Або використовуйте вбудовану реалізацію Android або Java 8 (не використовуйте Apache Commons Codec - це жахлива реалізація). Кодування використовується для "перетворення" байтових масивів у представлення рядків, щоб зробити його ASCII безпечним, наприклад:
String base64CipherMessage = Base64.getEncoder().encodeToString(cipherMessage);
4. Підготуйте розшифровку: десеріалізуйте
Якщо ви зашифрували повідомлення, спершу розшифруйте його для байтового масиву:
byte[] cipherMessage = Base64.getDecoder().decode(base64CipherMessage)
Важливо:
5. Розшифруйте
Ініціалізуйте шифр і встановіть ті ж параметри, що і для шифрування:
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
//use first 12 bytes for iv
AlgorithmParameterSpec gcmIv = new GCMParameterSpec(128, cipherMessage, 0, 12);
cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmIv);
//use everything from 12 bytes on as ciphertext
byte[] plainText = cipher.doFinal(cipherMessage, 12, cipherMessage.length - 12);
Важливо:
- не забудьте додати відповідні дані з ,
cipher.updateAAD(associatedData);
якщо ви додали його під час шифрування.
Фрагмент робочого коду можна знайти в цій суті.
Зауважте, що в останніх реалізаціях Android (SDK 21+) та Java (7+) має бути AES-GCM. Старіші версії можуть бракувати його. Я все одно вибираю цей режим, оскільки його легше реалізувати, крім того, що він є більш ефективним порівняно з аналогічним режимом Encrypt-then-Mac (наприклад, AES-CBC + HMAC ). Дивіться цю статтю про те, як реалізувати AES-CBC з HMAC .