111 lines
2.7 KiB
Python
111 lines
2.7 KiB
Python
|
"""
|
||
|
RFC 6979:
|
||
|
Deterministic Usage of the Digital Signature Algorithm (DSA) and
|
||
|
Elliptic Curve Digital Signature Algorithm (ECDSA)
|
||
|
|
||
|
http://tools.ietf.org/html/rfc6979
|
||
|
|
||
|
Many thanks to Coda Hale for his implementation in Go language:
|
||
|
https://github.com/codahale/rfc6979
|
||
|
"""
|
||
|
|
||
|
import hmac
|
||
|
from binascii import hexlify
|
||
|
from .util import number_to_string, number_to_string_crop, bit_length
|
||
|
from ._compat import hmac_compat
|
||
|
|
||
|
|
||
|
# bit_length was defined in this module previously so keep it for backwards
|
||
|
# compatibility, will need to deprecate and remove it later
|
||
|
__all__ = ["bit_length", "bits2int", "bits2octets", "generate_k"]
|
||
|
|
||
|
|
||
|
def bits2int(data, qlen):
|
||
|
x = int(hexlify(data), 16)
|
||
|
l = len(data) * 8
|
||
|
|
||
|
if l > qlen:
|
||
|
return x >> (l - qlen)
|
||
|
return x
|
||
|
|
||
|
|
||
|
def bits2octets(data, order):
|
||
|
z1 = bits2int(data, bit_length(order))
|
||
|
z2 = z1 - order
|
||
|
|
||
|
if z2 < 0:
|
||
|
z2 = z1
|
||
|
|
||
|
return number_to_string_crop(z2, order)
|
||
|
|
||
|
|
||
|
# https://tools.ietf.org/html/rfc6979#section-3.2
|
||
|
def generate_k(order, secexp, hash_func, data, retry_gen=0, extra_entropy=b""):
|
||
|
"""
|
||
|
order - order of the DSA generator used in the signature
|
||
|
secexp - secure exponent (private key) in numeric form
|
||
|
hash_func - reference to the same hash function used for generating
|
||
|
hash
|
||
|
data - hash in binary form of the signing data
|
||
|
retry_gen - int - how many good 'k' values to skip before returning
|
||
|
extra_entropy - extra added data in binary form as per section-3.6 of
|
||
|
rfc6979
|
||
|
"""
|
||
|
|
||
|
qlen = bit_length(order)
|
||
|
holen = hash_func().digest_size
|
||
|
rolen = (qlen + 7) // 8
|
||
|
bx = (
|
||
|
hmac_compat(number_to_string(secexp, order)),
|
||
|
hmac_compat(bits2octets(data, order)),
|
||
|
hmac_compat(extra_entropy),
|
||
|
)
|
||
|
|
||
|
# Step B
|
||
|
v = b"\x01" * holen
|
||
|
|
||
|
# Step C
|
||
|
k = b"\x00" * holen
|
||
|
|
||
|
# Step D
|
||
|
|
||
|
k = hmac.new(k, digestmod=hash_func)
|
||
|
k.update(v + b"\x00")
|
||
|
for i in bx:
|
||
|
k.update(i)
|
||
|
k = k.digest()
|
||
|
|
||
|
# Step E
|
||
|
v = hmac.new(k, v, hash_func).digest()
|
||
|
|
||
|
# Step F
|
||
|
k = hmac.new(k, digestmod=hash_func)
|
||
|
k.update(v + b"\x01")
|
||
|
for i in bx:
|
||
|
k.update(i)
|
||
|
k = k.digest()
|
||
|
|
||
|
# Step G
|
||
|
v = hmac.new(k, v, hash_func).digest()
|
||
|
|
||
|
# Step H
|
||
|
while True:
|
||
|
# Step H1
|
||
|
t = b""
|
||
|
|
||
|
# Step H2
|
||
|
while len(t) < rolen:
|
||
|
v = hmac.new(k, v, hash_func).digest()
|
||
|
t += v
|
||
|
|
||
|
# Step H3
|
||
|
secret = bits2int(t, qlen)
|
||
|
|
||
|
if 1 <= secret < order:
|
||
|
if retry_gen <= 0:
|
||
|
return secret
|
||
|
retry_gen -= 1
|
||
|
|
||
|
k = hmac.new(k, v + b"\x00", hash_func).digest()
|
||
|
v = hmac.new(k, v, hash_func).digest()
|