mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 01:18:00 +00:00
dsa_nonce_recover.py: feature to talk to an agent.
This commit is contained in:
parent
a8601a72a9
commit
d1a2d215b8
147
test/dsa_nonce_recover.py
Normal file → Executable file
147
test/dsa_nonce_recover.py
Normal file → Executable file
@ -1,21 +1,26 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Recover the nonce value k used in integer DSA or NIST-style ECDSA,
|
||||
# starting from the private key and the signature.
|
||||
#
|
||||
# _Without_ the private key, recovering the nonce is equivalent to
|
||||
# recovering the private key itself. But with it, it's a trivial piece
|
||||
# of modular arithmetic.
|
||||
#
|
||||
# This script generates a load of test signatures from various keys,
|
||||
# recovers the nonces used, and prints them. This allows an eyeball
|
||||
# check of whether they're evenly distributed.
|
||||
'''
|
||||
Recover the nonce value k used in integer DSA or NIST-style ECDSA,
|
||||
starting from the private key and the signature.
|
||||
|
||||
_Without_ the private key, recovering the nonce is equivalent to
|
||||
recovering the private key itself. But with it, it's a trivial piece
|
||||
of modular arithmetic.
|
||||
|
||||
This script generates a load of test signatures from various keys,
|
||||
recovers the nonces used, and prints them. This allows an eyeball
|
||||
check of whether they're evenly distributed.
|
||||
'''
|
||||
|
||||
import argparse
|
||||
|
||||
from base64 import b64decode as b64
|
||||
|
||||
from eccref import *
|
||||
from testcrypt import *
|
||||
from ssh import *
|
||||
from agenttest import agent_query
|
||||
|
||||
def recover_nonce(order, hashalg, privint, transform_hash, r, s, message):
|
||||
w = int(mp_invert(s, order))
|
||||
@ -44,40 +49,94 @@ def ecdsa_decode_sig(signature):
|
||||
s = int(mp_from_bytes_be(s))
|
||||
return r, s
|
||||
|
||||
def test(privkey, decode_sig, transform_hash, order, hashalg, algid, obits):
|
||||
print("----", algid)
|
||||
print("k=0x{{:0{}b}}".format(obits).format(order))
|
||||
privblob = ssh_key_private_blob(privkey)
|
||||
privint = int(mp_from_bytes_be(ssh_decode_string(privblob)))
|
||||
for message in (f"msg{i}".encode('ASCII') for i in range(100)):
|
||||
signature = ssh_key_sign(privkey, message, 0)
|
||||
r, s = decode_sig(signature)
|
||||
nonce = recover_nonce(order, hashalg, privint, transform_hash,
|
||||
r, s, message)
|
||||
print("k=0x{{:0{}b}}".format(obits).format(nonce))
|
||||
class SignerBase:
|
||||
def test(self, privkey, decode_sig, transform_hash, order, hashalg,
|
||||
algid, obits):
|
||||
print("----", algid)
|
||||
print("k=0x{{:0{}b}}".format(obits).format(order))
|
||||
privblob = ssh_key_private_blob(privkey)
|
||||
privint = int(mp_from_bytes_be(ssh_decode_string(privblob)))
|
||||
self.setup_key(privkey)
|
||||
for message in (f"msg{i}".encode('ASCII') for i in range(100)):
|
||||
signature = self.sign(privkey, message)
|
||||
r, s = decode_sig(signature)
|
||||
nonce = recover_nonce(order, hashalg, privint, transform_hash,
|
||||
r, s, message)
|
||||
print("k=0x{{:0{}b}}".format(obits).format(nonce))
|
||||
self.cleanup_key(privkey)
|
||||
|
||||
def test_dsa(pubblob, privblob):
|
||||
privkey = ssh_key_new_priv('dsa', pubblob, privblob)
|
||||
_, buf = ssh_decode_string(pubblob, return_rest=True)
|
||||
p, buf = ssh_decode_string(buf, return_rest=True)
|
||||
q, buf = ssh_decode_string(buf, return_rest=True)
|
||||
g, buf = ssh_decode_string(buf, return_rest=True)
|
||||
p = int(mp_from_bytes_be(p))
|
||||
q = int(mp_from_bytes_be(q))
|
||||
g = int(mp_from_bytes_be(g))
|
||||
transform_hash = lambda h: h
|
||||
test(privkey, dsa_decode_sig, transform_hash, q, 'sha1', 'dsa', 160)
|
||||
def test_dsa(self, pubblob, privblob):
|
||||
privkey = ssh_key_new_priv('dsa', pubblob, privblob)
|
||||
_, buf = ssh_decode_string(pubblob, return_rest=True)
|
||||
p, buf = ssh_decode_string(buf, return_rest=True)
|
||||
q, buf = ssh_decode_string(buf, return_rest=True)
|
||||
g, buf = ssh_decode_string(buf, return_rest=True)
|
||||
p = int(mp_from_bytes_be(p))
|
||||
q = int(mp_from_bytes_be(q))
|
||||
g = int(mp_from_bytes_be(g))
|
||||
transform_hash = lambda h: h
|
||||
self.test(privkey, dsa_decode_sig, transform_hash, q, 'sha1', 'dsa',
|
||||
160)
|
||||
|
||||
def test_ecdsa(algid, curve, hashalg, pubblob, privblob):
|
||||
privkey = ssh_key_new_priv(algid, pubblob, privblob)
|
||||
obits = int(mp_get_nbits(curve.G_order))
|
||||
def transform_hash(z):
|
||||
shift = max(0, mp_get_nbits(z) - obits)
|
||||
return mp_rshift_safe(z, shift)
|
||||
test(privkey, ecdsa_decode_sig, transform_hash, curve.G_order, hashalg,
|
||||
algid, obits)
|
||||
def test_ecdsa(self, algid, curve, hashalg, pubblob, privblob):
|
||||
privkey = ssh_key_new_priv(algid, pubblob, privblob)
|
||||
obits = int(mp_get_nbits(curve.G_order))
|
||||
def transform_hash(z):
|
||||
shift = max(0, mp_get_nbits(z) - obits)
|
||||
return mp_rshift_safe(z, shift)
|
||||
self.test(privkey, ecdsa_decode_sig, transform_hash, curve.G_order,
|
||||
hashalg, algid, obits)
|
||||
|
||||
test_dsa(b64('AAAAB3NzaC1kc3MAAABhAJyWZzjVddGdyc5JPu/WPrC07vKRAmlqO6TUi49ah96iRcM7/D1aRMVAdYBepQ2mf1fsQTmvoC9KgQa79nN3kHhz0voQBKOuKI1ZAodfVOgpP4xmcXgjaA73Vjz22n4newAAABUA6l7/vIveaiA33YYv+SKcKLQaA8cAAABgbErc8QLw/WDz7mhVRZrU+9x3Tfs68j3eW+B/d7Rz1ZCqMYDk7r/F8dlBdQlYhpQvhuSBgzoFa0+qPvSSxPmutgb94wNqhHlVIUb9ZOJNloNr2lXiPP//Wu51TxXAEvAAAAAAYQCcQ9mufXtZa5RyfwT4NuLivdsidP4HRoLXdlnppfFAbNdbhxE0Us8WZt+a/443bwKnYxgif8dgxv5UROnWTngWu0jbJHpaDcTc9lRyTeSUiZZK312s/Sl7qDk3/Du7RUI='), b64('AAAAFGx3ft7G8AQzFsjhle7PWardUXh3'))
|
||||
test_ecdsa('p256', p256, 'sha256', b64('AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHkYQ0sQoq5LbJI1VMWhw3bV43TSYi3WVpqIgKcBKK91TcFFlAMZgceOHQ0xAFYcSczIttLvFu+xkcLXrRd4N7Q='), b64('AAAAIQCV/1VqiCsHZm/n+bq7lHEHlyy7KFgZBEbzqYaWtbx48Q=='))
|
||||
test_ecdsa('p384', p384, 'sha384', b64('AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBMYK8PUtfAlJwKaBTIGEuCzH0vqOMa4UbcjrBbTbkGVSUnfo+nuC80NCdj9JJMs1jvfF8GzKLc5z8H3nZyM741/BUFjV7rEHsQFDek4KyWvKkEgKiTlZid19VukNo1q2Hg=='), b64('AAAAMGsfTmdB4zHdbiQ2euTSdzM6UKEOnrVjMAWwHEYvmG5qUOcBnn62fJDRJy67L+QGdg=='))
|
||||
test_ecdsa('p521', p521, 'sha512', b64('AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAFrGthlKM152vu2Ghk+R7iO9/M6e+hTehNZ6+FBwof4HPkPB2/HHXj5+w5ynWyUrWiX5TI2riuJEIrJErcRH5LglADnJDX2w4yrKZ+wDHSz9lwh9p2F+B5R952es6gX3RJRkGA+qhKpKup8gKx78RMbleX8wgRtIu+4YMUnKb1edREiRg=='), b64('AAAAQgFh7VNJFUljWhhyAEiL0z+UPs/QggcMTd3Vv2aKDeBdCRl5di8r+BMm39L7bRzxRMEtW5NSKlDtE8MFEGdIE9khsw=='))
|
||||
class TestcryptSigner(SignerBase):
|
||||
def setup_key(self, key):
|
||||
pass
|
||||
def cleanup_key(self, key):
|
||||
pass
|
||||
def sign(self, key, message):
|
||||
return ssh_key_sign(key, message, 0)
|
||||
|
||||
class AgentSigner(SignerBase):
|
||||
def setup_key(self, key):
|
||||
alg = ssh_decode_string(key.public_blob())
|
||||
msg = (ssh_byte(SSH2_AGENTC_ADD_IDENTITY) +
|
||||
ssh_string(alg) +
|
||||
key.openssh_blob() +
|
||||
ssh_string(b"dsa_nonce_recover test key"))
|
||||
result = agent_query(msg)
|
||||
assert result == ssh_byte(SSH_AGENT_SUCCESS)
|
||||
|
||||
def cleanup_key(self, key):
|
||||
msg = (ssh_byte(SSH2_AGENTC_REMOVE_IDENTITY) +
|
||||
ssh_string(key.public_blob()))
|
||||
result = agent_query(msg)
|
||||
assert result == ssh_byte(SSH_AGENT_SUCCESS)
|
||||
|
||||
def sign(self, key, message):
|
||||
msg = (ssh_byte(SSH2_AGENTC_SIGN_REQUEST) +
|
||||
ssh_string(key.public_blob()) +
|
||||
ssh_string(message))
|
||||
rsp = agent_query(msg)
|
||||
t, rsp = ssh_decode_byte(rsp, True)
|
||||
assert t == SSH2_AGENT_SIGN_RESPONSE
|
||||
sig, rsp = ssh_decode_string(rsp, True)
|
||||
assert len(rsp) == 0
|
||||
return sig
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description=__doc__,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
parser.add_argument("--agent", action="store_true",
|
||||
help="Test an SSH agent instead of testcrypt. "
|
||||
"(Still needs testcrypt.)")
|
||||
args = parser.parse_args()
|
||||
|
||||
signer = AgentSigner() if args.agent else TestcryptSigner()
|
||||
|
||||
signer.test_dsa(b64('AAAAB3NzaC1kc3MAAABhAJyWZzjVddGdyc5JPu/WPrC07vKRAmlqO6TUi49ah96iRcM7/D1aRMVAdYBepQ2mf1fsQTmvoC9KgQa79nN3kHhz0voQBKOuKI1ZAodfVOgpP4xmcXgjaA73Vjz22n4newAAABUA6l7/vIveaiA33YYv+SKcKLQaA8cAAABgbErc8QLw/WDz7mhVRZrU+9x3Tfs68j3eW+B/d7Rz1ZCqMYDk7r/F8dlBdQlYhpQvhuSBgzoFa0+qPvSSxPmutgb94wNqhHlVIUb9ZOJNloNr2lXiPP//Wu51TxXAEvAAAAAAYQCcQ9mufXtZa5RyfwT4NuLivdsidP4HRoLXdlnppfFAbNdbhxE0Us8WZt+a/443bwKnYxgif8dgxv5UROnWTngWu0jbJHpaDcTc9lRyTeSUiZZK312s/Sl7qDk3/Du7RUI='), b64('AAAAFGx3ft7G8AQzFsjhle7PWardUXh3'))
|
||||
signer.test_ecdsa('p256', p256, 'sha256', b64('AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHkYQ0sQoq5LbJI1VMWhw3bV43TSYi3WVpqIgKcBKK91TcFFlAMZgceOHQ0xAFYcSczIttLvFu+xkcLXrRd4N7Q='), b64('AAAAIQCV/1VqiCsHZm/n+bq7lHEHlyy7KFgZBEbzqYaWtbx48Q=='))
|
||||
signer.test_ecdsa('p384', p384, 'sha384', b64('AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBMYK8PUtfAlJwKaBTIGEuCzH0vqOMa4UbcjrBbTbkGVSUnfo+nuC80NCdj9JJMs1jvfF8GzKLc5z8H3nZyM741/BUFjV7rEHsQFDek4KyWvKkEgKiTlZid19VukNo1q2Hg=='), b64('AAAAMGsfTmdB4zHdbiQ2euTSdzM6UKEOnrVjMAWwHEYvmG5qUOcBnn62fJDRJy67L+QGdg=='))
|
||||
signer.test_ecdsa('p521', p521, 'sha512', b64('AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAFrGthlKM152vu2Ghk+R7iO9/M6e+hTehNZ6+FBwof4HPkPB2/HHXj5+w5ynWyUrWiX5TI2riuJEIrJErcRH5LglADnJDX2w4yrKZ+wDHSz9lwh9p2F+B5R952es6gX3RJRkGA+qhKpKup8gKx78RMbleX8wgRtIu+4YMUnKb1edREiRg=='), b64('AAAAQgFh7VNJFUljWhhyAEiL0z+UPs/QggcMTd3Vv2aKDeBdCRl5di8r+BMm39L7bRzxRMEtW5NSKlDtE8MFEGdIE9khsw=='))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
Loading…
Reference in New Issue
Block a user