Криптография в Java: шифрование и хеширование – полное руководство
Криптография — фундаментальная основа безопасности современных приложений. В Java встроена мощная и гибкая инфраструктура для работы с шифрованием и хешированием — Java Cryptography Architecture (JCA) и Java Cryptography Extension (JCE). Эти библиотеки позволяют реализовать как симметричное (AES), так и асимметричное (RSA) шифрование, а также криптографическое хеширование (SHA-256). В этой статье мы разберем ключевые концепции и напишем рабочие примеры на чистом Java (без сторонних зависимостей).
Основные понятия и архитектура JCA/JCE
JCA предоставляет каркас для работы с криптографическими операциями. Ключевая идея — провайдеры (providers), которые реализуют конкретные алгоритмы. По умолчанию JDK включает провайдер SUN (для хешей) и SunJCE (для шифрования). Основные классы находятся в пакете javax.crypto и java.security.
- Cipher — основной класс для шифрования и дешифрования.
- KeyGenerator — генерация симметричных ключей.
- KeyPairGenerator — генерация пар ключей для асимметричного шифрования.
- MessageDigest — вычисление хеш-сумм.
- SecretKeySpec — представление симметричного ключа из массива байт.
Симметричное шифрование: AES
AES (Advanced Encryption Standard) — самый популярный симметричный алгоритм. Использует один и тот же ключ для шифрования и дешифрования. Рекомендуемый режим — GCM (аутентифицированное шифрование) или CBC с PKCS5Padding. Ниже пример шифрования строки с использованием AES-256/GCM.
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import java.security.SecureRandom;
import java.util.Base64;
public class AESGCMExample {
private static final int AES_KEY_SIZE = 256;
private static final int GCM_IV_LENGTH = 12;
private static final int GCM_TAG_LENGTH = 128;
public static SecretKey generateKey() throws Exception {
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(AES_KEY_SIZE, SecureRandom.getInstanceStrong());
return keyGen.generateKey();
}
public static String encrypt(String plaintext, SecretKey key) throws Exception {
byte[] iv = new byte[GCM_IV_LENGTH];
SecureRandom.getInstanceStrong().nextBytes(iv);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH, iv);
cipher.init(Cipher.ENCRYPT_MODE, key, spec);
byte[] cipherText = cipher.doFinal(plaintext.getBytes());
byte[] encrypted = new byte[iv.length + cipherText.length];
System.arraycopy(iv, 0, encrypted, 0, iv.length);
System.arraycopy(cipherText, 0, encrypted, iv.length, cipherText.length);
return Base64.getEncoder().encodeToString(encrypted);
}
public static String decrypt(String encryptedData, SecretKey key) throws Exception {
byte[] decoded = Base64.getDecoder().decode(encryptedData);
byte[] iv = new byte[GCM_IV_LENGTH];
System.arraycopy(decoded, 0, iv, 0, iv.length);
byte[] cipherText = new byte[decoded.length - iv.length];
System.arraycopy(decoded, iv.length, cipherText, 0, cipherText.length);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH, iv);
cipher.init(Cipher.DECRYPT_MODE, key, spec);
return new String(cipher.doFinal(cipherText));
}
public static void main(String[] args) throws Exception {
SecretKey key = generateKey();
String original = "Привет, мир!";
String encrypted = encrypt(original, key);
String decrypted = decrypt(encrypted, key);
System.out.println("Оригинал: " + original);
System.out.println("Зашифровано: " + encrypted);
System.out.println("Расшифровано: " + decrypted);
}
}
В примере мы генерируем 256-битный ключ, добавляем случайный IV (вектор инициализации) и используем режим GCM, который обеспечивает проверку целостности. Результат кодируется в Base64 для удобства передачи.
Асимметричное шифрование: RSA
RSA использует пару ключей: открытый (public) для шифрования и закрытый (private) для дешифрования. Обычно RSA применяют для шифрования небольших данных (например, ключей сессии). Размер ключа — 2048 или