Слабый генератор случайных чисел в контексте ECDSA приводит к полной
компрометации приватного ключа даже при корректной математической
реализации алгоритма. В криптографии подпись ECDSA считается безопасной
только при строгом выполнении одного критического условия —
одноразовости и криптографической стойкости nonce k,
используемого при генерации каждой подписи.
ECDSA формируется вокруг параметров эллиптической кривой с порядком
группы n и приватного ключа d. Для подписи
сообщения вычисляется хэш z и выбирается случайное значение
k, после чего:
R = k * Gr = R.x mod ns = k⁻¹ (z + r·d) mod nПодпись — это пара (r, s).
Ключевая уязвимость заключается в том, что значение k
должно быть:
[1, n-1]Любое отклонение разрушает безопасность схемы.
Если генератор случайных чисел предсказуем или повторяет значения, возникает несколько критических сценариев.
Если два разных сообщения подписаны с одинаковым k,
получаем:
s1 = k⁻¹ (z1 + r·d)s2 = k⁻¹ (z2 + r·d)Вычитая уравнения, можно выразить k, а затем
восстановить приватный ключ:
d = (s1·z2 - s2·z1) / (r·(s2 - s1)) mod n
Это полностью разрушает ключевую пару.
В Stanford JavaScript Crypto Library (SJCL) используется модуль:
sjcl.randomОн строится на сборе энтропии из:
Пример инициализации:
sjcl.random.startCollectors();
И использование:
const k = sjcl.bn.random(n);
Проблема возникает, когда:
encrypt/sign без прогрева
RNGconst key = sjcl.random.randomWords(8);
Если random ещё не собрал достаточный entropy pool,
результат может быть предсказуемым.
SJCL позволяет проверку:
if (!sjcl.random.isReady()) {
sjcl.random.addEventListener('ready', signData);
}
Игнорирование этого состояния приводит к деградации стойкости.
В некоторых интеграциях разработчики заменяют источник случайности:
sjcl.random = Math.random;
Это полностью уничтожает криптографическую стойкость, так как
Math.random():
В JavaScript-криптографии часто возникает конфликт между:
window.crypto.getRandomValues() (криптографически
стойкий источник)sjcl.random (энтропийный пул с накоплением)SJCL может работать автономно, но при неправильной конфигурации не использует системный CSPRNG напрямую.
В современных условиях предпочтительно связывать SJCL с:
sjcl.random.setDefaultParanoia(6);
и обеспечивать первичную инициализацию через системный генератор.
Даже частичная утечка k приводит к возможности
восстановления d. Если известны несколько битов nonce или
наблюдается bias (смещение распределения), применяются методы:
В JS-среде это особенно актуально из-за:
Для устранения зависимости от случайности применяется детерминированная генерация nonce:
В этом подходе k вычисляется как функция:
k = HMAC(privkey, hash(message))
Преимущество:
SJCL сам по себе не всегда принудительно использует RFC6979, поэтому интеграция должна быть явной.
sjcl.random хранит внутренний пул энтропии. При
неправильной эксплуатации возникают состояния:
Особенно критично в сценариях:
В анализе подписей можно выявить:
r значения(r, s)Даже без знания приватного ключа это указывает на деградацию генератора случайных чисел.
ECDSA как математическая конструкция остаётся корректной, но реализация в JavaScript через SJCL полностью зависит от качества:
sjcl.randomОшибки в любом из этих уровней приводят к компрометации даже при идеальной эллиптической кривой и корректных параметрах группы.