- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在尝试通过关注 this guide 来学习如何创建比特币地址.如果向下滚动,第一步,即第 0 步,是拥有一个 256 位(64 十六进制)长的 ECDSA key 。我研究了 Python Cryptography 并使用下面的代码来测试生成 key ,但保存的 key 始终是一个长的(180 个字符)base 64 字符串。
我已尝试阅读文档并查看我在 Github 上调用的函数,但我看不到在哪里可以指定 key 的长度。在 this file 的第 216 行,它表示 secp256k1 的 key 大小默认为 256 位。这是否意味着我导出错误?
或者,我考虑过在 secp256k1,( 0x1
到 0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C 范围内生成一个随机的十六进制字符串,长度为 64 个字符D036 4140
),但我看不到在哪里可以从字符串或十六进制值创建私钥实例
gentest.py
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.serialization import load_pem_private_key
def gen_key():
private_key = ec.generate_private_key(
ec.SECP256K1(), default_backend()
)
return private_key
def save_key(pk, filename):
pem = pk.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
)
with open(filename, 'wb') as pem_out:
pem_out.write(pem)
def load_key(filename):
with open(filename, 'rb') as pem_in:
pemlines = pem_in.read()
private_key = load_pem_private_key(pemlines, None, default_backend())
return private_key
if __name__ == '__main__':
pk = gen_key()
filename = 'privkey.pem'
save_key(pk, filename)
pk2 = load_key(filename)
privkey.pem
-----BEGIN PRIVATE KEY-----
MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgQGh8om7IuKSTW637ZQug
SZQHUTv/yQzmM+KxGi1bg0ehRANCAATALLpDeKtfHxEnrgazJUu2z2/esSfzF5bj
Z4B/IBBB9uYHyMtjY8hS926bpXiWql7y7MMZXDSDD/zYWELuJZ1U
-----END PRIVATE KEY-----
最佳答案
如果您没有不透明 私钥(我认为这涉及专业硬件,所以不太可能),您可以通过key.private_numbers()
method 访问私有(private)号码信息。私钥对象的,此时您可以将值本身作为整数访问; .private_numbers()
方法生成一个 EllipticCurvePrivateNumbers
带有 .private_value
attribute 的对象,一个 Python int
。使用 format()
将该值格式化为 64 个字符的零填充十六进制:
>>> key = gen_key()
>>> key.private_numbers()
<cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateNumbers object at 0x110a6b828>
>>> key.private_numbers().private_value
1704732612341385685752055250212403073347894734334856205449544619169914419683
>>> format(key.private_numbers().private_value, '064x')
'03c4d82ee8e4c9d245f5a5ceae513569fb5693a0c3cca223b198c6944521f9e3'
或者使用 int.to_bytes()
将其编码为字节按大端或小端顺序(整数十六进制输出按大端顺序):
>>> key.private_numbers().private_value.to_bytes(32, 'big')
b'\x03\xc4\xd8.\xe8\xe4\xc9\xd2E\xf5\xa5\xce\xaeQ5i\xfbV\x93\xa0\xc3\xcc\xa2#\xb1\x98\xc6\x94E!\xf9\xe3'
>>> key.private_numbers().private_value.to_bytes(32, 'big').hex()
'03c4d82ee8e4c9d245f5a5ceae513569fb5693a0c3cca223b198c6944521f9e3'
所有这一切都有点令人费解,因为操作 cryptography
模块通常不需要它,该模块通过数据结构与 OpenSSL 或其他密码学后端一起工作,这些数据结构将这些信息保存在库友好的环境中,而不是 Python-友好的格式。
是的,您生成的 key 长 256 位,您可以通过查看私钥的 .key_size
属性来验证这一点:
>>> key.key_size
256
DER 格式可能是另一条路径,因为那是机器可读的信息。传统的 OpenSSL 格式使得从 X.690 ASN.1 structure 中获取信息相对容易。手动,无需安装 ASN.1 解析器,但这并不是万无一失的。您将查找 04 20
字节序列(4 是一个八位字节字符串,20 十六进制表示它的长度为 32 个字节), 该值将是第一个整数的序列;这意味着私钥将始终从第 8 个字节开始:
der_bytes = key.private_bytes(
encoding=serialization.Encoding.DER,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption())
assert der_bytes[5:7] == b'\x04\x20'
key_bytes = der_bytes[7:39]
不过,我不能 100% 确定这些断言是否成立,只是访问私有(private)号码要简单得多。
关于python - 如何在 Python 密码学中为 ECDSA (secp256k1) 生成较短的私钥,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52236189/
我是一名优秀的程序员,十分优秀!