Apple登录协议Apple网页登录协议分析,SRP算法(附C++加密代码)
步骤3,4的值均来自官网的js文件 webSRPClientWorker.js 中的计算。注意c并没有用到,而是在下次发包时候带上,作用是一个SessionID之类的。网页登录有点不同于Itunes,这里加密后的值若登录后会作废。官网的登录协议存在一个加密,似乎叫SRP 加密什么的。到此Apple 网页登录所需的所有加密值都有了。a 是通过本地私钥计算的,获取过程大致为。下面自己编写一下 m1,m
·
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 网页登录所需的所有加密值都有了。
更多推荐
所有评论(0)