Асимметричное шифрование основано на использовании пары ключей: публичного и приватного. Публичный ключ применяется для шифрования данных, приватный — для их расшифровки. Такая модель решает ключевую проблему симметричного шифрования: безопасную передачу секретного ключа.
В основе лежит математическая связь между двумя ключами:
Данные, зашифрованные публичным ключом, могут быть расшифрованы только соответствующим приватным ключом. Обратная операция невозможна в практическом смысле.
На практике асимметричное шифрование применяется не для больших объёмов данных, а для:
Web Crypto API предоставляет интерфейс crypto.subtle,
через который реализуются криптографические операции.
Основные алгоритмы асимметричного шифрования:
Создание асимметричной пары ключей выполняется через
generateKey.
const keyPair = await crypto.subtle.generateKey(
{
name: "RSA-OAEP",
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: "SHA-256"
},
true,
["encrypt", "decrypt"]
);
name — алгоритм (RSA-OAEP)modulusLength — длина ключа в битах (2048 или
4096)publicExponent — стандартное значение 65537hash — хеш-функция для OAEP paddingОбъект содержит:
publicKeyprivateKeyПеред шифрованием данные должны быть преобразованы в бинарный формат.
const encoder = new TextEncoder();
const data = encoder.encode("секретное сообщение");
const encrypted = await crypto.subtle.encrypt(
{
name: "RSA-OAEP"
},
keyPair.publicKey,
data
);
ArrayBufferconst decrypted = await crypto.subtle.decrypt(
{
name: "RSA-OAEP"
},
keyPair.privateKey,
encrypted
);
const decoder = new TextDecoder();
const result = decoder.decode(decrypted);
Web Crypto API использует стандартизированные форматы экспорта:
const exportedPublic = await crypto.subtle.exportKey(
"spki",
keyPair.publicKey
);
const exportedPrivate = await crypto.subtle.exportKey(
"pkcs8",
keyPair.privateKey
);
Импорт позволяет восстановить ключи из сохранённого формата.
const importedPublic = await crypto.subtle.importKey(
"spki",
exportedPublic,
{
name: "RSA-OAEP",
hash: "SHA-256"
},
true,
["encrypt"]
);
const importedPrivate = await crypto.subtle.importKey(
"pkcs8",
exportedPrivate,
{
name: "RSA-OAEP",
hash: "SHA-256"
},
true,
["decrypt"]
);
Асимметричное шифрование на основе RSA имеет технические ограничения:
По этой причине применяется гибридная схема:
Типовая схема взаимодействия:
Подписи обеспечивают:
const signKeys = await crypto.subtle.generateKey(
{
name: "RSA-PSS",
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: "SHA-256"
},
true,
["sign", "verify"]
);
const data = new TextEncoder().encode("сообщение");
const signature = await crypto.subtle.sign(
{
name: "RSA-PSS",
saltLength: 32
},
signKeys.privateKey,
data
);
const valid = await crypto.subtle.verify(
{
name: "RSA-PSS",
saltLength: 32
},
signKeys.publicKey,
signature,
data
);
ECC-криптография обеспечивает:
Используется для безопасного согласования общего секрета.
const ecdhKeys = await crypto.subtle.generateKey(
{
name: "ECDH",
namedCurve: "P-256"
},
true,
["deriveKey"]
);
const derivedKey = await crypto.subtle.deriveKey(
{
name: "ECDH",
public: otherPublicKey
},
ecdhKeys.privateKey,
{
name: "AES-GCM",
length: 256
},
false,
["encrypt", "decrypt"]
);
const ecdsaKeys = await crypto.subtle.generateKey(
{
name: "ECDSA",
namedCurve: "P-256"
},
true,
["sign", "verify"]
);
Ключи Web Crypto API могут быть:
extractable: false)extractable: true)Неэкспортируемые ключи повышают безопасность, так как:
JSON Web Key позволяет хранить ключи в JSON-структуре.
const jwkKey = await crypto.subtle.exportKey(
"jwk",
keyPair.publicKey
);
Пример структуры:
{
"kty": "RSA",
"e": "AQAB",
"n": "...",
"alg": "RSA-OAEP-256",
"ext": true
}