more flexible recover_pk

This commit is contained in:
Philippe Teuwen 2020-12-10 21:33:37 +01:00
commit 21f5edb4b9

View file

@ -210,13 +210,23 @@ CURVES = {
0xBD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34 0xBD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34
) )
), ),
"secp256k1": (
## openssl uses the name: prime256v1 714,
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F,
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141,
0x0000000000000000000000000000000000000000000000000000000000000000,
0x0000000000000000000000000000000000000000000000000000000000000007,
(
0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798,
0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8
)
),
## openssl uses the name: prime256v1.
"secp256r1": ( "secp256r1": (
415, 415,
0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF, 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF,
0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551, 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551,
-3, 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC,
0x5AC635D8AA3A93E7B3EbBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B, 0x5AC635D8AA3A93E7B3EbBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B,
( (
0x6B17D1F2E12c4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296, 0x6B17D1F2E12c4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296,
@ -313,30 +323,21 @@ class EllipticCurve:
####################################################################### #######################################################################
def recover(data, signature, alghash=None): def guess_curvename(signature):
recovered = set() if (len(signature) // 2) & 0xfe == 32 :
if len(signature) == 32: curves = [ "secp128r1" ]
curve = get_curve("secp128r1") elif (len(signature) // 2) & 0xfe == 56:
recoverable = False curves = [ "secp224r1" ]
elif len(signature) == 33: elif (len(signature) // 2) & 0xfe == 64:
curve = get_curve("secp128r1") curves = [ "secp256k1", "secp256r1" ]
recoverable = True
elif len(signature) == 56:
curve = get_curve("secp224r1")
recoverable = False
elif len(signature) == 57:
curve = get_curve("secp224r1")
recoverable = True
elif len(signature) == 64:
curve = get_curve("secp256r1")
recoverable = False
elif len(signature) == 65:
curve = get_curve("secp256r1")
recoverable = True
else: else:
print("Unsupported signature size %i" % len(signature)) raise ValueError("Unsupported signature size %i" % len(signature))
exit(1) return curves
def recover(data, signature, curvename, alghash=None):
recovered = set()
curve = get_curve(curvename)
recoverable = len(signature) % 1 == 1
if (recoverable): if (recoverable):
try: try:
pk = curve.recover(signature, data, hash=alghash) pk = curve.recover(signature, data, hash=alghash)
@ -358,7 +359,7 @@ def recover(data, signature, alghash=None):
pass pass
return recovered return recovered
def recover_multiple(uids, sigs, alghash=None): def recover_multiple(uids, sigs, curvename, alghash=None):
recovered = set() recovered = set()
assert len(uids) == len(sigs) assert len(uids) == len(sigs)
for i in range(len(uids)): for i in range(len(uids)):
@ -368,7 +369,7 @@ def recover_multiple(uids, sigs, alghash=None):
signature = binascii.unhexlify(sigs[i]) signature = binascii.unhexlify(sigs[i])
if debug: if debug:
print("Signature (%2i): " % len(signature), binascii.hexlify(signature)) print("Signature (%2i): " % len(signature), binascii.hexlify(signature))
recovered_tmp = recover(data, signature, alghash) recovered_tmp = recover(data, signature, curvename, alghash)
if i == 0: if i == 0:
if recovered_tmp == set(): if recovered_tmp == set():
break break
@ -427,7 +428,7 @@ def selftests():
{'name': "ICODE DNA, ICODE SLIX2", {'name': "ICODE DNA, ICODE SLIX2",
'samples': ["EE5F9B00180104E0", "32D9E7579CD77E6F1FA11419231E874826984C5F189FDE1421684563A9663377"], 'samples': ["EE5F9B00180104E0", "32D9E7579CD77E6F1FA11419231E874826984C5F189FDE1421684563A9663377"],
'pk': "048878A2A2D3EEC336B4F261A082BD71F9BE11C4E2E896648B32EFA59CEA6E59F0" }, 'pk': "048878A2A2D3EEC336B4F261A082BD71F9BE11C4E2E896648B32EFA59CEA6E59F0" },
# ! uses secp256r1 , SHA-256, # uses secp256r1?, SHA-256,
# {'name': "Minecraft Earth", # {'name': "Minecraft Earth",
# 'samples': ["aa", "DF0E506DFF8FCFC4B7B979D917644445F1230D2C7CDC342AFA842CA240C210BE7275F62073A9670F2DCEFC602CBEE771C2B4CD4A04F3D1EA11F49ABDF7E8B721"], # 'samples': ["aa", "DF0E506DFF8FCFC4B7B979D917644445F1230D2C7CDC342AFA842CA240C210BE7275F62073A9670F2DCEFC602CBEE771C2B4CD4A04F3D1EA11F49ABDF7E8B721"],
# 'pk': "" }, # 'pk': "" },
@ -435,8 +436,11 @@ def selftests():
succeeded = True succeeded = True
for t in tests: for t in tests:
print("Testing %-25s" % (t['name']+":"), end="") print("Testing %-25s" % (t['name']+":"), end="")
recovered = recover_multiple(t['samples'][::2], t['samples'][1::2]) curvenames = guess_curvename(t['samples'][1])
recovered |= recover_multiple(t['samples'][::2], t['samples'][1::2], alghash="sha256") recovered = set()
for c in curvenames:
for h in [None, "sha1", "sha256", "sha512"]:
recovered |= recover_multiple(t['samples'][::2], t['samples'][1::2], c, alghash=h)
if (len(recovered) == 1): if (len(recovered) == 1):
pk = recovered.pop() pk = recovered.pop()
pk = binascii.hexlify(pk).decode('utf8') pk = binascii.hexlify(pk).decode('utf8')
@ -465,14 +469,15 @@ if __name__ == "__main__":
print("Usage: \n%s UID SIGN [UID SIGN] [...]" % sys.argv[0]) print("Usage: \n%s UID SIGN [UID SIGN] [...]" % sys.argv[0])
print("Example: \n%s 04ee45daa34084 ebb6102bff74b087d18a57a54bc375159a04ea9bc61080b7f4a85afe1587d73b" % sys.argv[0]) print("Example: \n%s 04ee45daa34084 ebb6102bff74b087d18a57a54bc375159a04ea9bc61080b7f4a85afe1587d73b" % sys.argv[0])
exit(1) exit(1)
uids, sigs = sys.argv[1:][::2], sys.argv[1:][1::2]
print("Assuming no hash was used in the signature generation:") curvenames = guess_curvename(sigs[0])
recovered = recover_multiple(sys.argv[1:][::2], sys.argv[1:][1::2]) for c in curvenames:
print("Possible uncompressed Pk(s):") print("\nAssuming curve=%s" % c)
for pk in list(recovered): print("========================")
print(binascii.hexlify(pk).decode('utf8')) for h in [None, "sha1", "sha256", "sha512"]:
print("Assuming SHA-256 was used in the signature generation:") print("Assuming hash=%s" % h)
recovered = recover_multiple(sys.argv[1:][::2], sys.argv[1:][1::2], alghash="sha256") recovered = recover_multiple(uids, sigs, c, alghash=h)
print("Possible uncompressed Pk(s):") if recovered:
for pk in list(recovered): print("Possible uncompressed Pk(s):")
print(binascii.hexlify(pk).decode('utf8')) for pk in list(recovered):
print(binascii.hexlify(pk).decode('utf8'))