Skip to content
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

Private keys of regular devices #37

Open
acalatrava opened this issue Apr 5, 2021 · 26 comments
Open

Private keys of regular devices #37

acalatrava opened this issue Apr 5, 2021 · 26 comments
Labels
question Further information is requested

Comments

@acalatrava
Copy link

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!

@acalatrava acalatrava added the question Further information is requested label Apr 5, 2021
@Sn0wfreezeDev
Copy link
Member

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.

@acalatrava
Copy link
Author

acalatrava commented Apr 6, 2021

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.

@Sn0wfreezeDev
Copy link
Member

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

@llama
Copy link

llama commented Jun 3, 2021

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.

@Sn0wfreezeDev
Copy link
Member

I find it in KeychainAccess easily

@llama
Copy link

llama commented Jun 3, 2021

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?

@Sn0wfreezeDev
Copy link
Member

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.

@llama
Copy link

llama commented Jun 4, 2021

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!

@Sn0wfreezeDev
Copy link
Member

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.

@llama
Copy link

llama commented Jun 11, 2021

Yay I was finally able to decrypt these .record files. For anybody else trying to do this:

  1. Open the .record files as plists.
  2. First value is the nonce. Second value is the tag. Third value is ciphertext.
  3. 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.
  4. Decrypt using 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.

@robinkruyt
Copy link

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.

@Sn0wfreezeDev
Copy link
Member

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.

@leokeba
Copy link

leokeba commented Oct 20, 2021

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 !

@Sn0wfreezeDev
Copy link
Member

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.

@leokeba
Copy link

leokeba commented Oct 21, 2021

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.

@Sn0wfreezeDev
Copy link
Member

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.

@mrx23dot
Copy link

@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?

@luke-jr
Copy link

luke-jr commented Nov 21, 2022

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?

@PaulBerry-Briggs
Copy link

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?

@YeapGuy
Copy link

YeapGuy commented Jan 28, 2024

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

@th122
Copy link

th122 commented Feb 7, 2024

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.

@denysvitali
Copy link

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.

@thisiscam
Copy link

On macOS 15 running security -v find-generic-password -l 'BeaconStore' -g gives

find-generic-password "-l" "BeaconStore" "-g"
security: SecKeychainSearchCopyNext: The specified item could not be found in the keychain.

@crschmidt
Copy link

crschmidt commented Dec 11, 2024

On macOS 15 running security -v find-generic-password -l 'BeaconStore' -g gives

find-generic-password "-l" "BeaconStore" "-g"
security: SecKeychainSearchCopyNext: The specified item could not be found in the keychain.

From experimenting, it seems that Apple may have moved the BeaconStore into the iCloud/Local Items keychain as part of MacOS 15, which (as far as I can tell) can not be accessed from the security tool or any other tool. You can probably confirm this by opening up the Keychain Access app and searching for BeaconStore to see if the BeaconStore key is located on the login keychain or the iCloud or "Local Items" keychain. If so, this seems like it makes it much more difficult to extract keys from OS X 15.x, which I would guess is probably intentional on Apple's part.

@thisiscam
Copy link

On macOS 15 running security -v find-generic-password -l 'BeaconStore' -g gives

find-generic-password "-l" "BeaconStore" "-g"
security: SecKeychainSearchCopyNext: The specified item could not be found in the keychain.

From experimenting, it seems that Apple may have moved the BeaconStore into the iCloud/Local Items keychain as part of MacOS 15, which (as far as I can tell) can not be accessed from the security tool or any other tool. You can probably confirm this by opening up the Keychain Access app and searching for BeaconStore to see if the BeaconStore key is located on the login keychain or the iCloud or "Local Items" keychain. If so, this seems like it makes it much more difficult to extract keys from OS X 15.x, which I would guess is probably intentional on Apple's part.

Yes, the BeaconStore is indeed now in the iCloud keychain. I also recently found that Apple might have changed the key rotation algorithm on official airtags: malmeloo/FindMy.py#90 So maybe this is part of their attempt to strengthen security of official accessories. Unfortunately, that means I can't use official airtags anymore for my own purpose..

@thisiscam
Copy link

Here's another plausible explanation of this: MartinPham/FindMySync#25 (comment) .

Basically, I'm stuck at fetching the password to decode the plists because of this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests