В части 1 статьи «За пределами безопасного хранения» рассматривалось неправомерное использование собственной функции подписи платёжной системы. Эта вторая часть посвящена другому способу получения несанкционированных подписей: ошибки в реализации криптографии позволяют злоумышленнику восстановить приватный ключ и самостоятельно подписывать операции. Главный вопрос: может ли злоумышленник восстановить ключ, не читая его защищённую копию?
В разделе 1 изложены требования безопасности к генерации и хранению ключей, а также к подписанию. В разделах 2 и 3 разбираются четыре инцидента, связанных с генерацией ключей, и два инцидента, связанных с подписанием, с объяснением ошибок реализации и их последствий. В разделе 4 на основе этих случаев сформулированы принципы проектирования и реализации, а затем объясняется, как проверять соблюдение необходимых требований.
1. Требования безопасности на протяжении жизненного цикла ключа
Ключ необходимо сгенерировать, сохранить и использовать для подписания. Как показано на схеме, к каждому этапу предъявляется своё требование безопасности.

В иерархическом детерминированном кошельке, использующем мнемонические фразы BIP-39 и вывод ключей по BIP-32, криптографически стойкие случайные данные кодируются в мнемоническую фразу и преобразуются в начальное значение. Из него выводятся приватные ключи, публичные ключи и адреса кошелька [1, 2].
После генерации начальные значения и приватные ключи необходимо защищать с помощью шифрования или аппаратной изоляции. Затем приватный ключ используется для создания подписи, которую можно проверить публично. В зависимости от схемы для подписания также может требоваться случайный nonce, сгенерированный безопасным способом или детерминированно выведенный из секретных данных.
На этих этапах действуют разные требования безопасности:
- Непредсказуемость при создании. Злоумышленник не должен иметь возможности предсказать секрет, управляющий кошельком, или перебрать возможные значения этого секрета на практике.
- Конфиденциальность при хранении. Посторонние лица не должны иметь возможности прочитать секретные данные через программное обеспечение, физические интерфейсы, резервные копии, журналы или удалённые сервисы.
- Отсутствие утечек при использовании. Подписание не должно раскрывать достаточно информации для восстановления секрета даже после появления множества публично наблюдаемых подписей.
Аппаратные кошельки, защищённые элементы и доверенные среды исполнения (TEE) могут усилить защиту конфиденциальности. Но само по себе их наличие не обеспечивает соблюдения двух других требований. Предсказуемый ключ остаётся предсказуемым после помещения в защищённое хранилище; математическая информация, раскрываемая подписями, остаётся доступной, даже если байты приватного ключа изолированы от хост-системы. Поэтому злоумышленник может восстановить уязвимый ключ и получить доступ к активам под его управлением, не читая сохранённую копию ключа.
В следующих двух разделах рассматривается, как ошибки реализации нарушают эти требования: недостатки генерации могут делать ключи предсказуемыми, а недостатки подписания — позволять восстанавливать их по публичным подписям. Эти случаи лежат в основе принципов реализации и целей проверки, изложенных в разделе 4.
2. Ошибки генерации ключей: предсказуемые приватные ключи
При генерации ключей непредсказуемость должна сохраняться на каждом шаге. Источник энтропии должен быть пригоден для криптографических целей, его состояния не должны поддаваться перебору на практике, а преобразования случайных байтов в начальное значение или приватный ключ должны сохранять предполагаемый уровень неопределённости. Для достижения 128-битного уровня безопасности пространство возможных секретов не должно сокращаться из-за ошибок реализации до размера, допускающего перебор на практике.
В таблице обобщены четыре способа утратить это свойство при генерации: слабый генератор в библиотеке, неверное подключение генератора случайных чисел (RNG), преобразование входных данных с потерей информации и генератор с ограниченным числом начальных состояний. Данные о последствиях взяты из отчётов за разные периоды; это не итоговые показатели, измеренные на одну дату.
| Инцидент | Период | Заявленный ущерб (прибл.) | Рассматриваемая ниже причина сбоя |
|---|---|---|---|
| Ill Bloom | май — июль 2026 года | нижняя оценка — около 5 млн USD по состоянию на 13 июля | Слабая случайность при генерации мнемонической фразы |
| Coldcard | С 30.07.2026; подсчёт по состоянию на 14 августа | 112,70 млн USD | Неверный путь вызова RNG в прошивке |
| XRPH Wallet | 03.09.2026 | 450 тыс. USD | Предсказуемые, крайне ограниченные входные данные для генерации кошелька |
| Qubic Wallet | 17.10.2026–18.10.2026 | 1,3 млн USD | Небезопасная генерация начального значения с помощью Math.random() |
2,1 Ill Bloom: слабая случайность в зависимости кошелька
В инциденте Ill Bloom некоторые программные кошельки генерировали фразы восстановления BIP-39 с использованием уязвимых версий crypto-js. Функция CryptoJS.lib.WordArray.random() этой библиотеки использовала собственный генератор с умножением и переносом (MWC), инициализируемый с помощью Math.random(), вместо получения энтропии из криптографически стойкого источника. Кошельки, использовавшие эту функцию как источник энтропии для задач, критичных с точки зрения безопасности, унаследовали недостатки генератора, даже если последующие этапы формирования мнемонической фразы и вывода ключей выполнялись в соответствии со стандартами [3].
Уязвимая реализация crypto-js v3.1.9-1 [4] содержит следующую характерную логику:
random: function (nBytes) {
var words = [];
var r = (function (m_w) {
var m_w = m_w;
var m_z = 0x3ade68b1;
var mask = 0xffffffff;
return function () {
m_z = (0x9069 * (m_z & 0xFFFF) + (m_z >> 0x10)) & mask;
m_w = (0x4650 * (m_w & 0xFFFF) + (m_w >> 0x10)) & mask;
var result = ((m_z << 0x10) + m_w) & mask;
result /= 0x100000000;
result += 0.5;
return result * (Math.random() > .5 ? 1 : -1);
}
});
for (var i = 0, rcache; i < nBytes; i += 4) {
var _r = r((rcache || Math.random()) * 0x100000000);
rcache = _r() * 0x3ade67b7;
words.push((_r() * 0x100000000) | 0);
}
return new WordArray.init(words, nBytes);
}
Здесь r() — собственный генератор на основе MWC, а Math.random() помогает инициализировать его состояние или влияет на него. Этот генератор псевдослучайных чисел (PRNG) выдаёт байты, похожие на обычную энтропию, но реализация не обеспечивала криптографической непредсказуемости. Эффективные пространства возможных значений составляли приблизительно 2 USD^{39}$ для номинально 128-битного выхода и 2 USD^{47}$ для номинально 256-битного выхода [3].
Уменьшенные пространства значений позволяли на практике восстановить возможные фразы восстановления, вывести соответствующие адреса кошельков и сопоставить их с публично доступными данными об активности в блокчейне. Таким образом, секрет можно было восстановить, ничего не извлекая из устройства жертвы. Следование стандарту мнемонических фраз не могло устранить слабую случайность, унаследованную от более старой зависимости.
2,2 Coldcard: аппаратный генератор случайных чисел, который не использовался кодом
Случай Coldcard показывает, почему одного наличия надёжного источника случайности недостаточно, если приложение обращается к другому генератору. Хотя устройство имело аппаратный генератор случайных чисел, ошибка интеграции на этапе сборки привела к тому, что rng_get() в коде генерации сид-фразы обращалась вместо него к Yasmarang — программному генератору псевдослучайных чисел MicroPython. Этот генератор, не предназначенный для криптографических целей, инициализировался с использованием неизменного уникального идентификатора устройства и ограниченной информации о времени. В результате его начальное состояние было достаточно предсказуемым, чтобы резко снизить эффективную энтропию генерируемых сид-фраз кошельков [5].

Процедура генерации сид-фразы также добавляла данные второго генератора Yasmarang. На старых устройствах Mk2/Mk3 этот второй генератор начинал работу с общедоступных констант и не добавлял энтропии. В новых моделях в процесс включили случайные данные из защищённых элементов, но при повторной инициализации генератора сохранялось лишь 32 бита. Поэтому, несмотря на создание 256-битных сид-фраз кошельков, эффективное пространство поиска резко сократилось. По предварительной оценке Coinkite, при указанных компанией допущениях относительно атаки число вариантов составляло около 2 USD^{40}$ для Mk2/Mk3 и 2 USD^{72}$ для Mk4/Q/Mk5 [6, 7].
Из-за этой слабости восстановление сид-фразы сводилось к автономному перебору: злоумышленник мог получать адреса из предполагаемых сид-фраз и сравнивать их с общедоступными данными блокчейна. Практические затраты зависят от модели устройства и допущений относительно атаки; оценка 2 USD^{72}$ не означает такой же осуществимости атаки, как в случае с 2 USD^{40}$. Найденное совпадение раскрывает соответствующие приватные ключи.
2.3 XRPH Wallet: ошибка формата входных данных, сократившая пространство ключей
Процесс генерации также включает преобразование случайных данных в формат, ожидаемый API кошелька. В XRPH Wallet при таком преобразовании отбрасывалась большая часть сгенерированных данных. Приложение для Android генерировало десятичные блоки с помощью JavaScript Math.random(), объединяло их в текстовую строку и передавало её в Wallet.fromEntropy(). Принимающий код интерпретировал символы как небольшие целочисленные значения байтов и сохранял только первые 16 позиций. Поскольку две позиции занимали неизменные разделители-пробелы, энтропию в итоговый кошелёк вносили лишь 14 изменяющихся десятичных цифр [8].
padlock = { A, B, C, D, E, F, G, H }; // each = 6 digits from the line above
r6 = A.join('') + ' ' + B.join('') + ' ' + C.join('') + ' ' + D.join('')
+ ' ' + E.join('') + ' ' + F.join('') + ' ' + G.join('') + ' ' + H.join('');
r5 = Wallet.fromEntropy;
r3 = r5.bind(Wallet)(r6); // a 55-char STRING is passed; fromEntropy wants 16 bytes
// compute entropy be like
const input = "528875 921568 528239 ..."; // decimal blocks
const entropy = Uint8Array.from(input).slice(0, 16);
// Result: [5,2,8,8,7,5,0,9,2,1,5,6,8,0,5,2]
После такого преобразования доступными оставались приблизительно 10 USD^{14}\approx 2^{46}$ вариантов входных данных кошелька вместо предполагавшегося пространства размером примерно 2 USD^{128}$ при равномерной выборке 16 байтов энтропии. Эта величина описывает число вариантов, достижимых при наблюдавшемся преобразовании, а не служит криптографическим доказательством статистической энтропии Math.random().
Два недостатка усугубили друг друга: неподходящий источник случайных чисел и ошибка представления и кодирования данных на границе API. Оба могут остаться незамеченными при функциональном тестировании, поскольку кошелёк по-прежнему генерирует правдоподобные адреса и подписывает действительные транзакции. Опубликованное расследование устанавливает, что пространство ключей допускает их восстановление, но само по себе не доказывает, каким именно способом злоумышленник получил ключ.
2,4 Qubic Wallet: слабая случайность за сид-фразой из 55 символов
Начальное состояние генератора тоже может ограничивать число возможных сид-фраз, какой бы длинной ни выглядела выходная строка. Пример Qubic иллюстрирует эту проблему: согласно сообщениям, компрометация его кошельков затронула сид-фразы, сгенерированные с помощью некриптографического генератора JavaScript Math.random(). Среди затронутых сред были браузеры Apple и некоторые старые сборки приложения для iOS на основе JavaScriptCore [9, 10].
Уязвимую логику генерации и её исправление можно представить следующим образом [11]:
// Vulnerable seed generation (abridged)
seed += letters[Math.floor(Math.random() * 26)];
// Corrected approach (schematic excerpt of the fix)
crypto.getRandomValues(bytes);
if (byte < 234) seed += letters[byte % 26];
Вызов Math.random() 55 раз не даёт 55 независимых источников энтропии. Между повторными инициализациями каждый вызов генератора псевдослучайных чисел детерминированно изменяет его внутреннее состояние. При фиксированной позиции вызова, если начальное значение равно , вся сид-фраза кошелька из 55 символов представляет собой детерминированную функцию . Знания и этой позиции вызова достаточно, чтобы воспроизвести все 55 символов; дополнительные вызовы генератора не создают дополнительной энтропии.
Диапазон возможных начальных состояний зависит от инициализации в среде выполнения. В исходном коде JavaScriptCore, снимок которого был получен 29.10.2026, генератор псевдослучайных чисел инициализируется 32-битным начальным значением. Это даёт не более 2 USD^{32}$ последовательностей при фиксированной позиции вызова. В рассмотренном здесь исходном коде V8 используется 64-битное начальное значение, что даёт не более 2 USD^{64}$ таких последовательностей. Эти верхние границы относятся к изученным путям инициализации при фиксированной позиции вызова. Снимки исходного кода не позволяют установить ни точные сборки браузеров, использовавшиеся во время инцидента, ни затраты на эксплуатацию уязвимости в них. В исправленной версии для получения криптографически стойких случайных данных используется crypto.getRandomValues(), а выборка с отбрасыванием (byte < 234) позволяет избежать смещения при сопоставлении байтов с 26 буквами [12, 13, 14].
3. Ошибки при подписании: восстановление приватного ключа по общедоступным подписям
После безопасной генерации ключ должен оставаться секретным и при использовании для подписания. Каждая подпись делает определённые данные доступными наблюдателям, а ошибки реализации могут превратить эти общедоступные данные в информацию, достаточную для восстановления приватного ключа. ECDSA и Schnorr используют для каждой подписи секретный скаляр, называемый одноразовым значением, чтобы скрыть вклад приватного ключа в общедоступную подпись.
Одноразовое значение должно оставаться секретным, не должно повторно использоваться для разных сообщений с одним и тем же ключом и должно соответствовать требованиям схемы к распределению. Детерминированный способ его получения совместим с этими требованиями: знания открытого ключа и подписанного сообщения не должно быть достаточно для предсказания одноразового значения.
Рассмотрим в качестве примера упрощённое соотношение для Schnorr:
где — приватный ключ, — одноразовое значение, — общедоступное проверочное значение, вычисляемое на основе общедоступной информации (например, открытого ключа и сообщения), — общедоступный скаляр подписи, а — порядок подгруппы. Если одноразовое значение известно, то при существовании обратного элемента для приватный ключ немедленно раскрывается: .
Кроме того, для утечки ключа необязательно знать одноразовое значение целиком. Ограничения или смещение в нескольких одноразовых значениях могут дать достаточно информации для восстановления ключа методами на основе решёток. Осуществимость зависит от раскрытой информации и доступных подписей.
В таблице сопоставлены два сбоя при формировании одноразовых чисел, рассматриваемые в этом разделе: в Zilliqa их значения были частично ограничены, а в SecondFi их стало возможно вычислить по общедоступным данным. Данные о последствиях относятся к разным историческим периодам.
| Инцидент | Период | Последствия по опубликованным данным (приблизительно) | Рассматриваемый ниже тип сбоя |
|---|---|---|---|
| Zilliqa Ledger Wallet | март — июль 2026 года | 683 130 969,66 ZIL |
Смещение в распределении одноразовых чисел при подписании по схеме EC-Schnorr |
| SecondFi | июнь 2026 года | Не установлены на основании приведённого кода | Ошибка при получении одноразового числа для Ed25519 |
3,1 Zilliqa Ledger Wallet: в каждом одноразовом числе для Schnorr отсутствовали 64 бита
Инцидент с Zilliqa Ledger Wallet был связан с ошибкой в приложении для транзакций Zilliqa по прежней схеме EC-Schnorr [15]. Приложение генерировало данные для одноразового числа, но копировало в итоговый буфер подписания не ту их часть. Оно сохраняло восемь нулевых байтов, добавленных для заполнения, и отбрасывало восемь байтов настоящих случайных данных. В результате каждое затронутое одноразовое число удовлетворяло условию 0 USD \le k < 2^{192},$ вместо того чтобы надлежащим образом принимать значения в пределах порядка группы secp256k1 размером примерно 256 бит.
Уравнения подписи показывают, почему такое ограничение одноразового числа имеет значение:
Здесь — образующий элемент группы. Преобразовав выражение, получаем
Таким образом, каждая подпись задаёт сравнение по модулю с неизвестным , при этом одноразовое число ограничено сверху величиной 2 USD^{192}$. Объединение нескольких независимых соотношений даёт задачу о скрытом числе (Hidden Number Problem, HNP), к решению которой можно подойти с помощью редукции решёток. Согласно официальному разбору инцидента, закрытый ключ удалось восстановить по четырём или более затронутым подписям.
Защищённому элементу не требовалось раскрывать байты закрытого ключа. Из-за смещённого распределения одноразовых чисел ключ можно было восстановить по подписям, уже опубликованным в блокчейне.
3,2 SecondFi: одноразовое число для подписи, вычисляемое по общедоступным данным
В SecondFi неправильное получение одноразового числа для Ed25519 привело не просто к частичному ограничению его возможных значений: число стало вычисляемым по общедоступным данным. Это позволило восстанавливать закрытые ключи подписи по одной общедоступной подписи транзакции [16].
В подписи типа Ed25519 предусмотренный схемой алгоритм получает секретный скаляр и секретный префикс для одноразового числа из секретного ключевого материала. Здесь — открытый ключ, — базовая точка Ed25519, — подписываемое сообщение, — порядок подгруппы, а обозначает SHA-512. Схематически это выглядит так:
Реализация с ошибкой вместо этого задаёт . Любой, кто знает подписанное сообщение, может вычислить . Поскольку , и общедоступны, наблюдатель затем может вычислить
при условии, что не равно нулю по модулю .
В отличие от частичной утечки одноразового числа в Zilliqa, для восстановления скаляра подписи здесь было достаточно одной затронутой подписи. Это само по себе не доказывает, что можно восстановить исходную мнемоническую фразу или все другие ключи того же уровня в иерархическом кошельке. Сбой произошёл на стыке получения ключей и подписания: необходимый секрет был доступен, но его не передали в процедуру получения одноразового числа.
4. Принципы безопасной реализации и проверка
В совокупности эти случаи показывают, почему источники случайности и алгоритмы подписания нужно проверять вместе с кодом, который их связывает. Непредсказуемый источник должен давать непредсказуемые ключи, а эти ключи должны оставаться секретными при подписании. Ошибки в процедурах преобразования данных или интерфейсах библиотек могут нарушить любое из этих требований.
В разделах 4,1 и 4,2 изложены принципы проектирования и реализации генерации ключей и подписания. Раздел 4,3 объясняет, какие подтверждения должны дать проверки и тесты для оценки соблюдения этих принципов в развёрнутой системе.
4,1 Сохраняйте стойкость при генерации ключей
Случаи, связанные с генерацией, указывают на три требования к реализации:
-
Используйте криптографически стойкий источник случайности и останавливайте генерацию при сбое. Для начальных значений и закрытых ключей требуется подходящий криптографически стойкий источник, например криптографически стойкий генератор псевдослучайных чисел (CSPRNG). Случаи Ill Bloom и Qubic показывают, почему генератор общего назначения не может выполнять эту роль. Если предусмотренный источник недоступен или даёт сбой, генерацию необходимо остановить, а не незаметно переключать на более слабый источник.
-
Сохраняйте энтропию при преобразовании данных. Выходные данные стойкого источника должны сохранять необходимую неопределённость при кодировании, выборке и передаче между интерфейсами. Случай XRPH Wallet показывает, почему внешне корректного результата недостаточно. Ограничения на тип, длину и кодирование должны предотвращать непредусмотренное усечение или смещение распределения при отображении значений, способное сократить фактическое пространство ключей.
-
Убедитесь, что развёрнутый код использует предусмотренный источник. Случай Coldcard показывает: наличие стойкого источника случайности ещё не устанавливает, к какому источнику приложение действительно обращается. Выбор источника должен оставаться правильным после интеграции, компиляции и развёртывания, в том числе на путях обработки ошибок и резервного переключения. Предположение о генераторе случайных чисел должно выполняться для исполняемого кода на целевой платформе.
4,2 Сохраняйте секретность при подписании
Требования к генерации защищают процесс создания ключа. Чтобы ключ оставался секретным при использовании, необходимо также правильно обращаться с одноразовыми числами. Требования зависят от схемы; наряду со схемами Schnorr и Ed25519, рассмотренными в этих случаях, список включает ECDSA.
-
ECDSA: Сохраняйте секретность и непредсказуемость одноразового числа и предотвращайте его повторное использование с одним ключом для разных сообщений. Детерминированная генерация согласно RFC 6979 [17] устраняет зависимость от новых внешних случайных данных для каждой подписи, но реализации всё равно необходимо защищать от утечек по побочным каналам и атак путём внесения сбоев.
-
EdDSA: Сохраняйте все секретные входные данные, необходимые для получения одноразового числа. SecondFi демонстрирует последствия исключения секретного префикса и использования только общедоступных данных. Обёртки и адаптеры ключей должны передавать полный набор секретных входных данных, требуемых RFC 8032 [18], а не считать сам факт получения работающей подписи доказательством правильности входных данных.
-
Schnorr: Сохраняйте распределение и представление одноразовых чисел, требуемые схемой. Как показывает Zilliqa, недостаточно лишь избегать повторений и полностью предсказуемых одноразовых чисел, если часть случайных данных теряется. Обработка данных и преобразование в скаляр не должны создавать ограничения или смещение распределения, которыми можно воспользоваться.
Хорошо проверенные библиотеки снижают риск ошибок реализации, но не устраняют ошибки интеграции. Даже правильная базовая реализация подписания остаётся небезопасной, если вызывающий её код передаёт неполные или повреждённые входные данные.
4.3 Проверяйте свойства безопасности
Чтобы оценить соблюдение этих требований, при проверках необходимо прослеживать путь входных данных через реализацию, которая действительно выполняется. Корректный результат может скрывать ошибку интеграции, поэтому проверка должна охватывать и пути выполнения, которые пропускают обычные функциональные тесты. В таблице требования к генерации и подписанию преобразованы в конкретные цели проверки:
| Область проверки | Цель проверки |
|---|---|
| Непредсказуемость энтропии | Установить, защищают ли источник, его инициализация и фактическое пространство начальных значений от вычислительно осуществимого предсказания или перебора |
| Сохранение энтропии | Убедиться, что преобразования и выборка сохраняют необходимую неопределённость без непредусмотренного усечения или смещения распределения |
| Интеграция генератора случайных чисел | Подтвердить, что развёрнутый исполняемый код использует предусмотренный источник, в том числе на путях обработки ошибок и резервного переключения |
| Секретность одноразового числа | Убедиться, что генерация или получение одноразового числа сохраняет его секретность, включая использование всех необходимых секретных входных данных, и что его нельзя воспроизвести только по общедоступным данным |
| Корректность одноразового числа | Сопоставить обработку одноразовых чисел с требованиями схемы, используя, где применимо, тесты с заранее известным результатом и независимые реализации |
| Безопасность зависимостей | Проверить версии и интеграцию криптографических зависимостей, а также убедиться, что обновления сохраняют требуемое поведение |
Для оценки этих целей необходимо сочетать несколько методов. Анализ кода позволяет проследить, как секретные и случайные входные данные поступают в развёрнутые процедуры генерации и подписания. Тесты нештатных сценариев и внесение сбоев позволяют исследовать поведение при нарушении обычных предположений; тесты с заранее известным результатом и сравнение с независимыми реализациями помогают выявить отклонения от схемы. Статистические тесты могут обнаружить очевидное смещение распределения, но успешная генерация адресов, проверка подписей или прохождение статистических тестов сами по себе не доказывают криптографическую стойкость. Оценивайте совокупность полученных подтверждений с учётом требований к источнику, обработке входных данных и схеме.
Сторонние команды или эксперты по безопасности могут дополнить внутреннюю проверку аудитом кода и интеграции, особенно на стыке источников случайности, получения ключей и библиотек подписания. Область проверки должна охватывать версии зависимостей, конфигурацию сборки и фактически выполняемый путь в коде. В выводах следует указывать затронутое свойство безопасности и приводить воспроизводимые подтверждения и регрессионные проверки. Изменения в реализации или её зависимостях всё равно требуют проверки.
Лучший аудитор безопасности Web3
Проверьте архитектуру, код и бизнес-логику до запуска
5. Заключение
Шесть инцидентов показывают два способа, которыми ошибки реализации могут подорвать защиту ключей: сократить множество возможных ключей при генерации или раскрыть сведения о существующем ключе через подписи. На основе анализа этих сбоев сформулированы требования к генерации и подписанию, а также цели проверки и тестирования кода, развёрнутого в платёжной инфраструктуре.
Для платёжных организаций безопасное хранение защищает сохранённый секрет, но не может исправить предсказуемую генерацию или устранить информацию, раскрываемую при подписании. Необходимые свойства должны сохраняться при использовании зависимостей и адаптеров и после развёртывания. Проверки и тесты должны охватывать всю эту реализацию, а не выводить её безопасность из корректности адресов и подписей.
Эти требования к реализации дополняют меры контроля процессов, рассмотренные в части 1 серии Beyond Secure Storage. В части 1 рассматриваются риски процессов, превентивные проверки и ограничение потерь, когда эти проверки не останавливают несанкционированные операции. Часть 2 посвящена ошибкам реализации, которые могут дать злоумышленнику возможность самостоятельно создавать подписи. Корректное выполнение криптографических операций не доказывает наличие разрешения на уровне бизнес-процесса; действительное одобрение в рамках бизнес-процесса не означает, что ключ подписи непредсказуем или что его невозможно восстановить. Для безопасности платёжных систем и систем подписания необходимо спроектировать и проверить как процесс авторизации, так и лежащую в его основе криптографическую реализацию.
Источники
-
[1] BIP-39, Мнемонический код для генерации детерминированных ключей.
-
[2] BIP-32, Иерархические детерминированные кошельки.
-
[3] CryptoJS, Уведомление о безопасности GHSA-rg76-677x-56q9.
-
[4] CryptoJS, исходный код core.js, версия 3.1.9-1.
-
[5] Coldcard, Уведомление о прошивке и примечания к выпуску.
-
[6] MicroPython, Разбор инцидента с Coldcard с точки зрения MicroPython.
-
[7] Coinkite, Подробный технический анализ проблемы с энтропией.
-
[8] XRPL.to, Взлом XRPH Wallet: опустошены 4011 кошельков, и любой ключ можно было угадать.
-
[9] Qubic, Заявление об инциденте и рекомендации для затронутых платформ.
-
[10] Qubicmap, Хронология инцидента Qubic и сводка по кошелькам.
-
[11] Qubic Wallet, Исправление генерации стойких начальных значений 09dd288.
-
[12] WebKit, JSGlobalObject.cpp, инициализация m_weakRandom.
-
[13] WebKit, WeakRandom.h, реализация начального значения и генератора псевдослучайных чисел.
-
[14] V8, math-random.cc, инициализация состояния генератора псевдослучайных чисел.
-
[15] Zilliqa, Разбор инцидента: смещение распределения одноразовых чисел в прежней схеме Schnorr.
-
[16] KarpelesLab, Анализ и воспроизведение реализации SecondFi.
-
[17] RFC 6979, Детерминированное применение DSA и ECDSA.
-
[18] RFC 8032, Алгоритм цифровой подписи на кривых Эдвардса (EdDSA).



