Apple 网页版登录协议
官网的登录协议存在一个加密,似乎叫SRP 加密什么的
完整的登录有四个包

//初始化
https://secure.store.apple.com/us/shop/giftcard/balance
//检查账号
https://idmsa.apple.com/appleauth/auth/federate?isRememberMeEnabled=true
//发送 请求体
{"accountName":"183655@qq.com","rememberMe":true}
//响应 请求体
{
   "federated" : false,
   "showFederatedIdpConfirmation" : false
}
https://idmsa.apple.com/appleauth/auth/signin/init
//发送 请求体
{
   "a" : "JVrdUTBgslsdEQsHyUBuUliDgkV2ktoL10Hc0SANrGzvDRRIdVD7FWsFEYu6UVNeq/L+A8GO6Loyk9bE3p77eG7RItKG6Vf6Kg5C1kKVLqoCyJcuo0eLFCxVxk58kEVOKC/C17oCaPFaJuekBrLF2uZPLwO6CxwOelEb5+6pCyl7NbIBgZFPT+7GmS//RRxwaLdSd7lTJbjneWQGdnW31pHWMU0oIxJ2yckYCXo7+XmznNkWp00OipxRk3gRfEJq1aCmcK/pedkOovstJAtYZAXT55KYrqQY1WZvaugfm34LGVK3dqSRsgbiMuCOdjM3dP8Zms/U41stitV5HfGI9w==",
   "accountName" : "183655@qq.com",
   "protocols" : [ "s2k", "s2k_fo" ]
}
//响应 请求体
{
   "b" : "o5AdJ0koE4o4KgWij90xBYABDua3BzIevRf+uHPnPTShhA3vukss04CAfk4gxUJ5GeBLXzNmXNjiXo+sqa2j6KMuJ9T4kT2Edry9GZ/4halBw9APnTIIKZj4Zmy0hodDCSiPORfhy75ALV0mgGF2CtrJtmFlArvbUlOrMhHdJkCZntqyabDcid66IY4+wmyyV5YLC/BVnXocnwsv61PeWF3t6lrUhKyitrzh9cp14dOABbKd8dBRgf+cHpEcsvyQ+b+l4PvCm9e/I6b6tWE1Njw4PlkOk08CUtI6+EeSRjc+2Tl7HbXgdgVxbOtmMv0zlLfS+gbdAyh2RChjkRbPzA==",
   "c" : "d-72e-cd5484b4-8dc0-11ef-a9f5-91f1c8ae4728:PRN",
   "iteration" : 20135,
   "protocol" : "s2k",
   "salt" : "eOwKfWjrUfiIAynOnQJ7gA=="
}
//根据上面的 b c salt(盐) 和账号信息算出 m1,m2
https://idmsa.apple.com/appleauth/auth/signin/complete?isRememberMeEnabled=true
//发送
{
   "accountName" : "183655@qq.com",
   "c" : "d-230-5c6dfc2b-8dba-11ef-a974-c72c822a521e:PRN",
   "m1" : "2mGXAjj6uMITZLfT4vRwKMgH+p8OvnSBRGzlM1FnzPQ=",
   "m2" : "EHZLaHl4RbIkU14NdCieIHnpjOxMg1ExfiSMJLL1q8s=",
   "rememberMe" : true
}
//得到
{
   "authType" : "sa"
}

实际发包中步骤2可以省略
网页登录有点不同于Itunes,这里加密后的值若登录后会作废
步骤3,4的值均来自官网的js文件 webSRPClientWorker.js 中的计算

a 是通过本地私钥计算的,获取过程大致为

var c,r,f,a;
c = ""183655@qq.com"";
r = new n.a(c);
f = r.publicValue;
a = btoa(String.fromCharCode.apply(String, o(new Uint8Array(f.buffer))));

这里的 a() 是初始化函数。

这一步成功后会得到
下一步加密需要的

b //返回的随机数serverPublicValue
c //返回的随机数
iteration //迭代次数
protocol //默认为s2k
salt //盐

先看调用过程
注意c并没有用到,而是在下次发包时候带上,作用是一个SessionID之类的

var m = {
iterations: msg.iterations,
serverPublicValue: new Uint8Array(t.from(msg.serverPublicValue, "base64")),
salt: new Uint8Array(t.from(msg.salt, "base64")),
password: msg.pwd,
protocol: msg.protocol,
accountName: msg.accountName
}
const result = await r.getEvidenceMessage(m);
 //getEvidenceMessage是异步的,这里得到result 就包含了我们需要的m1,m2

