Fix accessory key generation

This commit is contained in:
Mike A
2024-02-07 17:45:40 +01:00
parent d4a5fcef10
commit 612fe63408
2 changed files with 21 additions and 11 deletions

View File

@@ -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. 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 from findmy import FindMyAccessory
# PUBLIC key that the accessory is broadcasting or has previously broadcast. # PUBLIC key that the accessory is broadcasting or has previously broadcast.
# For nearby devices, you can use `device_scanner.py` to find it. # 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. # PRIVATE master key. 28 (?) bytes.
MASTER_KEY = b"" MASTER_KEY = device_data["privateKey"]["key"]["data"][-28:]
# "Primary" shared secret. 32 bytes. # "Primary" shared secret. 32 bytes.
SKN = b"" SKN = device_data["sharedSecret"]["key"]["data"]
# "Secondary" shared secret. 32 bytes. # "Secondary" shared secret. 32 bytes.
SKS = b"" SKS = device_data["secondarySharedSecret"]["key"]["data"]
# Lookahead in time slots. Each time slot is 15 minutes. # Lookahead in time slots. Each time slot is 15 minutes.
# Should be AT LEAST the time that has passed since you paired the accessory! # 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: def main() -> None:
@@ -30,13 +40,13 @@ def main() -> None:
for i in range(MAX_LOOKAHEAD): for i in range(MAX_LOOKAHEAD):
prim_key, sec_key = airtag.keys_at(i) 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("KEY FOUND!!")
print(f"This key was found at index {i}." 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()
print("KEEP THE BELOW KEY SECRET! IT CAN BE USED TO RETRIEVE THE DEVICE'S LOCATION!") 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}") print(f"PRIMARY key: {prim_key.private_key_b64}")
else: else:
print(f"SECONDARY key: {sec_key.private_key_b64}") print(f"SECONDARY key: {sec_key.private_key_b64}")

View File

@@ -1,7 +1,7 @@
"""Pure-python NIST P-224 Elliptic Curve cryptography. Used for some Apple algorithms.""" """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.asymmetric import ec
from cryptography.hazmat.primitives.hashes import SHA1
from cryptography.hazmat.primitives.kdf.x963kdf import X963KDF from cryptography.hazmat.primitives.kdf.x963kdf import X963KDF
ECPoint = tuple[float, float] ECPoint = tuple[float, float]
@@ -71,7 +71,7 @@ P224_P = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001
def x963_kdf(value: bytes, si: bytes, length: int) -> bytes: def x963_kdf(value: bytes, si: bytes, length: int) -> bytes:
"""Single pass of X9.63 KDF with SHA1.""" """Single pass of X9.63 KDF with SHA1."""
return X963KDF( return X963KDF(
algorithm=SHA1(), # noqa: S303 algorithm=hashes.SHA256(),
sharedinfo=si, sharedinfo=si,
length=length, length=length,
).derive(value) ).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. 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. :param sk: Current secret key for this time period.
Use SKN to derive the primary key, SKS for secondary. Use SKN to derive the primary key, SKS for secondary.
""" """