Die Authentifizierung der Extend API schlägt wegen fehlerhaftem hmac oder hkdf fehlPython

Python-Programme
Guest
 Die Authentifizierung der Extend API schlägt wegen fehlerhaftem hmac oder hkdf fehl

Post by Guest »

Ich versuche, den Anmeldefluss auf diesem Python-Repo zu replizieren, aber in Swift. Es gibt 4 Schritte, wie in der Anmeldefunktion angezeigt, und ich habe Probleme mit dem zweiten Schritt. Ich habe den ersten Schritt korrekt bestanden und alle erforderlichen Informationen aus „ChallengeParameters“ extrahiert. Wenn ich jedoch den zweiten Schritt versuche, erhalte ich die folgende http-Antwort. Ich bin zu 100 Prozent sicher, dass das von mir eingegebene Passwort korrekt ist und alle Werte von „ChallengeParameters“ richtig erscheinen. Ich habe das Gefühl, dass das Problem darin besteht, wie die Signatur berechnet wird, da die Berechnung ziemlich aufwändig ist und ich das Gefühl habe, dass ich sie nicht korrekt aus Python konvertiere.

Code: Select all

{"__type":"NotAuthorizedException","message":"Incorrect username or password."}
Wenn ich das Web-JS durchsuche, erhalte ich Folgendes: (und was ich an Auth übergebe)

Code: Select all

deviceKey = "-d4yTUB0o"
devicePassword = "us-east-1_c75a763a-304d-46f4-8b56-b72cb0101dac"
randomPasswordKey = "Nk/v/8FbJPo16AxlzUN3BFVw4NoMIRkslKpcQQUsh76eWezJwUE55g=="
Der relevante Code im obigen Link befindet sich in den Dateien cognito/srp.py und cognito/auth.py. Ich empfehle nicht, zu versuchen, dies zu reproduzieren. Ich denke, mein Problem liegt darin, dass ich CryptoKit nicht verstehe und den Python-Code konvertiere. Wenn Sie versuchen möchten, dies zu reproduzieren, müssen Sie ein Extend VCC-Konto erstellen. Außerdem müssen Sie die 3 Variablen extrahieren, wie in der Readme-Datei im Link gezeigt.
Um den Code aufzurufen, können Sie einfach Folgendes tun:

Code: Select all

let authParams = AuthParams(username: email, password: password, deviceKey: deviceKey, devicePassword: randomPasswordKey, deviceGroupKey: deviceGroupKey)
let cognito = Cognito(auth: authParams)

Task {
do {
let accessToken = try await cognito.authenticate()
} catch {
print("Err")
}
}
srp-Datei

Code: Select all

import Foundation
import CryptoKit
import BigInt

