Соль (salt) в криптографии представляет собой случайную последовательность байт, которая добавляется к исходным данным (чаще всего паролю) перед применением хеш-функции или алгоритма выработки ключа. Основная задача соли — исключить предсказуемость результата и защитить от предварительно вычисленных атак, таких как rainbow tables.
В Stanford JavaScript Crypto Library (SJCL) соль используется в механизмах симметричного шифрования на основе пароля и в функции PBKDF2 (Password-Based Key Derivation Function 2), которая применяется для получения криптографического ключа из пароля.
При преобразовании пароля в ключ нельзя использовать сам пароль напрямую. Вместо этого применяется функция многократного хеширования с добавлением соли:
K = (P, S, c, dkLen)
где:
В SJCL этот процесс используется внутри функций
sjcl.encrypt и sjcl.misc.pbkdf2.
В SJCL генерация случайных значений основана на криптографически
стойком генераторе случайных чисел sjcl.random.
Базовый способ получения соли:
const salt = sjcl.random.randomWords(8, 0);
Здесь:
8 — количество 32-битных слов (32 байта соли)0 — параноидальный уровень энтропии (минимальный
контроль блокировки генерации)Соль в SJCL обычно хранится как массив 32-битных чисел, а не строка.
Качество соли напрямую зависит от состояния генератора случайных чисел. SJCL использует накопление энтропии из событий браузера:
Перед использованием криптографических функций важно обеспечить достаточную энтропию:
sjcl.random.addEntropy([new Date().getTime()], 32, "time");
Без накопленной энтропии генерация соли может стать предсказуемой, что полностью ломает безопасность схемы.
Функция PBKDF2 в SJCL позволяет явно задавать соль:
const password = "secret-password";
const salt = sjcl.random.randomWords(8, 0);
const derivedKey = sjcl.misc.pbkdf2(password, salt, 10000, 256);
Параметры:
password — исходный парольsalt — случайная соль10000 — число итераций (усиление вычислений)256 — длина ключа в битахУвеличение количества итераций замедляет подбор пароля, а уникальная соль делает каждый результат неповторимым даже при одинаковых паролях.
При использовании высокоуровневого API шифрования SJCL соль создаётся автоматически:
const encrypted = sjcl.encrypt("password", "secret data");
Результат представляет собой JSON-строку:
{
"iv": "...",
"v": 1,
"iter": 10000,
"ks": 256,
"ts": 64,
"mode": "ccm",
"adata": "",
"cipher": "aes",
"salt": "....",
"ct": "...."
}
Поле salt генерируется автоматически и используется
внутри PBKDF2 для получения ключа шифрования.
Повторное шифрование одинаковых данных с тем же паролем даёт разные результаты именно из-за новой соли.
Соль не является секретом. Её свойства:
Ключевая ошибка — попытка использовать одну и ту же соль повторно. Это приводит к:
В SJCL соль сохраняется внутри сериализованного объекта шифрования, поэтому дополнительная логика хранения обычно не требуется.
При самостоятельном использовании PBKDF2 необходимо хранить соль отдельно:
const record = {
salt: sjcl.codec.hex.fromBits(salt),
key: sjcl.codec.hex.fromBits(derivedKey)
};
При восстановлении ключа соль обязательно должна использоваться в исходном виде.
Распространённые проблемы:
const salt = sjcl.codec.utf8String.toBits("static");
Такой подход полностью уничтожает защиту от радужных таблиц.
Генерация без sjcl.random:
const salt = [Math.random(), Math.random()];
Math.random() не является криптографически безопасным
источником.
Без сохранённой соли восстановление ключа невозможно:
В SJCL часто путают соль и IV (Initialization Vector):
Они выполняют разные функции и не заменяют друг друга. Даже при одинаковом пароле:
Рекомендуемая конфигурация:
sjcl.random.randomWords(4–8, 0)При корректном использовании SJCL:
Соль не усиливает пароль напрямую, но создаёт уникальный контекст для каждого случая шифрования, что является критическим элементом всей схемы PBKDF2 и симметричного шифрования на основе пароля в SJCL.