Open acalatrava opened 3 years ago
This is technically possible, but quite hard to implement.
The keys are not directly located in the macOS keychain. The keychain contains a key called BeaconStore
, which is used to encrypt the private keys synchronized between multiple devices. Those private keys are called Master Beacon
and they are located at ~/Library/com.apple.icloud.searchpartyd/MasterBeacons/
. The *.record files are property lists, which contain another property list. To decrypt them you should use the Beacon Store
key and AES GCM.
After you've got the actual private key you cannot just use its public key to public this one and have your device appear in FindMy. For this your would need to adapt the firmware that is currently available to send rotating keys as mentioned in our paper (see Section 6.1)
We are currently working on a firmware with rotating keys, but we do not have an ETA, yet.
Thank you for your input! I understand that you can't use the public key directly, but I don't think you need to implement the whole rotating keys thing, I guess that if you generate the first key and the device send that first key continuously that should work.
Also I tried to check those keys on my keychain but they are not present on any of my Macs. I'm still running MacOS Mojave so maybe that's the cause since offline finding appeared on MacOS Catalina, but my iPhone is running iOS14 so I thought at least their key should be there... but maybe is not synced since I'm not on Catalina/BigSur?
BTW, I maybe able to help with the new firmware if you need to. I'm trying to port the firmware to Go (using TinyGO) although it seems that the crypto packages are not available for nrf51822 so maybe that's not possible.
I'm not sure if this is the right communication channel or you have slack or something where we can discuss this technical things in a faster way.
This is definitely the best communication channel for the moment.
I think generating the first key does not work, because from our reverse engineering we know that the devices are only checking for current keys (for the last 7 days). You could probably generate one current key and deploy it to one of your devices. This could work for about 7 days.
The reason why you cannot find the keys is definitely macOS Mojave. You would need Catalina for Offline Finding and even Big Sur for Open Haystack.
I'll keep this issue open for further discussions
To decrypt them you should use the Beacon Store key and AES GCM.
@Sn0wfreezeDev how do you get the BeaconStore key? When I run security find-generic-password -l 'BeaconStore' -g
no value is printed (even with SIP off). I do see an attribute "gena" with a curious looking hex value, but it doesn't seem to work as a decryption key. Thanks.
I find it in KeychainAccess
easily
Odd, I have multiple airtags showing up in Find My, but the password field is blank for the BeaconStore item in KeychainAccess. Perhaps they relocated the key?
The content might be in any raw data that cannot be represented by some text. Probably because the randomly generate those passwords. You can probably access the data with Swift and Apple's security framework.
I did also try accessing it from Swift and saw no data stored under that keychain item.
When arbitrary data is stored as the value, the KeyChain app does not allow checking the "Show Password" box. Also, security
at least sometimes shows a representation of the data with the -g
flag. For example, you can see OpenHaystack's keychain plist data with security find-generic-password -l 'FindMyAccessories' -g
.
Can you share any information or example code that you used to retrieve the key and decrypt the .record files? Thanks!
Sorry, I don't have any source code available for this. The last time I decrypted my private keys was with macOS Catalina. Apple has changed a lot there after we submitted a security vulnerability.
Yay I was finally able to decrypt these .record files. For anybody else trying to do this:
kSecAttrGeneric
of the BeaconStore keychain item. You can get its hex encoding very simply with security -v find-generic-password -l 'BeaconStore' -g
.AES.GCM.open(sealedBox, using: key)
in CryptoKit
. The result is a plist.I had been stumped by the fact that there was no proper data associated with the keychain item in step (3), along with trying to use openssl
to decrypt the file rather than cryptokit. Thanks again @Sn0wfreezeDev.
Did any of you get any further with this? I’ve successfully decrypted the plist but have ended up with a private, public, sharedsecret and sharedlocationsecret key. None of which seem to be usable to generate valid rolling keys.
Hey @robinkruyt,
Congrats! That's exactly what you need to generate the keys. Please refer to the paper in section 6.1 to see how the rolling keys are generated. d = private key, p = public key, SK = shared secret.
Hello everyone,
I have a question that might be related. Feel free to delete or move my post if it's not. Using the technique described above to extract the key for a specific regular airtag (an apple one), would it be possible for a standalone bluetooth device (say, an ESP-32 dev board, or a raspberry pi) to identify it when it's in range, either with its BLE address or the contents of the payload ? If so, any hints about where I should start digging ? Trivia : I'm tracking my dog using an AirTag, I would like to be able to detect when it stays close to the front door for a while and open it automatically. Thanks !
Hi @leokeba
yes that would be possible if you have access to the private key, you can start generating public keys that will match the one sent out by your AirTag. But I expect this not to be stable, because the AirTag does not always emit those public keys. For example when your iPhone is close by the AirTag will go in a low-power mode and you cannot detect it with this technique. It will still send out BLE signals, but they are very short and do not contain much data.
Thanks @Sn0wfreezeDev for the quick answer.
From what I gather, the public key and BLE address are rotated every 24 hours. So in theory, if I'm able to to match the public key with the address, I could still be able to identify the AirTag using the address alone until it rotates again, right ? Also, I'm not very clear on the relation between private key, public key and advertisement data. Using the private key, I can generate a public one, but how would I know which one is the right one for said day ? Is it seeded with the date, or something similar ? Also, I read that the last byte of advertisement data changes every 15 minutes, but what is it exactly ? Is it the public key ? Is it trivial to match it with the last byte modified ? Thanks again, and sorry for all the questions, I'm still kind of a cryptography noob.
Yes you are right the AIrTag changes it's key pair (public and private key) every 24 hours. The public key is part of the BLE address and the BLE manufacturer data. To identify devices it is likely that the BLE address is enough. Yes one main problem is that you will not know where the AirTag starts with the rotation and at which position it is at the moment. Your iPhone might Log something like this (you can check with the Console app), but I'm not sure how you would find this out otherwise.
The iPhone and the AirTag often synchronize with each other to update the current state of the key.
@Sn0wfreezeDev is there a way for Apple to lockout/identify OpenHaystack users in the future? Or they just provide the infrastructure and don't see if we rotate the public part or not.
As I understand OpenHaystack hijacks the API so it can query arbitrary public key which don't depend on rotation/counter. Can they close down that API, or FindMy app depends on it?
Open the .record files as plists.
plutil -convert xml1 XXXXX.record
seems to work
The key is the "gena" or kSecAttrGeneric of the BeaconStore keychain item. You can get its hex encoding very simply with security -v find-generic-password -l 'BeaconStore' -g.
That command yields nothing. But without the -g
it shows a "gena" blob...
Decrypt using AES.GCM.open(sealedBox, using: key) in CryptoKit. The result is a plist.
Is there a way to actually do this without installing development tools?
Did anyone get any further with this?
I'm trying to do the same thing as @leokeba, track airtags that I own using standard ble scanners.
I understand from the discussion above that to do so I need to extract the private key for the airtag from my icloud keychain (by using the technique posted by @llama above) and then generate a public key from that private key (or maybe generate a set of possible public keys?) and then compare those to the public key being broadcast by the airtag, which is split across the ble address and the ble manufacturer data.... but it might be enough to just compare the approriate bits from the generated public keys to the bits in the ble address.
Does all that sound about right?
4. Decrypt using `AES.GCM.open(sealedBox, using: key)` in `CryptoKit`. The result is a plist.
How exactly would I go about this? I tried a few things, but I can't even get my code to compile...I figured it out
Thanks to everyone solving those mysteries so far. @YeapGuy 's script made retrieving the key pair a breeze, after my Mac lost track of all its tracked items (still not sure why things broke that badly, but any iOS device linked to my account is no longer able to query Apple's server on found AirTags or add new ones, let alone see those already deployed - devices, no problem, it's just the items that are lost), Any pointers how I can stuff those key pairs into OH or one of its happy derivates? Not wanting to hijack this thread, though, My problem is tracked in #232.
I have created this: https://github.com/denysvitali/searchparty-keys
Given the .record
files (and a BeaconStore
password) - it provides a way to get all the necessary keys - which can then be used to find your lost items.
I’m trying to use a public key from one of the devices currently registered on Find My App. This way I could create a tag that should appear as one of my Macs. According to the docs the private key should be on the iCloud Keychain but I’m unable to find it. Does anybody knows where is it and how can I export it? Thanks!