BlockChain-Account_TakeOver

题目描述

题目描述

ECDSA

签名

假设我们的私钥为 d A d_A dA而公钥为 Q A Q_A QA Q A = d A ⋅ G Q_A=d_A\cdot G QA=dAG,接下来就是签名的过程,要签名的消息为 m m m

  1. e = H A S H ( m ) e = HASH(m) e=HASH(m)
  2. e e e的左边的 L n L_n Ln个bit长度的值为 z z z L n L_n Ln即为前面提到的参数里 n n n的比特长度
  3. [ 1 , n − 1 ] [1, n-1] [1,n1]范围内,随机选择一个整数 k k k
  4. 利用 k k k得到椭圆曲线上的一点 ( x 1 , y 1 ) = k ⋅ G (x1,y1)=k \cdot G (x1y1)=kG
  5. 然后计算 r ≡ x 1 ( m o d n ) r \equiv x_1 (mod n) rx1(modn),如果如果 r = 0 r=0 r=0则返回步骤3重新选择 k k k
  6. 计算 s = k − 1 ( z + r ⋅ d A ) ( m o d n ) s = k^{-1}(z + r\cdot d_A) (mod n) s=k1(z+rdA)(modn),如果 s = 0 s=0 s=0则返回步骤3重新选择 k k k
  7. 得到的数字签名即为 ( r , s ) (r,s) (rs)

验证

取点 P = ( X p , Y p ) = s − 1 ⋅ z ⋅ G + s − 1 ⋅ r ⋅ Q A P=(X_p,Y_p)= s ^ {-1} \cdot z \cdot G + s ^ {-1} \cdot r \cdot Q_A P=(Xp,Yp)=s1zG+s1rQA
X p = r X_p=r Xp=r,则签名有效,否则无效

Simple Proof
P = ( X p , Y p ) = s − 1 ⋅ z ⋅ G + s − 1 ⋅ r ⋅ Q A P=(X_p,Y_p)= s ^ {-1} \cdot z \cdot G + s ^ {-1} \cdot r \cdot Q_A P=(Xp,Yp)=s1zG+s1rQA
因为 Q A = d A ⋅ G Q_A=d_A \cdot G QA=dAG,故有
P = s − 1 ⋅ z ⋅ G + s − 1 ⋅ r ⋅ Q A P= s ^ {-1} \cdot z \cdot G + s ^ {-1} \cdot r \cdot Q_A P=s1zG+s1rQA
= s − 1 ⋅ z ⋅ G + s − 1 ⋅ r ⋅ d A ⋅ G = s ^ {-1} \cdot z \cdot G + s ^ {-1} \cdot r \cdot d_A \cdot G =s1zG+s1rdAG
= s − 1 ⋅ G ⋅ ( z + r ⋅ d A ) = s ^ {-1} \cdot G \cdot {(z + r \cdot d_A)} =s1G(z+rdA)
又有 s = k − 1 ( z + r ⋅ d A ) ( m o d n ) s = k^{-1}(z + r\cdot d_A) (mod n) s=k1(z+rdA)(modn)
s − 1 = k ⋅ ( z + r ⋅ d A ) − 1 ( m o d n ) s^{-1} = k\cdot(z + r\cdot d_A)^{-1} (mod n) s1=k(z+rdA)1(modn)
代入得到 P = k ⋅ G P=k \cdot G P=kG

利用冲突的随机数恢复私钥

从上面的签名过程我们可以看到最关键的地方就在于随机数k,对于一个固定的椭圆曲线,一个确定的k就意味着一个确定的r,所以如果有两个相同的私钥签署的签名出现了相同的r就代表着在生成随机数时取到了相同的k,看到这里想必你也明白了我们题目的交易签名的问题出在哪了,这两笔交易的r值相同,代表在它们签名时使用的随机数k是相同的,而这就是我们恢复私钥的关键
我们不妨设这两个签名的 z z z s s s分别为 z 1 z_1 z1 z 2 z_2 z2 s 1 s_1 s1 s 2 s_2 s2
则有
s 1 − s 2 = k − 1 ( z 1 + d A ⋅ r ) − k − 1 ( z 2 + d A ⋅ r ) s_1-s_2= k ^ {-1}(z_1 + d_A \cdot r)-k ^ {-1}(z_2+ d_A \cdot r) s1s2=k1(z1+dAr)k1(z2+dAr)
= k − 1 ( z 1 − z 2 ) = k ^ {-1}(z_1 - z_2) =k1(z1z2)
那么 k = ( z 1 − z 2 ) ( s 1 − s 2 ) k = \frac {(z_1-z_2)}{(s_1-s_2)} k=(s1s2)(z1z2)
通过 k k k,可以计算出 d A = ( s ⋅ k − z ) / r d_A=(s \cdot k -z) /r dA=(skz)/r

P2PKH

p2pkh
PubkeyScript是一张记录了交易记录的指令列表,它控制了下一名使用者如何解锁已接收的比特币并传送。收款人会制造一个signature script,而该文件必须满足最后一个发送者创建的PubkeyScript的参数。
PubkeyScript的参数:

  1. 公钥哈希(Public Key Hash) (比特币地址)
  2. 电子签署(ScriptSig: (r,s)+pubkey)

ASM是汇编代码

  1. OP_PUSHBYTES_71指压入栈中一个71字节大小的数据
  2. nSequence用以记录该笔交易是否可以上链
  3. Previous output Script用以验证当前用于支付的比特币的来源
  4. ScriptPubKey是一个脚本,用以验证当前用户有能力使用这个UTXO中的比特币来支付,即证明身份
    OP_DUP复制栈顶数据
    OP_HASH160先后进行两种hash操作然后压入栈
    OP_PUSHBYTES_20将签名的hash值压入栈
    OP_EQUALVERIFY比较计算签名hash和刚压入栈的hash来验证有效性,有效返回1否则返回0
    OP_CHECKSIG检测栈顶的2个元素,pub key和signature是否能对应的上。对应的上,说明这个签名的私钥,和收款人的公钥可以对上。有资格花这笔钱
    OP_RETURN 用来当注释,携带一些信息
    Transaction hex则包含所有信息连接在一起

求解过程

提取r,s,z

脚本来源

# -*-coding:utf-8-*-
"""
@author: iceland
"""
import sys
import hashlib
import argparse
from urllib.request import urlopen

# # ==============================================================================
# parser = argparse.ArgumentParser(
#     description='This tool helps to get ECDSA Signature r,s,z values from Bitcoin rawtx or txid',
#     epilog='Enjoy the program! :)    Tips BTC: bc1q39meky2mn5qjq704zz0nnkl0v7kj4uz6r529at')
#
# parser.add_argument("-txid", help="txid of the transaction. Automatically fetch rawtx from given txid", action="store")
# parser.add_argument("-rawtx", help="Raw Transaction on the blockchain.", action="store")
#
# if len(sys.argv) == 1:
#     parser.print_help()
#     sys.exit(1)
# args = parser.parse_args()
# # ==============================================================================
#
# txid = args.txid if args.txid else ''
# rawtx = args.rawtx if args.rawtx else ''
#
# if rawtx == '' and txid == '':
#     print('One of the required option missing -rawtx or -txid');
#     sys.exit(1)


# ==============================================================================

def get_rs(sig):
    rlen = int(sig[2:4], 16)
    r = sig[4:4 + rlen * 2]
    #    slen = int(sig[6+rlen*2:8+rlen*2], 16)
    s = sig[8 + rlen * 2:]
    return r, s


def split_sig_pieces(script):
    sigLen = int(script[2:4], 16)
    sig = script[2 + 2:2 + sigLen * 2]
    r, s = get_rs(sig[4:])
    pubLen = int(script[4 + sigLen * 2:4 + sigLen * 2 + 2], 16)
    pub = script[4 + sigLen * 2 + 2:]
    assert (len(pub) == pubLen * 2)
    return r, s, pub


# Returns list of this list [first, sig, pub, rest] for each input
def parseTx(txn):
    if len(txn) < 130:
        print('[WARNING] rawtx most likely incorrect. Please check..')
        sys.exit(1)
    inp_list = []
    ver = txn[:8]
    if txn[8:12] == '0001':
        print('UnSupported Tx Input. Presence of Witness Data')
        sys.exit(1)
    inp_nu = int(txn[8:10], 16)

    first = txn[0:10]
    cur = 10
    for m in range(inp_nu):
        prv_out = txn[cur:cur + 64]
        var0 = txn[cur + 64:cur + 64 + 8]
        cur = cur + 64 + 8
        scriptLen = int(txn[cur:cur + 2], 16)
        script = txn[cur:2 + cur + 2 * scriptLen]  # 8b included
        r, s, pub = split_sig_pieces(script)
        seq = txn[2 + cur + 2 * scriptLen:10 + cur + 2 * scriptLen]
        inp_list.append([prv_out, var0, r, s, pub, seq])
        cur = 10 + cur + 2 * scriptLen
    rest = txn[cur:]
    return [first, inp_list, rest]


