Симметричное шифрование в Web Crypto API основано на использовании
одного и того же секретного ключа для шифрования и расшифрования данных.
В браузере вся криптографическая функциональность доступна через
интерфейс crypto.subtle, который предоставляет
низкоуровневые операции над бинарными данными.
В отличие от асимметричных алгоритмов, где используются пара ключей (открытый и закрытый), симметричное шифрование опирается на один общий секрет. Это делает его значительно быстрее, но накладывает требования на безопасное хранение ключа.
Ключевые характеристики:
В Web Crypto API наиболее часто используется алгоритм AES-GCM (Advanced Encryption Standard в режиме Galois/Counter Mode), который обеспечивает одновременно конфиденциальность и целостность данных.
Создание ключа выполняется через
crypto.subtle.generateKey. Важно явно указать алгоритм,
длину ключа и назначение.
const key = await crypto.subtle.generateKey(
{
name: "AES-GCM",
length: 256
},
true,
["encrypt", "decrypt"]
);
Параметры:
name: алгоритм шифрованияlength: размер ключа (128, 192 или 256 бит)extractable: возможность экспорта ключаkeyUsages: допустимые операцииКлюч возвращается как объект CryptoKey, который нельзя
напрямую прочитать или вывести в виде строки.
Web Crypto API работает только с бинарными данными
(ArrayBuffer или TypedArray). Строки
необходимо преобразовывать.
Стандартный подход:
const encoder = new TextEncoder();
const data = encoder.encode("секретное сообщение");
Для обратного преобразования используется
TextDecoder.
const decoder = new TextDecoder();
const text = decoder.decode(buffer);
Основная операция выполняется через
crypto.subtle.encrypt.
const iv = crypto.getRandomValues(new Uint8Array(12));
const encrypted = await crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: iv
},
key,
data
);
IV должен быть:
Повторное использование IV с тем же ключом критически нарушает безопасность.
Для восстановления исходного сообщения используется
crypto.subtle.decrypt.
const decrypted = await crypto.subtle.decrypt(
{
name: "AES-GCM",
iv: iv
},
key,
encrypted
);
const decoded = new TextDecoder().decode(decrypted);
Важно: тот же IV, который использовался при шифровании, обязателен для корректного дешифрования.
Результаты шифрования — это ArrayBuffer. Для хранения
или передачи часто требуется преобразование.
function arrayBufferToBase64(buffer) {
const bytes = new Uint8Array(buffer);
let binary = "";
bytes.forEach(b => binary += String.fromCharCode(b));
return btoa(binary);
}
function base64ToArrayBuffer(base64) {
const binary = atob(base64);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) {
bytes[i] = binary.charCodeAt(i);
}
return bytes.buffer;
}
Web Crypto API позволяет сохранять и восстанавливать ключи в стандартизированном формате.
const exported = await crypto.subtle.exportKey("raw", key);
const importedKey = await crypto.subtle.importKey(
"raw",
exported,
"AES-GCM",
true,
["encrypt", "decrypt"]
);
Формат "raw" используется для симметричных ключей
AES.
Одна из наиболее критичных ошибок. Если один и тот же IV используется с одним ключом для разных сообщений, криптосистема теряет стойкость.
AES-GCM оптимально работает с 12 байтами. Использование других значений может привести к снижению безопасности или несовместимости.
Для расшифрования необходимо хранить:
Часто IV добавляют в начало массива:
const combined = new Uint8Array(iv.length + encrypted.byteLength);
combined.set(iv);
combined.set(new Uint8Array(encrypted), iv.length);
Практическая схема хранения часто включает упаковку:
При расшифровании:
const iv = data.slice(0, 12);
const encrypted = data.slice(12);
CryptoKey защищён от прямого чтения. Однако безопасность
зависит от:
extractable: falseДаже сильное шифрование теряет смысл при компрометации JavaScript-контекста страницы.
AES-GCM реализуется на уровне браузера с использованием аппаратного ускорения, если оно доступно. Это делает его пригодным для:
const encoder = new TextEncoder();
const decoder = new TextDecoder();
const key = await crypto.subtle.generateKey(
{ name: "AES-GCM", length: 256 },
true,
["encrypt", "decrypt"]
);
const iv = crypto.getRandomValues(new Uint8Array(12));
const data = encoder.encode("пример текста");
const encrypted = await crypto.subtle.encrypt(
{ name: "AES-GCM", iv },
key,
data
);
const decrypted = await crypto.subtle.decrypt(
{ name: "AES-GCM", iv },
key,
encrypted
);
const result = decoder.decode(decrypted);
Симметричное шифрование редко применяется изолированно. Чаще используется в связке с:
Основная роль AES-GCM в браузере — обеспечение конфиденциальности данных на уровне клиента и временное хранение информации в зашифрованном виде.