steilerDev/icloud-photos-sync

Implementing new iCloud authentication process

steilerDev opened this issue ยท 7 comments

Describe the ultimate goal you want to achieve

Based on recent network captures, it seems that Apple has changed it's web authentication API flow utilising a new password exchange protocol that does not exchange the plain text password. Based on the current investigations, it seems it is using a variation of the SRP protocol.

How do you think the feature should be implemented

Ongoing reverse engineering efforts:

  • POST to https://idmsa.apple.com/appleauth/auth/signin/init with the following body:
{
  "a": 512 (random?) bytes - base64 encoded,
  "accountName": AppleID email,
  "protocols": [
    "s2k",
    "s2k_fo"
  ]
}
{
  "iteration" : 20403,
  "salt" : 16 (random?) bytes - base64 encoded,
  "protocol" : "s2k",
  "b" : 256 (random?) bytes - base64 encoded,
  "c" : "x-xxx-xxxxxxxx-xxxx-xxxx-xxxxx-xxxxxxxxxxxx:RNO" // where x matches [a-z0-9] Looks like some ID - changes slightly on every request 
}
  • Following this, the iCloud Web app responds to https://idmsa.apple.com/appleauth/auth/signin/complete?isRememberMeEnabled=true with the following payload:
{
  "accountName": AppleID email,
  "rememberMe": false,
  "trustTokens": [
    Trust Token string, or empty
  ],
  "m1": 32 bytes - base64 encoded,
  "c": appears to be the same string as 'c' in previous response,
  "m2": 32 bytes - base64 encoded
}
  • This endpoint (like the previous https://idmsa.apple.com/appleauth/auth/signin) returns either 406 or 200 depending on MFA status

From this my current efforts indicate the following:

  • a is the SRP public client ephemeral, derived from the account name and password
  • b is iCloud's public server ephemeral
  • m1/m2 are the session secrets derived from the challenge
  • c seems to be related to hashcashgen - it's part of the icloud.js attributions, luckily it seems we don't need to care and only hand it back

I'm currently trying to verify these assumption - however I am already seeing issues with this:

  • I'm not taking iterations into account (afaik there is no modern hashing algorithm that works on iterations?)
  • I'm ignoring protocol: s2k - this might refer to OpenPGP's string-2-key specifiers, which would also allow iterations and salting, which would add another level of complication to the reverse engineering efforts

Given all of this complexity, I was trying to follow the application logic of the iCloud Web App, unfortunately the code is obfuscated in a way that I cannot understand what's going on. You can find some references to srpData in there, as well as the crypto library and imports of md5 and sha. The Nt class is exposing functions that are most likely interesting for us (e.g. _getSRPValues(e)) - maybe someone with more JS debugging experience could follow this angle.

Implications

The currently implemented authentication flow (that is just sending the plain password) still works - I have no idea if Apple plans to kill off this behaviour / when they will do this. This item nevertheless takes highest priority, because it has the potential to break all iCloud API interactions.

foxt commented

It seems like this protoocol isn't anything new, rather a port of the existing protocol used by Apple devices since 2SV was introduced (i.e. around iOS 9)? to the web, the good thing being there already being documentation for that version (called Grandslam or GSA):

https://github.com/MathewYaldo/Apple-GSA-Protocol
https://github.com/ionescu007/Blackwood-4NT/tree/main

(afaik there is no modern hashing algorithm that works on iterations?)

https://en.wikipedia.org/wiki/PBKDF2 ?

foxt commented

I hacked on the existing js-srp package to get it working with the variant Apple uses.

npm i @foxt/js-srp

I left some code samples at https://github.com/foxt/js-srp-gsa

You are a maniac @foxt ! Thank you for your help on this ๐Ÿ‘๐Ÿป

Quickly tested it and works like a charm!

This issue should be resolved with version v1.3.0-beta.2, please confirm.

This issue was resolved with version v1.3.0.