2015-12-24 51 views
6

Tôi cần ký một mã băm 256 bit với ECDSA bằng khóa riêng 256 bit, giống như bitcoin, và tôi đang tuyệt vọng vì thiếu tài liệu về ecdsa trong python.Cách ký và xác minh chữ ký bằng ecdsa trong python

Tôi tìm thấy rất nhiều mã trên internet, nhưng không có gì dễ dàng như chỉ ecdsa.sign(msg, privkey) hoặc tương tự, mọi thứ tôi tìm thấy là rất nhiều mã toán học mà tôi không hiểu, nhưng họ sử dụng thư viện ecdsa (Tôi không biết tại sao họ sẽ không thêm chức năng ký tên vào thư viện sẽ được sử dụng để ký công cụ, thay vào đó một trang mã là cần thiết khi sử dụng thư viện?).

Đây là mã tốt nhất mà tôi tìm thấy cho đến nay:

def ecdsa_sign(val, secret_exponent): 
    """Return a signature for the provided hash, using the provided 
    random nonce. It is absolutely vital that random_k be an unpredictable 
    number in the range [1, self.public_key.point.order()-1]. If 
    an attacker can guess random_k, he can compute our private key from a 
    single signature. Also, if an attacker knows a few high-order 
    bits (or a few low-order bits) of random_k, he can compute our private 
    key from many signatures. The generation of nonces with adequate 
    cryptographic strength is very difficult and far beyond the scope 
    of this comment. 

    May raise RuntimeError, in which case retrying with a new 
    random value k is in order. 
    """ 
    G = ecdsa.SECP256k1 
    n = G.order() 
    k = deterministic_generate_k(n, secret_exponent, val) 
    p1 = k * G 
    r = p1.x() 
    if r == 0: raise RuntimeError("amazingly unlucky random number r") 
    s = (ecdsa.numbertheory.inverse_mod(k, n) * (val + (secret_exponent * r) % n)) % n 
    if s == 0: raise RuntimeError("amazingly unlucky random number s") 

    return signature_to_der(r, s) 

def deterministic_generate_k(generator_order, secret_exponent, val, hash_f=hashlib.sha256): 
    """ 
    Generate K value according to https://tools.ietf.org/html/rfc6979 
    """ 
    n = generator_order 
    order_size = (bit_length(n) + 7) // 8 
    hash_size = hash_f().digest_size 
    v = b'\x01' * hash_size 
    k = b'\x00' * hash_size 
    priv = intbytes.to_bytes(secret_exponent, length=order_size) 
    shift = 8 * hash_size - bit_length(n) 
    if shift > 0: 
     val >>= shift 
    if val > n: 
     val -= n 
    h1 = intbytes.to_bytes(val, length=order_size) 
    k = hmac.new(k, v + b'\x00' + priv + h1, hash_f).digest() 
    v = hmac.new(k, v, hash_f).digest() 
    k = hmac.new(k, v + b'\x01' + priv + h1, hash_f).digest() 
    v = hmac.new(k, v, hash_f).digest() 

    while 1: 
     t = bytearray() 

     while len(t) < order_size: 
      v = hmac.new(k, v, hash_f).digest() 
      t.extend(v) 

     k1 = intbytes.from_bytes(bytes(t)) 

     k1 >>= (len(t)*8 - bit_length(n)) 
     if k1 >= 1 and k1 < n: 
      return k1 

     k = hmac.new(k, v + b'\x00', hash_f).digest() 
     v = hmac.new(k, v, hash_f).digest() 

Nhưng tôi chỉ không thể tin tưởng một mã như vậy bởi vì tôi không có ý tưởng những gì nó làm. Ngoài ra, các nhận xét trong ecdsa_sign cho biết trả về chữ ký cho giá trị, số mũ bí mật, và số không. Nó nói nó rất quan trọng để có một nonce, nhưng tôi chỉ không thể tìm ra nơi mà nonce là.

Có cách nào đơn giản, một dòng để ký và xác minh chữ ký ECDSA bằng bất kỳ thư viện đáng tin cậy nào trong python trên cửa sổ không?

+0

bạn không thể ký tên bằng cách sử dụng openssl? –

+0

các ưu điểm của việc sử dụng openssl trên ecdsa là gì? – Jorky10

+0

Tôi tưởng tượng ecdsa lib sử dụng openssl để không có sự khác biệt, bạn sẽ có quyền truy cập vào bất cứ điều gì bạn cần bằng cách sử dụng openssl https://www.openssl.org/docs/manmaster/crypto/ecdsa.html https: //www.guyrutenberg .com/2013/12/28/create-self-signed-ecdsa-ssl-certificate-using-openssl/ –

Trả lời

5

Bạn có thể thử bằng cách sử dụng gói ECDSA python, sử dụng Python3:

pip3 install ecdsa 

Cách sử dụng:

from ecdsa import SigningKey 

# SECP256k1 is the Bitcoin elliptic curve 
sk = SigningKey.generate(curve=ecdsa.SECP256k1) 
vk = sk.get_verifying_key() 
sig = sk.sign(b"message") 
vk.verify(sig, b"message") # True 

Để xác minh chữ ký hiện tại với một khóa công khai:

from ecdsa import VerifyingKey 

message = b"message" 
public_key = '98cedbb266d9fc38e41a169362708e0509e06b3040a5dfff6e08196f8d9e49cebfb4f4cb12aa7ac34b19f3b29a17f4e5464873f151fd699c2524e0b7843eb383' 
sig = '740894121e1c7f33b174153a7349f6899d0a1d2730e9cc59f674921d8aef73532f63edb9c5dba4877074a937448a37c5c485e0d53419297967e95e9b1bef630d' 

vk = VerifyingKey.from_string(bytes.fromhex(public_key), curve=ecdsa.SECP256k1) 
vk.verify(bytes.fromhex(sig), message) # True 

Các gói tương thích với Python 2 cũng như

EDIT: câu trả lời trước đó cần nhập SECP256k1, đã được sửa. Nhờ @ chengcheng-zhang đã chỉ ra số

+0

Bạn cũng có thể sử dụng sign_digest và verify_digest cho dữ liệu được phân tích, ví dụ, nếu bạn đang chuyển băm sha256 trong nhị phân. –

+0

Có cách nào để làm cho các phím nhỏ hơn không? Ví dụ, xác định kích thước tối đa của chúng? –

+0

@Nuclear_Man_D Tôi tin rằng kích thước khóa là cố định. – k26dr

Các vấn đề liên quan