-
-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use with device already in the network? #4
Comments
The issue with using original (or compatible) accessories is that each accessory has a private master key that is required in order to decrypt its location reports. This key is generated during the pairing session between the accessory and an Apple device when it is first set up. The nicest solution would be to perform the pairing sequence ourselves in order to obtain the private key. We have pretty good (official) documentation for the bluetooth protocol between the device and accessory, so that won't be a problem. The real issue is that Apple's servers are also involved in the pairing process. As far as I know, nobody has successfully reverse engineered this part of the protocol yet, so we would first need to find out what data is exchanged between the device and Apple. Well-behaving accessories will reject pairing attempts that are not signed by Apple servers. Another way could be to have an Apple device do the pairing, and figure out where the master key is stored. As long as we have enough details to generate the rotating private keys derived from this master key, we can fetch location reports for the accessory. I don't own any Apple devices however, so I'm not really able to help in this regard. That said, this is something I'd be interested in to include in this library, so I'll leave this issue open as a feature request. |
Oh, neat! I'm expecting the Just for future reference, can you share where you found those values? This is information I'd like to include in the documentation if possible. |
Just as a quick update, I'm currently working on implementing the key derivation algorithm needed for this. It's just taking a little longer because to my knowledge this algorithm isn't standardized anywhere, so I have to roll my own crypto... fingers crossed, haha. At this point, judging by your screenshot I'm fairly certain that we're going to need the In the meantime, could you please try to dump a copy of your tag in lost mode using this script? There is a keyroll mechanism involved, so to test the algorithm we're gonna sequentially generate a bunch of keys and compare them against one of the public keys that the tag broadcasts; if it's in the sequence, we know the algorithm works. If you have a rough indication of when you first paired your tag, that will help narrow down the search sequence. The keyroll works in periods of 15 minutes. |
Sure :) There are .record files in
The
Sure, I'll re-pair the tag when I'm at home, so that I know the exact time when it was paired, and then I'll give it a shot. |
Okay, I re-paired the tag at 13:28, put it into lost mode at 13:30 (why is this needed btw?) and turned off my experimental iPhone right after that. Then I ran the scanner. Here's the result from 13:32 (4 minutes after pairing)
And here's the result from 13:55 (27 minutes after pairing)
Do you need anything else? I'm willing to send you over the stuff I dumped from the macOS Find My app if that helps. 😄 |
Thanks! With lost mode I actually meant the "separated" state, i.e. the state in which the tag is actually broadcasting its keys and can be found using Find My. Those scans are looking good though! It keeps broadcasting the same key while the hint byte changes, which is what I was expecting. Yesterday I implemented the actual algorithm, so it should be able to generate the keys now. I did have to change it a bit to generate private keys instead of public ones (because we want to decrypt reports instead of only generate them), so I hope it works... my group theory is a bit rusty. 😅 If I find the time, I'll try to integrate it with the library today and see if I can set up a test script. If you're comfortable with sharing that data, it would be greatly appreciated! Feel free to send them to |
Which OS are you running ? I don't have that record in my Keychain |
I'm running 13.6.1 on a Hackintosh system |
Alright, it should be ready! I have added a new example which you can check out if you want; it currently does not actually fetch location reports, just tries to find the private key belonging to the broadcasted public key. That key can be plugged into the Note that the master / secret keys are in binary format, so you might have to convert them first. I think the script should be pretty self-explanatory, but if you get stuck let me know. |
Heh, funny, the command stopped working for me as well. The keychain item is now called BeaconStore, so the command to obtain the key is now |
Ah right.
|
I've updated your script to automatically get the decode key and decode all of the files from ~/Library/com.apple.icloud.searchpartyd |
It works! I was successfully able to retrieve the private key belonging to the scan @YeapGuy posted here before 🎉 The one you emailed me earlier today does not work however; I'm not entirely sure why, but I probably messed something up for the secondary key generation. After the first 4:00 am it switches from primary to secondary. If you could post the full results of a scan again that'd be great. Right now this means that using the values that you extracted from the beaconstore, we're able to generate all keys that the accessory is using and use them to fetch and decrypt their location reports. There are still a few issues though:
The library and example script have been updated; make sure to use the public key (so not the "lookup key") to make it work. It can now also read all the necessary details from the .plist file, so you don't need to fill out the keys manually anymore. |
Nevermind, secondary key generation was actually working perfectly; I just made a silly mistake where it compared against the primary key twice. 🫠 Should be fixed now. |
Awesome :) It works for me with the first broadcasted key. But with the current public key, I get no match found. Results of a scan now
|
It works fine for me, but the key was found at index 192 / 200. That's 8 * 15 min = 2 hours ago, which also just happens to be exactly 2 days + 2 hours after you first paired the tag. The reason for this is that the library currently just generates the secondary key at I have just pushed an update that specifically generates keys for a certain timestamp. I'm uncertain whether the 4 AM rule is in UTC or the local timezone, but it should now be much more reliable. |
Yeah, it works with yesterday's key now. Today's key worked immediately. The scan from today
And the result of real_airtag.py
|
I would like to share some of my work based on this library, which we used in the past week to attempt to recover a stolen MacBook. Unfortunately, it ran out of battery, before we put it all together and understood how it works. So we were unsuccessful, but I think there's quite a big potential with it, and could help others a lot: https://github.com/hajekj/OfflineFindRecovery I plan to work on automating most of the steps, and making it into an application, so it can be used from phone or any device more easily. |
The FindMy networks for AirTags (like this project) and for MacBooks / iPhones are two separate things if I quote the original seemoo research correctly. @hajekj are you querying Apple's servers with this to find your MacBook, or are you searching for the BLE beacon? |
I am doing both. Querying Apple service for historical movement data, and searching for BLE to find the precise location - like specific hotel room. It is the same thing in my opinion, just handles the key generation differently:
|
I did not know that! I was under the impression that only airtags could be queried with the FindMy projects. It would be very handy to have a small script that dumps the private key from the |
Look into the repo there is a script to decrypt the keys of all the beacons you have - AirPods, MacBook, iPhone, AirTag etc. |
https://gist.github.com/airy10/5205dc851fbd0715fcd7a5cdde25e7c8 Then copy the file from the OwnedBeacons directory for the device you want to "decrypted.plist" and you then can use the scripts from @hajekj to generate the keys using "findmy-keygeneration.py", then find the last known locations if you have an anisette server using "findmy-historicallocations.py" Note the the script "findmy-keygeneration.py" needs some change for the AirTag (at least with my iTag chinese devices...) as the secondary key is from a different field :
And the test With that, I could retrieve the history locations from my iTags |
I tried using that script, but couldn't get it to work @airy10 - I will try again and comment on the Gist, if I manage to isolate the issue, but I guess it could be MacOS version related. |
It might be. It's fine here both from the command line or from a playground |
I'm not clearly understand which PUBLIC_KEY should be used in real_airtag.py, if the only one I have is already contained in decrypted.plist, but the result there is |
@malmeloo, Another thing is that the script generates all the keys from the pairing days until today and next 48 hours so I should have all the keys independently from TZ but won't retrieve the locations.. Bye |
@malmeloo, If you need more details ask me :-D |
Ah sorry, I missed the edit to your previous message. Can you share which script you are using? As for that second issue, which reported timestamp are you referring to? The ones directly reported by this library (so the found-at and uploaded-at timestamps) are timezone-aware but default to UTC, which would explain the 2-hour difference. I'll fix this to default to the local timezone, but for now it can be fixed by calling |
Here are my scripts: HistoricalLocations
FindKeys
Best Regards |
With #26 merged, I've updated Could you try that example now and see if it works for you? Make sure to actually run the module from |
Hello @malmeloo, Thanks for your work!! |
That's nice to hear! I've actually already been working on exactly that, so stay tuned ;-). |
Are you sure the airtag wasn't in range at that time? I think the FindMy app also shows those locations, though I'm not 100% sure. I'll take another look at the implementation, maybe the key generator is indeed missing some keys. |
@malmeloo, If you refer to location for this night, the AirTag is in range with iPhone, that I have used to see findmy app Do you think that if the AirTag is in range the findmy won't update the location to apple servers? |
Indeed, to my knowledge the AirTag does not broadcast any keys when the owner device has recently connected to it, because it is in |
@malmeloo thanks for all your work on this. I've just started with FindMy/airtags and have been testing your latest real_airtag.py, am working with the current code from git, using a new airtag I paired yesterday. The problem I'm hitting is that this exception:
Checking the payload bytes, I have about 30 responses that look like this:
which are decoding fine. Then I get a response like this, which is failing
byte 5 changes from 04 to 05. I know nothing about this response but presuming it's ASN.1, byte 04 indicates a string, byte 05 indicates null. Any ideas? Is the full reponse string safe to share here? Or if you can point me to some details on the format of this string I'll try and parse it and get you some more information. |
Following myself up, it looks like if I just check for EDIT: I had to make another small change in real_airtag.py to handle recently paired devices:
|
@faceless2 very interesting... I do indeed believe that it's ASN.1, but I'm also not entirely certain. I wonder why it would be null though? That part of the payload encodes the ephemeral key used to encrypt the location report, so it makes no sense to me... unless the report is unencrypted? Is the payload's length any different compared to the other ones? It looks like you're on the right track though, judging by And thank you for the fix, I'll update the example in a second 🙂 |
You can use MQTT or Home Assistant devicetracker "see" service for that. (updateMQTT function for MQTT, and updateHomeAssistant for "/api/services/device_tracker/see" service) Airy |
@malmeloo here's the payload:
Things have moved on in the last hour (!) and I've now got this working with three airtags (I modified your Finally, I realise this is a quick proof of concept you only added last night but I already have some very minor suggestions, if you don't mind.
|
Hello @airy10, Do you know a way to send also date and time? Best regards |
@faceless2 Thanks! I've created a new issue to track this, as I'm not particularly convinced this is an AirTag-only problem: #27 As for your other suggestions, I like the idea of passing a plist in as an argument, although I would like to keep the examples as simple as possible. In my experience they quickly get too convoluted, but I'd like them to only really show the core functionality of a certain task so that people can learn from them quickly. The friendly name is not really possible unfortunately, since this information is not collected by Apple in the location report. I have just finished a change that allows you to quickly query reports for an accessory through the library itself, avoiding much of the key logic that is currently present in the example. That should also make it easier to distinguish reports in any code using it. |
Unfortunately, I don't think that there is a way to force the date associated with the lat/long, either with MQTT or the see device. You can add send some custom attributes but they won't be used by "map". I think that some device_tracker subclass let the user set some custom update date so adding some new subclass might be a way. |
@airy10, |
Last suggestion for this issue: I can confirm that with a small change, the The only change required was if "secondarySharedSecret" in device_data :
SKS = device_data["secondarySharedSecret"]["key"]["data"]
else:
SKS = device_data["secureLocationsSharedSecret"]["key"]["data"] well, that and a try/catch around |
@faceless2 Great feedback, thank you! I've integrated plist parsing directly into the library now, and it should now also support iPhones with that change. The examples now also read the keys or plist path directly from the command line arguments. For now these changes are only present in #28, but I intend to merge that soon and make a new, proper release shortly after. |
As of a few minutes ago, official accessories are now officially supported! 🎉 Since this is now implemented, I am going to close this issue. If you're running into problems while using this feature, feel free to open a new one! |
@malmeloo,
|
@wes1993 Thanks, updated! |
Hi,
How technically feasible is it to use this project to work with official AirTags or other Find My devices? Already working AirTag clones are being sold for $2-4 a piece on Aliexpress, so I don't see a point in spending a lot of time messing with flashing, firmwares and all of that OpenHaystack stuff, when I can just buy a working "AirTag" for so cheap.
The text was updated successfully, but these errors were encountered: