2015-12-24 16 views
6

Muszę podpisać hash 256 bitów za pomocą ECDSA używając klucza prywatnego 256 bitów, tak jak robi bitcoin, i dochodzę do desperacji z powodu braku dokumentacji ecdsa w python.Jak podpisać i zweryfikować podpis za pomocą ecdsa w pythonie

Znalazłem wiele kodów w Internecie, ale nie było nic tak łatwego jak tylko ecdsa.sign(msg, privkey) lub coś podobnego, wszystko, co znalazłem, to dużo kodu matematycznych rzeczy, których nie rozumiem, ale mimo to używają biblioteki ecdsa (Nie wiem, dlaczego nie dodaliby funkcji podpisywania w bibliotece, która będzie używana do podpisywania danych, zamiast tego strona kodu jest potrzebna podczas korzystania z biblioteki?).

Jest to najlepszy kod znalazłem do tej pory:

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() 

Ale ja po prostu nie można ufać kod tak, bo nie mam pojęcia, co robi. Również komentarze w ecdsa_sign mówią, że zwraca podpis podając wartość, tajny wykładnik, i nonce. Mówi, że bardzo ważne jest, aby mieć nonce, ale nie mogę po prostu dowiedzieć się, gdzie jest ten nonce.

Czy istnieje prosty, jednokierunkowy sposób podpisywania i weryfikacji podpisów ECDSA przy użyciu dowolnej zaufanej biblioteki w pythonie w systemie Windows?

+0

nie możesz go podpisać przy pomocy openssl? –

+0

jakie są zalety używania openssl over ecdsa? – Jorky10

+0

Wyobrażam sobie, że biblioteka ecdsa używa openssl, więc nie ma różnicy, będziesz mieć dostęp do wszystkiego, czego potrzebujesz, używając openssl https://www.openssl.org/docs/manmaster/crypto/ecdsa.html https://www.guyrutenberg .com/2013/12/28/tworzenie-self-signed-ecdsa-ssl-certificate-using-openssl/ –

Odpowiedz

5

Można spróbować przy użyciu pakietu ECDSA Pythonie, używając Python3:

pip3 install ecdsa 

Zastosowanie:

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 

Aby zweryfikować istniejący podpis z kluczem publicznym:

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 

pakiet jest kompatybilny z Python 2 oraz

EDYCJA: odpowiedź wcześniej wymagała zaimportowania SECP256k1, która została naprawiona. Dzięki @ chengcheng-zhang za wskazanie go

+0

Możesz także użyć sign_digest i verify_digest dla strawionych danych, na przykład, jeśli przekazujesz mieszanie sha256 w postaci binarnej. –

+0

Czy istnieje sposób na zmniejszenie liczby kluczy? Na przykład, zdefiniuj ich maksymalny rozmiar? –

+0

@Nuclear_Man_D Uważam, że rozmiar klucza jest stały. – k26dr

Powiązane problemy