Как зашифровать текст паролем
- Оставьте выбранными Зашифровать и тип ключа Пароль.
- Введите Пароль. Показать пароль открывает его во время ввода. Оставьте Итерации PBKDF2 равными 310 000, если нет особых причин; тот, кто будет расшифровывать, должен ввести то же число.
- Наберите сообщение в поле Открытый текст и нажмите Зашифровать, Enter в поле пароля или Ctrl+Enter в тексте.
- Скопируйте Зашифрованный Base64 или скачайте его. Отметьте Вывод URL-safe (- _ , без =), если строка пойдёт в URL.
Под результатом инструмент показывает разбивку: размеры соли, IV, шифртекста и тега, общий размер и способ вывода ключа. Чтобы передать результат, отправьте Base64 одним сообщением, а пароль передайте по другому каналу, например по телефону или в другом мессенджере. Получатель открывает AES-расшифровку и проделывает всё в обратном порядке.
Для чего это нужно и для чего нет
Инструмент нужен, чтобы безопасно передать кусок текста, когда лучшего канала нет: пароль от Wi-Fi для гостя, код восстановления коллеге, заметку в тикете, который читает слишком много людей. Он заменяет «да просто скину в чат» на то, что перехватчик не прочитает.
Это не менеджер секретов. Он ничего не хранит, не управляет доступом, не записывает, кто что расшифровал, не меняет ключи и не может отозвать уже отправленный секрет. Учётным данным приложений, боевым ключам и всему, чем пользуется команда, место в настоящем менеджере секретов или менеджере паролей с общим доступом. И помните: зашифрованный текст навсегда остаётся расшифровываемым для любого, кто позже узнает пароль.
Точный формат
В режиме пароля результат такой:
Base64( salt[16] ‖ iv[12] ‖ ciphertext ‖ tag[16] )
- Ключ: PBKDF2-HMAC-SHA256 от пароля в UTF-8 с 16-байтной солью и 310 000 итераций, на выходе 32 байта.
- Шифр: AES-256-GCM с 12-байтным IV, 128-битным тегом и без дополнительных данных.
- Случайность: новые соль и IV при каждом шифровании, из
crypto.getRandomValues.
Шифртекст ровно той же длины, что и сообщение в UTF-8, так что накладные расходы блоба составляют 44 байта. Сообщение в 33 байта превращается в 77 байт, то есть в 104 символа Base64. Байта версии нет, и число итераций не сохраняется: если вы его меняете, получатель должен ввести то же значение, иначе расшифровка завершится той же ошибкой, что и при неверном пароле.
В режиме «Сырой» ключ шаг PBKDF2 исчезает, и результат имеет вид Base64( iv[12] ‖ ciphertext ‖ tag[16] ), зашифрованный вашим ключом длиной 16, 24 или 32 байта в Base64 или hex. Кнопка Сгенерировать случайный ключ создаёт такой ключ. Chrome и Edge не поддерживают 192-битные ключи AES, и инструмент в этом случае выдаёт понятную ошибку; используйте 128 или 256 бит.
Расшифровка в Python или Node.js
Получателю не нужен этот сайт. В Python с пакетом cryptography (pip install cryptography):
import base64, os
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives import hashes
def _key(password, salt):
return PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt=salt,
iterations=310000).derive(password.encode("utf-8"))
def decrypt(b64, password):
data = base64.b64decode(b64)
salt, iv, ct = data[:16], data[16:28], data[28:]
return AESGCM(_key(password, salt)).decrypt(iv, ct, None).decode("utf-8")
def encrypt(text, password):
salt, iv = os.urandom(16), os.urandom(12)
ct = AESGCM(_key(password, salt)).encrypt(iv, text.encode("utf-8"), None)
return base64.b64encode(salt + iv + ct).decode("ascii")
AESGCM.decrypt ожидает тег в конце шифртекста, и именно там его размещает этот формат. В Node.js тег нужно отделить и передать отдельно:
const crypto = require("crypto");
function decrypt(b64, password) {
const data = Buffer.from(b64, "base64");
const salt = data.subarray(0, 16), iv = data.subarray(16, 28);
const tag = data.subarray(data.length - 16), ct = data.subarray(28, data.length - 16);
const key = crypto.pbkdf2Sync(password, salt, 310000, 32, "sha256");
const d = crypto.createDecipheriv("aes-256-gcm", key, iv);
d.setAuthTag(tag);
return Buffer.concat([d.update(ct), d.final()]).toString("utf8");
}
Блобы с этой страницы расшифровываются обеими функциями, а блобы из encrypt() расшифровывает эта страница. Если вы выбрали вывод URL-safe, Buffer.from(b64, "base64") в Node прочитает его как есть, а в Python используйте base64.urlsafe_b64decode(b64 + "=" * (-len(b64) % 4)). openssl enc здесь не поможет: GCM он не поддерживает. Base64-сторона подробнее разобрана на страницах Python и Node.js.
Вопросы и ответы
Достаточно ли закодировать текст в Base64, чтобы его защитить?
Нет. Base64 меняет только способ записи байтов, и декодировать его может любой без ключа. Этот инструмент сначала шифрует AES, а Base64 использует лишь для того, чтобы превратить шифртекст в текст, который можно вставить куда угодно. Разница разобрана в статье Base64 – это не шифрование.
Почему при шифровании одного и того же текста результат каждый раз другой?
Каждый запуск использует новую случайную соль на 16 байт и IV на 12 байт. Так и задумано: одинаковые сообщения не должны давать одинаковый шифртекст, а AES-GCM никогда не должен повторно использовать IV с тем же ключом.
Насколько стойким должен быть пароль?
PBKDF2 с 310 000 итераций замедляет перебор, но короткий или распространённый пароль это не спасёт. Используйте длинную случайную парольную фразу, например из пяти и более случайных слов, и передавайте её по другому каналу, чем шифртекст.
Можно ли шифровать этим инструментом файлы?
Нет, он шифрует только текст. Для файлов берите специальный инструмент вроде age или gpg.
Какой режим AES и размер ключа использует инструмент?
В режиме пароля используется AES-256 в режиме GCM с 128-битным тегом аутентификации. В режиме «сырого» ключа размер зависит от вашего ключа: 128, 192 или 256 бит.