diff --git a/examples/real_airtag.py b/examples/real_airtag.py index abc4c26..03e298e 100644 --- a/examples/real_airtag.py +++ b/examples/real_airtag.py @@ -4,25 +4,35 @@ Example showing how to retrieve the primary key of your own AirTag, or any other This key can be used to retrieve the device's location for a single day. """ +import plistlib +from datetime import datetime from findmy import FindMyAccessory # PUBLIC key that the accessory is broadcasting or has previously broadcast. # For nearby devices, you can use `device_scanner.py` to find it. -LOOKUP_KEY = "9J5sdEARfh6h0Hr3anfNjy+vnIwETaUodv73ZA==" +PUBLIC_KEY = "" +# Path to a .plist dumped from the Find My app. +PLIST_PATH = "airtag.plist" + +# == The variables below are auto-filled from the plist!! == + +with open(PLIST_PATH, "rb") as f: + device_data = plistlib.load(f) # PRIVATE master key. 28 (?) bytes. -MASTER_KEY = b"" +MASTER_KEY = device_data["privateKey"]["key"]["data"][-28:] # "Primary" shared secret. 32 bytes. -SKN = b"" +SKN = device_data["sharedSecret"]["key"]["data"] # "Secondary" shared secret. 32 bytes. -SKS = b"" +SKS = device_data["secondarySharedSecret"]["key"]["data"] # Lookahead in time slots. Each time slot is 15 minutes. # Should be AT LEAST the time that has passed since you paired the accessory! -MAX_LOOKAHEAD = 7 * 24 * 4 +delta = datetime.now() - device_data["pairingDate"] +MAX_LOOKAHEAD = int(delta.total_seconds() / (15 * 60)) + 1 def main() -> None: @@ -30,13 +40,13 @@ def main() -> None: for i in range(MAX_LOOKAHEAD): prim_key, sec_key = airtag.keys_at(i) - if LOOKUP_KEY in (prim_key.adv_key_b64, prim_key.adv_key_b64): + if PUBLIC_KEY in (prim_key.adv_key_b64, prim_key.adv_key_b64): print("KEY FOUND!!") print(f"This key was found at index {i}." - f" It was likely paired approximately {i * 15} minutes ago") + f" It was likely paired approximately {i * 15} minutes ago.") print() print("KEEP THE BELOW KEY SECRET! IT CAN BE USED TO RETRIEVE THE DEVICE'S LOCATION!") - if prim_key.adv_key_b64 == LOOKUP_KEY: + if prim_key.adv_key_b64 == PUBLIC_KEY: print(f"PRIMARY key: {prim_key.private_key_b64}") else: print(f"SECONDARY key: {sec_key.private_key_b64}") diff --git a/findmy/util/crypto.py b/findmy/util/crypto.py index 48cea12..7d2696d 100644 --- a/findmy/util/crypto.py +++ b/findmy/util/crypto.py @@ -1,7 +1,7 @@ """Pure-python NIST P-224 Elliptic Curve cryptography. Used for some Apple algorithms.""" +from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import ec -from cryptography.hazmat.primitives.hashes import SHA1 from cryptography.hazmat.primitives.kdf.x963kdf import X963KDF ECPoint = tuple[float, float] @@ -71,7 +71,7 @@ P224_P = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001 def x963_kdf(value: bytes, si: bytes, length: int) -> bytes: """Single pass of X9.63 KDF with SHA1.""" return X963KDF( - algorithm=SHA1(), # noqa: S303 + algorithm=hashes.SHA256(), sharedinfo=si, length=length, ).derive(value) @@ -86,7 +86,7 @@ def derive_ps_key(privkey: bytes, sk: bytes) -> bytes: """ Derive a primary or secondary key used by an accessory. - :param pubkey: Public key generated during pairing + :param privkey: Private key generated during pairing :param sk: Current secret key for this time period. Use SKN to derive the primary key, SKS for secondary. """