Crypto-js для JavaScript (Node.js): полное руководство с примерами
В современной веб-разработке безопасность данных является критически важным аспектом. Будь то хранение паролей пользователей, передача конфиденциальной информации по сети или защита файлов от несанкционированного доступа — криптография лежит в основе этих процессов. Библиотека Crypto-js предоставляет мощный и удобный набор криптографических алгоритмов для экосистемы JavaScript, работая как в браузере, так и в среде Node.js.
Данная библиотека реализует широкий спектр стандартных криптографических функций: симметричное шифрование (AES, DES, TripleDES), хеширование (MD5, SHA-1, SHA-256, SHA-512), вычисление HMAC, а также генерацию случайных чисел и работу с кодировками (Base64, Hex, UTF-8). Crypto-js не зависит от нативных модулей операционной системы, что делает её идеальным выбором для изоморфных приложений (код, работающий и на клиенте, и на сервере).
В этой статье мы подробно разберём установку библиотеки, основные методы с примерами кода, а также рассмотрим реальный практический пример использования Crypto-js для защиты данных в веб-приложении. Материал будет полезен как начинающим разработчикам, так и опытным специалистам, желающим систематизировать свои знания о криптографии в JavaScript.
Установка
Для установки Crypto-js в проекте Node.js выполните следующую команду в терминале:
npm install crypto-js
После установки вы можете импортировать библиотеку в свой код:
// Для Node.js (CommonJS)
const CryptoJS = require("crypto-js");
// Для ES Modules (если используется "type": "module" в package.json)
import CryptoJS from "crypto-js";
Быстрый старт: минимальный рабочий пример
Давайте начнём с простейшего примера — шифрования и дешифрования строки с использованием алгоритма AES:
const CryptoJS = require("crypto-js");
// Исходное сообщение
const message = "Hello, Crypto-js!";
// Секретный ключ (должен быть надёжным в реальном приложении)
const secretKey = "my-secret-key-123";
// Шифрование
const ciphertext = CryptoJS.AES.encrypt(message, secretKey).toString();
console.log("Зашифрованное сообщение:", ciphertext);
// Дешифрование
const bytes = CryptoJS.AES.decrypt(ciphertext, secretKey);
const decryptedMessage = bytes.toString(CryptoJS.enc.Utf8);
console.log("Расшифрованное сообщение:", decryptedMessage);
Этот пример демонстрирует базовый цикл работы с симметричным шифрованием: мы преобразуем исходный текст в зашифрованную строку (Base64), а затем восстанавливаем исходное сообщение с помощью того же ключа.
Основные методы/функции/классы
Рассмотрим ключевые возможности Crypto-js. Для каждого метода приведена сигнатура, краткое описание и рабочий пример.
1. CryptoJS.AES.encrypt() / CryptoJS.AES.decrypt()
Сигнатура: CryptoJS.AES.encrypt(message, key, [options]) и CryptoJS.AES.decrypt(ciphertext, key, [options])
Что делает: Реализует симметричное шифрование и дешифрование по алгоритму AES (Advanced Encryption Standard). Поддерживает режимы ECB, CBC, CFB, OFB, CTR и размер ключа 128/192/256 бит.
const CryptoJS = require("crypto-js");
const message = "Секретные данные";
const key = "supersecretkey123";
// Шифрование с указанием режима и IV (вектор инициализации)
const iv = CryptoJS.lib.WordArray.random(16); // 16 байт для AES-128
const encrypted = CryptoJS.AES.encrypt(message, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
}).toString();
console.log("Зашифровано (CBC):", encrypted);
// Дешифрование
const decrypted = CryptoJS.AES.decrypt(encrypted, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
}).toString(CryptoJS.enc.Utf8);
console.log("Расшифровано:", decrypted);
2. CryptoJS.SHA256()
Сигнатура: CryptoJS.SHA256(message)
Что делает: Вычисляет SHA-256 хеш от переданного сообщения. Возвращает объект WordArray, который можно преобразовать в строку Hex или Base64.
const CryptoJS = require("crypto-js");
const data = "Hello, world!";
const hash = CryptoJS.SHA256(data);
console.log("SHA-256 (Hex):", hash.toString(CryptoJS.enc.Hex));
console.log("SHA-256 (Base64):", hash.toString(CryptoJS.enc.Base64));
3. CryptoJS.HmacSHA256()
Сигнатура: CryptoJS.HmacSHA256(message, key)
Что делает: Вычисляет HMAC (Hash-based Message Authentication Code) с использованием алгоритма SHA-256. Используется для проверки целостности и аутентичности сообщения.
const CryptoJS = require("crypto-js");
const message = "Важное сообщение";
const secret = "мой-секретный-ключ";
const hmac = CryptoJS.HmacSHA256(message, secret);
console.log("HMAC-SHA256:", hmac.toString(CryptoJS.enc.Hex));
4. CryptoJS.MD5()
Сигнатура: CryptoJS.MD5(message)
Что делает: Вычисляет MD5 хеш. Внимание: MD5 считается криптографически нестойким и не рекомендуется для использования в системах безопасности. Подходит только для контроля целостности некритичных данных.
const CryptoJS = require("crypto-js");
const text = "Проверка целостности";
const md5Hash = CryptoJS.MD5(text);
console.log("MD5:", md5Hash.toString());
5. CryptoJS.enc.Base64.stringify() / CryptoJS.enc.Base64.parse()
Сигнатура: CryptoJS.enc.Base64.stringify(wordArray) и CryptoJS.enc.Base64.parse(base64String)
Что делает: Преобразует WordArray в строку Base64 и обратно. Полезно для кодирования бинарных данных в текстовый формат.
const CryptoJS = require("crypto-js");
// Кодирование
const wordArray = CryptoJS.enc.Utf8.parse("Hello, Base64!");
const base64String = CryptoJS.enc.Base64.stringify(wordArray);
console.log("Base64:", base64String);
// Декодирование
const decodedWordArray = CryptoJS.enc.Base64.parse(base64String);
const decodedString = decodedWordArray.toString(CryptoJS.enc.Utf8);
console.log("Декодировано:", decodedString);
6. CryptoJS.lib.WordArray.random()
Сигнатура: CryptoJS.lib.WordArray.random(numberOfBytes)
Что делает: Генерирует криптографически стойкий набор случайных байт. Используется для создания векторов инициализации (IV), соли или ключей.
const CryptoJS = require("crypto-js");
// Генерация 32 случайных байт (256 бит)
const randomBytes = CryptoJS.lib.WordArray.random(32);
console.log("Случайные байты (Hex):", randomBytes.toString(CryptoJS.enc.Hex));
console.log("Случайные байты (Base64):", randomBytes.toString(CryptoJS.enc.Base64));
7. CryptoJS.PBKDF2()
Сигнатура: CryptoJS.PBKDF2(password, salt, [options])
Что делает: Реализует функцию формирования ключа на основе пароля (Password-Based Key Derivation Function 2). Позволяет получить криптостойкий ключ из пароля, используя соль и множество итераций.
const CryptoJS = require("crypto-js");
const password = "user_password_123";
const salt = CryptoJS.lib.WordArray.random(16);
const key = CryptoJS.PBKDF2(password, salt, {
keySize: 256 / 32, // 256 бит
iterations: 10000,
hasher: CryptoJS.algo.SHA256
});
console.log("Сгенерированный ключ (Hex):", key.toString(CryptoJS.enc.Hex));
console.log("Соль (Hex):", salt.toString(CryptoJS.enc.Hex));
8. CryptoJS.TripleDES.encrypt() / CryptoJS.TripleDES.decrypt()
Сигнатура: CryptoJS.TripleDES.encrypt(message, key, [options]) и CryptoJS.TripleDES.decrypt(ciphertext, key, [options])
Что делает: Реализует шифрование/дешифрование по алгоритму Triple DES (3DES). Используется для совместимости с устаревшими системами.
const CryptoJS = require("crypto-js");
const message = "Legacy data";
const key = "24bytekeyfortripledes!!"; // Ключ должен быть 24 байта
const encrypted = CryptoJS.TripleDES.encrypt(message, key).toString();
console.log("3DES Encrypted:", encrypted);
const decrypted = CryptoJS.TripleDES.decrypt(encrypted, key).toString(CryptoJS.enc.Utf8);
console.log("3DES Decrypted:", decrypted);
Реальный практический пример
Рассмотрим полноценный пример создания безопасного менеджера паролей. Приложение будет шифровать пароли пользователя с использованием мастер-пароля, сохранять их в файл и дешифровать при необходимости.
const CryptoJS = require("crypto-js");
const fs = require("fs");
const readline = require("readline");
// Настройки шифрования
const ITERATIONS = 100000;
const KEY_SIZE = 256 / 32;
const SALT_SIZE = 32;
class PasswordManager {
constructor(masterPassword) {
this.masterPassword = masterPassword;
this.salt = CryptoJS.lib.WordArray.random(SALT_SIZE);
this.encryptionKey = this._deriveKey(masterPassword);
this.vault = {};
}
// Вывод ключа из мастер-пароля
_deriveKey(password) {
return CryptoJS.PBKDF2(password, this.salt, {
keySize: KEY_SIZE,
iterations: ITERATIONS,
hasher: CryptoJS.algo.SHA512
});
}
// Шифрование отдельной записи
_encryptEntry(plaintext) {
const iv = CryptoJS.lib.WordArray.random(16);
const encrypted = CryptoJS.AES.encrypt(plaintext, this.encryptionKey, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return {
iv: iv.toString(CryptoJS.enc.Hex),
data: encrypted.toString()
};
}
// Дешифрование записи
_decryptEntry(entry) {
const iv = CryptoJS.enc.Hex.parse(entry.iv);
const decrypted = CryptoJS.AES.decrypt(entry.data, this.encryptionKey, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return decrypted.toString(CryptoJS.enc.Utf8);
}
// Добавление пароля
addPassword(service, username, password) {
const plaintext = JSON.stringify({ username, password });
this.vault[service] = this._encryptEntry(plaintext);
console.log(`✅ Пароль для ${service} добавлен`);
}
// Получение пароля
getPassword(service) {
if (!this.vault[service]) {
console.log(`❌ Сервис "${service}" не найден`);
return null;
}
try {
const decrypted = this._decryptEntry(this.vault[service]);
const { username, password } = JSON.parse(decrypted);
console.log(`🔑 ${service}: ${username} / ${password}`);
return { username, password };
} catch (error) {
console.log("❌ Ошибка дешифрования. Возможно, неверный мастер-пароль.");
return null;
}
}
// Сохранение хранилища в файл
saveToFile(filename) {
const data = {
salt: this.salt.toString(CryptoJS.enc.Hex),
vault: this.vault
};
fs.writeFileSync(filename, JSON.stringify(data, null, 2));
console.log(`💾 Хранилище сохранено в ${filename}`);
}
// Загрузка хранилища из файла
loadFromFile(filename) {
if (!fs.existsSync(filename)) {
console.log("❌ Файл хранилища не найден");
return false;
}
const raw = fs.readFileSync(filename, "utf8");
const data = JSON.parse(raw);
this.salt = CryptoJS.enc.Hex.parse(data.salt);
this.encryptionKey = this._deriveKey(this.masterPassword);
this.vault = data.vault;
console.log(`📂 Хранилище загружено из ${filename}`);
return true;
}
// Вывод списка сервисов
listServices() {
console.log("📋 Список сохранённых сервисов:");
Object.keys(this.vault).forEach(service => {
console.log(` - ${service}`);
});
}
}
// Демонстрация работы
async function main() {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const question = (query) => new Promise(resolve => rl.question(query, resolve));
console.log("🔐 Менеджер паролей (Crypto-js Demo)");
console.log("=".repeat(40));
const masterPassword = await question("Введите мастер-пароль: ");
const manager = new PasswordManager(masterPassword);
// Попробуем загрузить существующее хранилище
const loaded = manager.loadFromFile("vault.json");
while (true) {
console.log("\nВыберите действие:");
console.log("1. Добавить пароль");
console.log("2. Получить пароль");
console.log("3. Список сервисов");
console.log("4. Сохранить и выйти");
const choice = await question("Ваш выбор (1-4