下面自己编写一下 m1,m2的计算过程

#include <iostream>
#include <openssl/sha.h>
#include <string>
#include <vector>
#include <iomanip>

// Helper function to calculate SHA-256 hash
std::vector<unsigned char> sha256(const std::vector<unsigned char>& data) {
    std::vector<unsigned char> hash(SHA256_DIGEST_LENGTH);
    SHA256_CTX sha256;
    SHA256_Init(&sha256);
    SHA256_Update(&sha256, data.data(), data.size());
    SHA256_Final(hash.data(), &sha256);
    return hash;
}

// XOR two byte arrays of equal length
std::vector<unsigned char> xorBytes(const std::vector<unsigned char>& a, const std::vector<unsigned char>& b) {
    std::vector<unsigned char> result(a.size());
    for (size_t i = 0; i < a.size(); i++) {
        result[i] = a[i] ^ b[i];
    }
    return result;
}

// Calculate M1
std::vector<unsigned char> calculateM1(
    const std::string& N,
    const std::string& g,
    const std::string& username,
    const std::vector<unsigned char>& salt,
    const std::vector<unsigned char>& A,
    const std::vector<unsigned char>& B,
    const std::vector<unsigned char>& K
) {
    // Calculate sha256(N) and sha256(g)
    auto i1 = sha256(std::vector<unsigned char>(N.begin(), N.end()));
    auto i2 = sha256(std::vector<unsigned char>(g.begin(), g.end()));
    
    // XOR i1 and i2
    auto i = xorBytes(i1, i2);

    // Prepare SHA256 context for M1
    SHA256_CTX sha256;
    SHA256_Init(&sha256);
    
    // Update with XOR result
    SHA256_Update(&sha256, i.data(), i.size());

    // Update with sha256(username)
    auto usernameHash = sha256(std::vector<unsigned char>(username.begin(), username.end()));
    SHA256_Update(&sha256, usernameHash.data(), usernameHash.size());

    // Update with salt, A, B, and K
    SHA256_Update(&sha256, salt.data(), salt.size());
    SHA256_Update(&sha256, A.data(), A.size());
    SHA256_Update(&sha256, B.data(), B.size());
    SHA256_Update(&sha256, K.data(), K.size());

    // Finalize and return the hash for M1
    std::vector<unsigned char> M1(SHA256_DIGEST_LENGTH);
    SHA256_Final(M1.data(), &sha256);
    return M1;
}

// Calculate M2
std::vector<unsigned char> calculateM2(
    const std::vector<unsigned char>& A,
    const std::vector<unsigned char>& M1,
    const std::vector<unsigned char>& K
) {
    // Prepare SHA256 context for M2
    SHA256_CTX sha256;
    SHA256_Init(&sha256);

    // Update with A, M1, and K
    SHA256_Update(&sha256, A.data(), A.size());
    SHA256_Update(&sha256, M1.data(), M1.size());
    SHA256_Update(&sha256, K.data(), K.size());

    // Finalize and return the hash for M2
    std::vector<unsigned char> M2(SHA256_DIGEST_LENGTH);
    SHA256_Final(M2.data(), &sha256);
    return M2;
}

// Helper function to print vector as hex
void printHex(const std::vector<unsigned char>& data) {
    for (const auto& byte : data) {
        std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)byte;
    }
    std::cout << std::dec << std::endl;
}

int main() {
    // Test data
    std::string N = "AC6BDB41..."; // Replace with the actual value
    std::string g = "02";
    std::string username = "testuser";
    std::vector<unsigned char> salt = {0x00, 0x01, 0x02};  // Example salt
    std::vector<unsigned char> A = {0xAA, 0xBB, 0xCC};      // Example A
    std::vector<unsigned char> B = {0xDD, 0xEE, 0xFF};      // Example B
    std::vector<unsigned char> K = {0x11, 0x22, 0x33};      // Example K

    // Calculate M1 and M2
    auto M1 = calculateM1(N, g, username, salt, A, B, K);
    auto M2 = calculateM2(A, M1, K);

    // Print M1 and M2
    std::cout << "M1: ";
    printHex(M1);
    std::cout << "M2: ";
    printHex(M2);

    return 0;
}

到此Apple 网页登录所需的所有加密值都有了。

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