# ==============================================================================
def get_rawtx_from_blockchain(txid):
    try:
        htmlfile = urlopen("https://blockchain.info/rawtx/%s?format=hex" % txid, timeout=20)
    except:
        print('Unable to connect internet to fetch RawTx. Exiting..')
        sys.exit(1)
    else:
        res = htmlfile.read().decode('utf-8')
    return res


# =============================================================================

def getSignableTxn(parsed):
    res = []
    first, inp_list, rest = parsed
    tot = len(inp_list)
    for one in range(tot):
        e = first
        for i in range(tot):
            e += inp_list[i][0]  # prev_txid
            e += inp_list[i][1]  # var0
            if one == i:
                e += '1976a914' + HASH160(inp_list[one][4]) + '88ac'
            else:
                e += '00'
            e += inp_list[i][5]  # seq
        e += rest + "01000000"
        z = hashlib.sha256(hashlib.sha256(bytes.fromhex(e)).digest()).hexdigest()
        res.append([inp_list[one][2], inp_list[one][3], z, inp_list[one][4], e])
    return res


# ==============================================================================
def HASH160(pubk_hex):
    return hashlib.new('ripemd160', hashlib.sha256(bytes.fromhex(pubk_hex)).digest()).hexdigest()


# ==============================================================================

txn = '010000000153db4e56f159c0679818ef8ce814ce8fcaad12b854da7e582fb5f19266945f63000000006a47304402200e1e942f62d61cc25117d71bc2da4b523bd720dc7feec77551a0b152eb042cd7022030d7d78612b765dff96dd14fc5d723e06a8fa61b42a93410236273baf82f7f15012102572263bbac032e37cf96fe7664fb799f56353108c032807cc23ca557fb60b394ffffffff02d0070000000000001976a914b1c75a61c0461cd92c124e00ee275a600aa096b288ac0000000000000000056a0343544600000000'
# if rawtx == '':
#     rawtx = get_rawtx_from_blockchain(txid)

print('\nStarting Program...')

m = parseTx(txn)
e = getSignableTxn(m)

for i in range(len(e)):
    print('=' * 70,
          f'\n[Input Index #: {i}]\n     R: {e[i][0]}\n     S: {e[i][1]}\n     Z: {e[i][2]}\nPubKey: {e[i][3]}')

求dA

#-*-coding:utf-8-*-
r1 = 0x0e1e942f62d61cc25117d71bc2da4b523bd720dc7feec77551a0b152eb042cd7
s1 = 0x5611099541793c7681a9f8b48364d6e7088e16afe7b7b6244c52e94d28252a3b
z1 = 0x5ecd4154a2db20480d7715d6e47a772aaf596e11e6f16a4d58e9f0d260294660

r2 = 0x0e1e942f62d61cc25117d71bc2da4b523bd720dc7feec77551a0b152eb042cd7
s2 = 0x30d7d78612b765dff96dd14fc5d723e06a8fa61b42a93410236273baf82f7f15
z2 = 0x50f1c6205aab5f8dac7b505f91dfc437b1b13cd00f12a492570a040a27c38e25

assert r1 == r2
r = r1
def inverse_mod( a, m ):
    """Inverse of a mod m."""
    if a < 0 or m <= a: a = a % m
    c, d = a, m
    uc, vc, ud, vd = 1, 0, 0, 1
    while c != 0:
        q, c, d = divmod( d, c ) + ( c, )
        uc, vc, ud, vd = ud - q*uc, vd - q*vc, uc, vc

    assert d == 1
    if ud > 0: return ud
    else: return ud + m


def derivate_privkey(p, r, s1, s2, z1, z2):
    z = z1 - z2
    s = s1 - s2
    r_inv = inverse_mod(r, p)
    s_inv = inverse_mod(s, p)
    k = (z * s_inv) % p
    d = (r_inv * (s1 * k - z1)) % p
    return d, k

p  = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141

privatekey,k=derivate_privkey(p,r,s1,s2,z1,z2)

利用私钥解密AES

import base64
cipher = base64.b64decode(b"4w/VLHqPZi/epoOGvjoY9TZWhDtYpL3iLsUTyvzghJM=")
privatekey = 0xF41AA419CB6BD43F322D403F40728CE9784CD0B465F409322A76A3DF0A984A29
from Crypto.Cipher import AES
from Crypto.Util.number import *
key = long_to_bytes(privatekey)[0:16]
iv = long_to_bytes(privatekey)[16:]
aes = AES.new(key=key,iv=iv,mode=AES.MODE_CBC)
flag = aes.decrypt(cipher.encode())
print(flag)

参考链接

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/20370.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Ambari-2.7.7源码编译

0 说明 本文基于Ambari-2.7.7版本进行源码编译。所需的编译资料统一提供如下&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1F2D7zBGfKihxTBArnOilTw 提取码&#xff1a;8m17 1 前提条件 1.1 下载ambari源码包 wget https://github.com/apache/ambari/releases/t…

Linux:文本三剑客之sed编辑器

Linux&#xff1a;sed编辑器 一、sed1.1 sed编辑器1.2 sed编辑器的工作流程1.3 命令格式1.4常用选项1.5 常用操作1.6 实际应用 一、sed 1.1 sed编辑器 sed是一种流编辑器&#xff0c;流编辑器会在编辑器处理数据之前基于预先提供的一组规则来编辑数据流。sed编辑器可以根据命…

FE_Vue学习笔记 常用指令的学习【v-model filters v-text v-html v-cloak v-once v-pre 自定义指令】

1 收集表单数据 v-model 收集表单数据&#xff1a; 若&#xff1a;<input type"text">&#xff0c;则v-model收集的是value的值&#xff0c;用户输入的就是value值。 若&#xff1a;<input type"radio">&#xff0c;则v-modle收集的是value的…

浏览csdn博客自动隐藏侧边栏并只看目录

背景 CSDN 总算做了点好事&#xff0c;能够隐藏大部分无关信息&#xff0c;只看博客内容本身。具体如图&#xff0c;还在测试版 以我的一篇博客为例&#xff0c;原始界面&#xff0c;花里胡哨一堆 点击隐藏侧栏后的清爽版 点击只看目录后的清爽版 前提提要 安装油猴脚本&…

OLS样本估计量抽样分布模拟

OLS样本估计量抽样分布模拟 文章目录 OLS样本估计量抽样分布模拟1 OLS估计量分布2 R语言实现 1 OLS估计量分布 对于线性回归方程 Y β 0 β 1 X ε Y \beta_0\beta_1 X \varepsilon Yβ0​β1​Xε 利用普通最小二乘法(OLS&#xff09;估计上述方程参数使的假定(之一)是…

[译] Flutter 3.10 的新功能

[译] Flutter 3.10 的新功能 原文 https://medium.com/flutter/whats-new-in-flutter-3-10-b21db2c38c73 无缝的Web和移动端集成&#xff0c;Impeller稳定版的突破性图形性能&#xff0c;以及更多 欢迎使用Flutter 3.10&#xff01;我们非常期待展示我们令人惊叹的Flutter社区所…

示波器的数据处理怎么记录?

示波器的使用 - 记录和保存示波器测试结果 安泰测试为您分享如何记录示波器的数据。 "从您把示波器探头连接到器件的那一刻起&#xff0c;信号就开启了一次瞬间即可完成的重大旅程。它必须 跨过五个不同的“模块”&#xff0c;才能完成从器件到示波器&#xff0c;最后返回…

十五、Gateway网关

目录 Zuul网关和gateway网关的区别&#xff1a; Gateway路由配置 1、新建服务网关项目&#xff0c;并在项目pom文件中引入gateway网关依赖 2、在application.yml配置gateway 3、如果不用配置的方式配置gateway路由&#xff0c;还可以通过代码的形式配置 4、启动网关服务&…

Reed-Muller序列

Reed-Muller函数的由来 我们知道对于连续信号&#xff0c;时间和频率是对偶域(duality)&#xff0c;其中正弦函数是时移的特征函数&#xff08;where sinusoids are eigenfunctions of time shifts&#xff09;。而在汉明空间(Hamming space)中&#xff0c;there are discrete…

【软考|软件设计师】某计算机系统的CPU主频为2.8GHz

目录 题&#xff1a; CPI MIPS 题&#xff1a; 某计算机系统的CPU主频为2.8GHz。某应用程序包括3类指令&#xff0c;各类指令的CPI &#xff08;执行每条指令所需要的时钟周期&#xff09;及指令比例如下表所示。执行该应用程序时 的平均CPI为______&#xff1b; 运算速度…

ASP.NET Core 8 中身份验证的改进

ASP.NET Core 团队正在改进 .NET 8 中的身份验证、授权和身份管理(统称为“身份验证”)。新的 APIs 将使自定义用户登录和身份管理体验变得更加容易。新的端点将在没有外部依赖的单页应用程序(SPA)中启用基于令牌的身份验证和授权。我们还将改进我们的指引和文档&#xff0c;使…

基于SSM+JSP的人体健康信息管理系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

JMeter入门配置

目录 场景&#xff1a; 环境及工具 &#xff1a; JMeter中文配置&#xff1a; 配置登录接口&#xff1a; 配置响应结果&#xff1a; 配置json提取器 测试json提取器 配置Beanshell后置处理器&#xff1a; http请求右键-->添加---->后置处理器--->Beanshell后置处理…

第五章 面向对象-7.hashCode()和toString()

hashCode()和toString() hashCode() hashCoed 的特性&#xff1a; &#xff08;1&#xff09;HashCode的存在主要是用于查找的快捷性&#xff0c;如Hashtable&#xff0c;HashMap等&#xff0c;HashCode经常用于确定对象的存储地址&#xff1b; &#xff08;2&#xff09;如果…

MySQL基础(二十九)数据库的设计规范

1 范式 1.1 范式简介 在关系型数据库中&#xff0c;关于数据表设计的基本原则、规则就称为范式。可以理解为&#xff0c;一张数据表的设计结 构需要满足的某种设计标准的 级别 。要想设计一个结构合理的关系型数据库&#xff0c;必须满足一定的范式。 1.2 范式都包括哪些 目…

医院内导航及智能导医,医院导诊图怎么制作?

在大型综合性医院&#xff0c;由于专业分工精细&#xff0c;一个诊疗过程涉及的功能单元往往分布在不同的楼宇、不同楼层的不同位置&#xff0c;再加上多数患者对医院环境不熟悉&#xff0c;导致滞院的时间长、诊疗效率低、患者对服务的满意度下降。为解决这一问题&#xff0c;…

空中下载技术(OTA)电控信息安全

随着汽车电子控制系统功能复杂度和数据颗粒度呈阶梯式增加&#xff0c;其发展速度逐渐超越网络安全防护方法、技术和标准的发展&#xff0c;现阶段汽车电子正面临巨大的网络信息安全风险&#xff0c;对功能安全的潜在影响也仍在探索和解决中&#xff0c;信息安全问题已经成为影…

C++ 中到底是应该include .h文件还是应该include .cpp文件

在阅读一个较大的解决方案中&#xff0c;对于其他文件夹下的.h和.cpp文件&#xff0c;有时候#include“XXX.h”文件&#xff0c;有时候是#include“XXX.cpp”文件&#xff0c;而且二者还不能更换。下面就好好分析一下他们二者的区别。 测试 测试&#xff1a;XXX.h和XXX.cpp…

Linux内核(十四)Input 子系统详解 IV —— 配对的input设备与input事件处理器 input_register_handle

文章目录 input_handle结构体详解配对的input设备与input事件处理器实例input核心层对驱动层和事件层之间的框架建立流程图 本文章中与input子系统相关的结构体可参考input子系统结构体解析 input函数路径&#xff1a;drivers/input/input.c input_handle结构体详解 input_ha…

(转)雪花算法(SnowFlake)

简介 现在的服务基本是分布式、微服务形式的&#xff0c;而且大数据量也导致分库分表的产生&#xff0c;对于水平分表就需要保证表中 id 的全局唯一性。 对于 MySQL 而言&#xff0c;一个表中的主键 id 一般使用自增的方式&#xff0c;但是如果进行水平分表之后&#xff0c;多…
最新文章