From c299b102ee410261eb212277b16fcadcf1c6d454 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sat, 20 Feb 2021 00:30:27 +0100 Subject: [PATCH] recover_pk: flake8 --- tools/recover_pk.py | 112 +++++++++++++++++++++++--------------------- 1 file changed, 59 insertions(+), 53 deletions(-) diff --git a/tools/recover_pk.py b/tools/recover_pk.py index a268181f9..0310b4750 100755 --- a/tools/recover_pk.py +++ b/tools/recover_pk.py @@ -4,6 +4,7 @@ import binascii import sys +import hashlib debug = False @@ -15,9 +16,11 @@ debug = False # code snippets we needed: ####################################################################### # code snippets from JacobianCurve: -# This code is public domain. Everyone has the right to do whatever they want with it for any purpose. +# This code is public domain. Everyone has the right to do whatever +# they want with it for any purpose. # Copyright (c) 2013 Vitalik Buterin + class JacobianCurve: def __init__(self, p, n, a, b, g): self.p = p @@ -27,11 +30,9 @@ class JacobianCurve: self.g = g self.n_length = len(bin(self.n).replace("0b", "")) - def to_jacobian(self, p): return p[0], p[1], 1 - def jacobian_double(self, p): if not p[1]: return 0, 0, 0 @@ -43,7 +44,6 @@ class JacobianCurve: nz = (2 * p[1] * p[2]) % self.p return nx, ny, nz - def jacobian_add(self, p, q): if not p[1]: return q @@ -67,12 +67,10 @@ class JacobianCurve: nz = (h * p[2] * q[2]) % self.p return (nx, ny, nz) - def from_jacobian(self, p): z = inverse(p[2], self.p) return (p[0] * z ** 2) % self.p, (p[1] * z ** 3) % self.p - def jacobian_shamir(self, a, n, b, m): ab = self.jacobian_add(a, b) if n < 0 or n >= self.n: @@ -97,17 +95,15 @@ class JacobianCurve: return res def fast_shamir(self, a, n, b, m): - return self.from_jacobian(self.jacobian_shamir(self.to_jacobian(a), n, self.to_jacobian(b), m)) + return self.from_jacobian( + self.jacobian_shamir( + self.to_jacobian(a), n, self.to_jacobian(b), m)) ####################################################################### # code snippets from sslcrypto # MIT License # Copyright (c) 2019 Ivan Machugovskiy -import hmac -import os -import hashlib -import struct def int_to_bytes(raw, length): data = [] @@ -123,6 +119,7 @@ def bytes_to_int(data): raw = raw * 256 + byte return raw + def legendre(a, p): res = pow(a, (p - 1) // 2, p) if res == p - 1: @@ -130,6 +127,7 @@ def legendre(a, p): else: return res + def inverse(a, n): if a == 0: return 0 @@ -141,6 +139,7 @@ def inverse(a, n): lm, low, hm, high = nm, new, lm, low return lm % n + def square_root_mod_prime(n, p): if n == 0: return 0 @@ -186,8 +185,9 @@ def square_root_mod_prime(n, p): r = r * b % p return r -# name: (nid, p, n, a, b, (Gx, Gy)), + CURVES = { + # name: (nid, p, n, a, b, (Gx, Gy)), "secp128r1": ( 706, 0xFFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF, @@ -199,7 +199,6 @@ CURVES = { 0xCF5AC8395BAFEB13C02DA292DDED7A83 ) ), - # ! h=4, how to handle that? "secp128r2": ( 707, 0xFFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF, @@ -305,13 +304,14 @@ CURVES = { ) } + def get_curve(name): if name not in CURVES: raise ValueError("Unknown curve {}".format(name)) nid, p, n, a, b, g = CURVES[name] - params = {"p": p, "n": n, "a": a, "b": b, "g": g} return EllipticCurve(nid, p, n, a, b, g) + class EllipticCurve: def __init__(self, nid, p, n, a, b, g): self.p, self.n, self.a, self.b, self.g = p, n, a, b, g @@ -319,15 +319,12 @@ class EllipticCurve: self.public_key_length = (len(bin(p).replace("0b", "")) + 7) // 8 self.order_bitlength = len(bin(n).replace("0b", "")) - def _int_to_bytes(self, raw, len=None): return int_to_bytes(raw, len or self.public_key_length) - def _subject_to_int(self, subject): return bytes_to_int(subject[:(self.order_bitlength + 7) // 8]) - def recover(self, signature, data, hash="sha256"): # Sanity check: is this signature recoverable? if len(signature) != 1 + 2 * self.public_key_length: @@ -395,24 +392,26 @@ class EllipticCurve: ####################################################################### + def guess_curvename(signature): - l = (len(signature) // 2) & 0xfe - if l == 32 : - curves = [ "secp128r1", "secp128r2" ] - elif l == 48: - curves = [ "secp192k1", "secp192r1" ] - elif l == 56: - curves = [ "secp224k1", "secp224r1" ] - elif l == 64: - curves = [ "secp256k1", "secp256r1" ] - elif l == 96: - curves = [ "secp384r1" ] - elif l == 132: - curves = [ "secp521r1" ] + siglen = (len(signature) // 2) & 0xfe + if siglen == 32: + curves = ["secp128r1", "secp128r2"] + elif siglen == 48: + curves = ["secp192k1", "secp192r1"] + elif siglen == 56: + curves = ["secp224k1", "secp224r1"] + elif siglen == 64: + curves = ["secp256k1", "secp256r1"] + elif siglen == 96: + curves = ["secp384r1"] + elif siglen == 132: + curves = ["secp521r1"] else: raise ValueError("Unsupported signature size %i" % len(signature)) return curves + def recover(data, signature, curvename, alghash=None): recovered = set() curve = get_curve(curvename) @@ -423,7 +422,7 @@ def recover(data, signature, curvename, alghash=None): recovered.add(pk) if debug: print("Possible Pk: ", binascii.hexlify(pk)) - except: + except ValueError: pass else: for i in range(2): @@ -434,20 +433,23 @@ def recover(data, signature, curvename, alghash=None): recovered.add(pk) if debug: print("Possible Pk: ", binascii.hexlify(pk)) - except: + except ValueError: pass return recovered + def recover_multiple(uids, sigs, curvename, alghash=None): recovered = set() assert len(uids) == len(sigs) for i in range(len(uids)): data = binascii.unhexlify(uids[i]) if debug: - print("UID (%2i): " % len(data), binascii.hexlify(data)) + print("UID (%2i): " % + len(data), binascii.hexlify(data)) signature = binascii.unhexlify(sigs[i]) if debug: - print("Signature (%2i): " % len(signature), binascii.hexlify(signature)) + print("Signature (%2i): " % + len(signature), binascii.hexlify(signature)) recovered_tmp = recover(data, signature, curvename, alghash) if i == 0: if recovered_tmp == set(): @@ -458,60 +460,63 @@ def recover_multiple(uids, sigs, curvename, alghash=None): recovered &= recovered_tmp return recovered + def selftests(): tests = [ {'name': "Mifare Ultralight EV1", 'samples': ["04C1285A373080", "CEA2EB0B3C95D0844A95B824A7553703B3702378033BF0987899DB70151A19E7", "04C2285A373080", "A561506723D422D29ED9F93E60D20B9ED1E05CC1BF81DA19FE500CA0B81CC0ED"], - 'pk': "0490933BDCD6E99B4E255E3DA55389A827564E11718E017292FAF23226A96614B8" }, + 'pk': "0490933BDCD6E99B4E255E3DA55389A827564E11718E017292FAF23226A96614B8"}, {'name': "NTAG21x", 'samples': ["04E10CDA993C80", "8B76052EE42F5567BEB53238B3E3F9950707C0DCC956B5C5EFCFDB709B2D82B3", "04DB0BDA993C80", "6048EFD9417CD10F6B7F1818D471A7FE5B46868D2EABDC6307A1E0AAE139D8D0"], - 'pk': "04494E1A386D3D3CFE3DC10E5DE68A499B1C202DB5B132393E89ED19FE5BE8BC61" }, + 'pk': "04494E1A386D3D3CFE3DC10E5DE68A499B1C202DB5B132393E89ED19FE5BE8BC61"}, {'name': "Mifare Classic EV1", 'samples': ["0433619AB35780", "B9FAE369EC21C980650D87ED9AE9B1610E859131B4B8699C647548AB68D249BB", "524374E2", "F8758CE30A58553A9985C458FB9C7D340FCFB04847B928A0667939272BC58B5E", "53424B8A", "B4F533E8C06C021E242EFE8558C1672ED7022E5AE4E7AA2D46113B0AB6928AFC", "BD2A4146", "19505576ED327D8F8870C86B1ED00898BFEDFFF27CC82FC515BA2EEC26050873"], - 'pk': "044F6D3F294DEA5737F0F46FFEE88A356EED95695DD7E0C27A591E6F6F65962BAF" }, + 'pk': "044F6D3F294DEA5737F0F46FFEE88A356EED95695DD7E0C27A591E6F6F65962BAF"}, {'name': "DESFire Light", 'samples': ["0439556ACB6480", "D5BD0978106E1E38B513642335966AB21E9F950DCFCFAB45FF13D0DC3CA4C2AE7E0D671DF1240937D040DAC4601C5F66ED62C546EE03ED08", "043B156ACB6480", "76B46932BF2FCF4931A24C755F5CB1686B914F1856177686B864BDAD58EFA6A7493E5C2232F3ADDAA434EA4647BFD1D385BDA6115E77D74C"], - 'pk': "040E98E117AAA36457F43173DC920A8757267F44CE4EC5ADD3C54075571AEBBF7B942A9774A1D94AD02572427E5AE0A2DD36591B1FB34FCF3D" }, + 'pk': "040E98E117AAA36457F43173DC920A8757267F44CE4EC5ADD3C54075571AEBBF7B942A9774A1D94AD02572427E5AE0A2DD36591B1FB34FCF3D"}, {'name': "DESFire EV2", 'samples': ["042A41CAE45380", "B2769F8DDB575AEA2A680ADCA8FFED4FAB81A1E9908E2B82FE0FABB697BBD9B23835C416970E75768F12902ACA491349E94E6589EAF4F508", "045640CAE45380", "D34B53A8C2C100D700DEA1C4C0D0DE4409F3A418CD8D57C4F41F146E42AD9A55F014199ABBF5CA259C7799DB0AE20D5E77D4950AC7E95D33"], - 'pk': "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3A" }, + 'pk': "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3A"}, {'name': "DESFire EV3", 'samples': ["04448BD2DB6B80", "5CBB5632795C8F15263FEFB095B51C7B541AFD914A1AE44EF6FB8AF605EDF13DBFEE6C3A2DB372245E671DFE0D42CB1F0D0B8FE67A89D2F6", "04445DD2DB6B80", "166BFD9F9BFAA451172566101580DF9894F582C4A4E258C15037AD2F35A475CF1D7FB817618623A6569F991931AFB2766984E21A18512A6D"], - 'pk': "041DB46C145D0A36539C6544BD6D9B0AA62FF91EC48CBC6ABAE36E0089A46F0D08C8A715EA40A63313B92E90DDC1730230E0458A33276FB743" }, -# TODO one more Mifare Plus EV1... + 'pk': "041DB46C145D0A36539C6544BD6D9B0AA62FF91EC48CBC6ABAE36E0089A46F0D08C8A715EA40A63313B92E90DDC1730230E0458A33276FB743"}, {'name': "Mifare Plus EV1", + # TODO one more Mifare Plus EV1... 'samples': ["042A2B221C5080", "BAC40CD88E9193C58ADA5055350C4F648EB5A7AEC4FCF9BD4CDD7B1C558DE5F59C6636F26286ED48622AAA2331D4DF1CEE23B57B94BDA631"], - 'pk': "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E" }, + 'pk': "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E"}, {'name': "NTAG413DNA", 'samples': ["042468222F5C80", "B9211E320F321BD1D0E158E10FF15109B389638BAE15D9909D7725BF1250ED236D66F1AF75C94D60330E4E92535F5E6997675281A5687173", "042938222F5C80", "18B642797D1FD71806146A7A6EC778D3FDD04F39C4A3B36A592BD1A114DC44E5528380FA766C0B7EA32B284AFBE84300B620369F0686D8CC"], - 'pk': "04bb5d514f7050025c7d0f397310360eec91eaf792e96fc7e0f496cb4e669d414f877b7b27901fe67c2e3b33cd39d1c797715189ac951c2add" }, + 'pk': "04bb5d514f7050025c7d0f397310360eec91eaf792e96fc7e0f496cb4e669d414f877b7b27901fe67c2e3b33cd39d1c797715189ac951c2add"}, {'name': "NTAG424DNA", 'samples': ["0463474AA26A80", "27E9A50E6CA4BA9037C02F7D20A80D0284D0C1D83C67F5A5AC1D8A4EF86C9508417E4E9C6F85AA7920F0ABDED984CAF20467D66EA54BBF08", "04C46C222A6380", "344A806EBF704C05C19215D2F840529CE365AAD2D08A469A95896D75D477D9FAB02A0C827E9F215BD8EB0E56A3A9A008FB75D706AABBD4DA"], - 'pk': "048A9B380AF2EE1B98DC417FECC263F8449C7625CECE82D9B916C992DA209D68422B81EC20B65A66B5102A61596AF3379200599316A00A1410" }, + 'pk': "048A9B380AF2EE1B98DC417FECC263F8449C7625CECE82D9B916C992DA209D68422B81EC20B65A66B5102A61596AF3379200599316A00A1410"}, {'name': "Vivokey Spark1", -# ! tag signature bytes output by pm3 must be read right to left: echo $sig |sed 's/\(..\)/\1\n/g'|tac|tr -d '\n' (and it uses a SHA256) + # ! tag signature bytes output by pm3 must be read right to left: + # echo $sig |sed 's/\(..\)/\1\n/g'|tac|tr -d '\n' + # (and it uses a SHA256) 'samples': ["E0040118009C870C", "4B4E03E1211952EF6A5F9D84AB218CD4D7549D0CDF8CA8779F9AD16C9A9CBF3B", "E0040118009B4D62", "25CF13747C3389EC7889DE916E3747584978511CC78B51CFB1883B494CBED7AB"], - 'pk': "04d64bb732c0d214e7ec580736acf847284b502c25c0f7f2fa86aace1dada4387a" }, -# ! tag UID is considered inversed: E0040118009B5FEE => EE5F9B00180104E0 -# TODO one more ICODE-DNA... + 'pk': "04d64bb732c0d214e7ec580736acf847284b502c25c0f7f2fa86aace1dada4387a"}, {'name': "ICODE DNA, ICODE SLIX2", + # ! tag UID is considered inverted: E0040118009B5FEE => EE5F9B00180104E0 + # TODO one more ICODE-DNA... 'samples': ["EE5F9B00180104E0", "32D9E7579CD77E6F1FA11419231E874826984C5F189FDE1421684563A9663377"], - 'pk': "048878A2A2D3EEC336B4F261A082BD71F9BE11C4E2E896648B32EFA59CEA6E59F0" }, -# uses secp256r1?, SHA-256, -# {'name': "Minecraft Earth", -# 'samples': ["aa", "DF0E506DFF8FCFC4B7B979D917644445F1230D2C7CDC342AFA842CA240C210BE7275F62073A9670F2DCEFC602CBEE771C2B4CD4A04F3D1EA11F49ABDF7E8B721"], -# 'pk': "" }, + 'pk': "048878A2A2D3EEC336B4F261A082BD71F9BE11C4E2E896648B32EFA59CEA6E59F0"}, + # {'name': "Minecraft Earth", + # # uses secp256r1?, SHA-256, + # 'samples': ["aa", "DF0E506DFF8FCFC4B7B979D917644445F1230D2C7CDC342AFA842CA240C210BE7275F62073A9670F2DCEFC602CBEE771C2B4CD4A04F3D1EA11F49ABDF7E8B721"], + # 'pk': ""}, ] succeeded = True for t in tests: @@ -541,6 +546,7 @@ def selftests(): print("[FAIL]") print("Tests: [%s]" % ["FAIL", "OK"][succeeded]) + if __name__ == "__main__": if len(sys.argv) == 2 and sys.argv[1] == "selftests": selftests()