class SRPAuthentication {
private let auth: AuthParams
private let N_HEX = """
FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF
"""
private let G_HEX = "2"
private let INFO_BITS = "Caldera Derived Key"
private let N: BigInt
private let g: BigInt
private let a: BigInt
private let A: BigInt

init(auth: AuthParams) {
self.auth = auth
self.N = BigInt(N_HEX, radix: 16) ?? BigInt(0)
self.g = BigInt(G_HEX, radix: 16) ?? BigInt(0)
self.a = SRPAuthentication.generateRandomSmallA(N: self.N)
self.A = SRPAuthentication.calculateA(g: self.g, a: self.a, N: self.N)
}

func getAuthParams() -> [String: String] {
return ["USERNAME": auth.username, "SRP_A": self.A.serialize().hexEncodedString()]
}

func passwordVerifierChallenge(challengeParams: [String: Any]) ->  [String: String] {
guard let challengeParameters = challengeParams["ChallengeParameters"] as? [String: Any] else {
print("Error: Missing or invalid 'ChallengeParameters'")
return [:]
}

guard let username = challengeParameters["USERNAME"] as? String,
let userId = challengeParameters["USER_ID_FOR_SRP"] as? String,
let saltHex = challengeParameters["SALT"] as? String,
let srpBHex = challengeParameters["SRP_B"] as? String,
let secretBlockB64 = challengeParameters["SECRET_BLOCK"] as? String,
let bigB = BigInt(srpBHex, radix: 16),
let salt = BigInt(saltHex, radix: 16),
let secretBlock = Data(base64Encoded: secretBlockB64) else {
print("Error: Missing or invalid parameters in challengeParameters")
return [:]
}

let hkdf = self.getPasswordAuthenticationKey(
poolName: "pN4CuZHEc",
userId: userId,
password: self.auth.password,
bigB: bigB,
salt: salt
)

let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.timeZone = TimeZone(identifier: "UTC")
dateFormatter.dateFormat = "EEE MMM dd HH:mm:ss 'UTC' yyyy"
let timestamp = dateFormatter.string(from: Date())

// Create message
var message = "pN4CuZHEc\(userId)".data(using: .utf8)!
message.append(secretBlock)
message.append(timestamp.data(using: .utf8)!)

// Calculate HMAC signature
let hmac = HMAC.authenticationCode(for: message, using: SymmetricKey(data: hkdf))
let signature = Data(hmac).base64EncodedString()

return [
"TIMESTAMP": timestamp,
"USERNAME": username,
"PASSWORD_CLAIM_SECRET_BLOCK": secretBlockB64,
"PASSWORD_CLAIM_SIGNATURE": signature,
"DEVICE_KEY": self.auth.deviceKey
]
}

private func getPasswordAuthenticationKey(
poolName: String,
userId: String,
password: String,
bigB: BigInt,
salt: BigInt
) -> Data {
// Calculate U value
let u = calculateU(A: self.A, B: bigB)

// Calculate X value
let userPass = "\(poolName)\(userId):\(password)"
let userPassHash = SHA256.hash(data: userPass.data(using: .utf8)!).hexEncodedString()
let xHex = padHex(longToHex(salt)) + userPassHash
let x = hexToLong(xHex)

// Calculate S value
let gPowXN = g.power(x, modulus: N)
let intVal1 = (bigB - (self.k() * gPowXN)) % N
let intVal2 = (self.a + (u * x)) % (N - 1)
let s = intVal1.power(intVal2, modulus: N)

// Compute HKDF
return computeHKDF(inputKeyMaterial: padHex(longToHex(s)), salt: padHex(longToHex(u)))
}

private func calculateU(A: BigInt, B: BigInt) -> BigInt {
let uHex = padHex(longToHex(A)) + padHex(longToHex(B))
return hexToLong(SHA256.hash(data: uHex.data(using: .utf8)!).hexEncodedString())
}

private func computeHKDF(inputKeyMaterial: String, salt: String) -> Data {
let ikm = Data(hex: inputKeyMaterial)
let saltData = Data(hex: salt)
let prk = HMAC.authenticationCode(for: ikm, using: SymmetricKey(data: saltData))
let infoBits = (INFO_BITS + "\u{01}").data(using: .utf8)!
return Data(HMAC.authenticationCode(for: infoBits, using: SymmetricKey(data: prk))).prefix(16)
}

private func k() -> BigInt {
let kHex = "00\(N_HEX)0\(G_HEX)"
return BigInt(sha256Hex(kHex), radix: 16) ?? BigInt(0)
}

static func generateRandomSmallA(N: BigInt) -> BigInt {
guard N > 1 else {
fatalError("N must be greater than 1 for random generation.")
}
return BigInt(Int.random(in: 1..  BigInt {
return g.power(a, modulus: N)
}
}

struct AuthParams {
let username: String
let password: String
let deviceKey: String
let devicePassword: String
let deviceGroupKey: String
}

extension Data {
func hexEncodedString() -> String {
return map { String(format: "%02x", $0) }.joined()
}
}

extension Sequence where Element == UInt8 {
func hexEncodedString() -> String {
return map { String(format: "%02x", $0) }.joined()
}
}

enum CognitoError: Error {
case invalidURL
case requestFailed
case unexpectedChallenge(challengeName: String)
}

func sha256Hex(_ input: String) -> String {
let data = input.data(using: .utf8)!
let digest = SHA256.hash(data: data)
return digest.map { String(format: "%02x", $0) }.joined()
}

extension Data {
init(hex: String) {
self.init(Array(hex: hex))
}
}

extension Array where Element == UInt8 {
init(hex: String) {
self = hex.compactMap { UInt8(String($0), radix: 16) }
}
}

func hexToLong(_ hex: String) -> BigInt {
return BigInt(hex, radix: 16) ?? BigInt(0)
}

func longToHex(_ number: BigInt) -> String {
return String(number, radix: 16)
}

func padHex(_ hex: String) -> String {
return hex.count % 2 == 0 ? hex : "0" + hex
}
bekannte Datei

Code: Select all

import Foundation
import CryptoKit
import BigInt

class Cognito {
private let srp: SRPAuthentication
private var accessToken: String = ""
private var refreshToken: String = ""
private var expiry: Date = Date()
private let session: URLSession
private let lock = NSLock()

init(auth: AuthParams) {
self.srp = SRPAuthentication(auth: auth)
self.session = URLSession(configuration: .default)
}

func authenticate() async throws -> String {
let userChallenge = try await userSRPAuth()

if let challengeName = userChallenge["ChallengeName"] as? String, challengeName == "PASSWORD_VERIFIER" {
print(challengeName)
} else {
print("user challenge")
throw CognitoError.unexpectedChallenge(challengeName: "VERIFIER Err")
}

let deviceAuth = try await userPasswordVerifier(challengeParams: userChallenge)

if let challengeName = deviceAuth["ChallengeName"] as? String, challengeName == "DEVICE_SRP_AUTH" {
print(challengeName)
} else {
print("device auth")
throw CognitoError.unexpectedChallenge(challengeName: "SRP_AUTH Err")
}

// TODO step 3 and 4

return "" // return access token
}

private func userSRPAuth() async throws -> [String: Any] {
return try await makeRequest(
target: "AWSCognitoIdentityProviderService.InitiateAuth",
body: [
"AuthFlow": "USER_SRP_AUTH",
"ClientId": "79k2g0t0ujq2tfchb23d5j6htk",
"AuthParameters": srp.getAuthParams(),
"ClientMetadata": [:]
]
)
}

private func userPasswordVerifier(challengeParams: [String: Any]) async throws -> [String: Any] {

let challenge_responses = srp.passwordVerifierChallenge(challengeParams: challengeParams)

return try await makeRequest(
target: "AWSCognitoIdentityProviderService.RespondToAuthChallenge",
body: [
"ChallengeName": "PASSWORD_VERIFIER",
"ClientId": "79k2g0t0ujq2tfchb23d5j6htk",
"ChallengeResponses": challenge_responses,
"ClientMetadata": [:]
]
)
}

func makeRequest(target: String, body: [String: Any]) async throws ->  [String: Any] {
guard let url = URL(string: "https://cognito-idp.us-east-1.amazonaws.com/") else {
throw CognitoError.invalidURL
}

var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue(target, forHTTPHeaderField: "X-Amz-Target")
request.addValue("application/x-amz-json-1.1", forHTTPHeaderField: "Content-Type")
request.httpBody = try JSONSerialization.data(withJSONObject: body, options: [])

let (data, response) = try await URLSession.shared.data(for: request)

if let dataString = String(data: data, encoding: .utf8) {
print("Response Data as String: \(dataString)") //Incorrect username or password
} else {
print("Unable to convert data to string.")
}

guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
throw CognitoError.requestFailed
}

do {
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
return json
} else {
throw CognitoError.requestFailed
}
} catch {
throw CognitoError.requestFailed
}
}
}

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post