125 lines
5.0 KiB
Swift
125 lines
5.0 KiB
Swift
//
|
|
// Copyright Amazon.com Inc. or its affiliates.
|
|
// All Rights Reserved.
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
|
|
import Foundation
|
|
import AmplifySRP
|
|
import AmplifyBigInteger
|
|
|
|
struct AmplifySRPClient: SRPClientBehavior {
|
|
|
|
let commonState: SRPCommonState
|
|
let client: SRPClientState
|
|
|
|
init(NHexValue: String, gHexValue: String) throws {
|
|
guard let N = BigInt(NHexValue, radix: 16),
|
|
let g = BigInt(gHexValue, radix: 16)
|
|
else {
|
|
throw SRPError.numberConversion
|
|
}
|
|
self.commonState = SRPCommonState(prime: N, generator: g)
|
|
self.client = SRPClientState(commonState: commonState)
|
|
}
|
|
|
|
var kHexValue: String {
|
|
commonState.k.asString(radix: 16)
|
|
}
|
|
|
|
func generateClientKeyPair() -> SRPKeys {
|
|
let publicHexValue = client.publicA.asString(radix: 16)
|
|
let privateHexValue = client.privateA.asString(radix: 16)
|
|
let srpKeys = SRPKeys(publicKeyHexValue: publicHexValue,
|
|
privateKeyHexValue: privateHexValue)
|
|
return srpKeys
|
|
}
|
|
|
|
func calculateSharedSecret(username: String,
|
|
password: String,
|
|
saltHexValue: String,
|
|
clientPrivateKeyHexValue: String,
|
|
clientPublicKeyHexValue: String,
|
|
serverPublicKeyHexValue: String) throws -> String {
|
|
guard let clientPublicNum = BigInt(clientPublicKeyHexValue, radix: 16) else {
|
|
throw SRPError.numberConversion
|
|
}
|
|
guard let clientPrivateNum = BigInt(clientPrivateKeyHexValue, radix: 16) else {
|
|
throw SRPError.numberConversion
|
|
}
|
|
guard let saltNum = BigInt(saltHexValue, radix: 16) else {
|
|
throw SRPError.numberConversion
|
|
}
|
|
guard let serverPublicKeyNum = BigInt(serverPublicKeyHexValue, radix: 16) else {
|
|
throw SRPError.numberConversion
|
|
}
|
|
guard serverPublicKeyNum % commonState.prime != BigInt(0) else {
|
|
throw SRPError.illegalParameter
|
|
}
|
|
let sharedSecret = SRPClientState.calculateSessionKey(username: username,
|
|
password: password,
|
|
publicClientKey: clientPublicNum,
|
|
privateClientKey: clientPrivateNum,
|
|
publicServerKey: serverPublicKeyNum,
|
|
salt: saltNum,
|
|
commonState: commonState)
|
|
return sharedSecret.asString(radix: 16)
|
|
}
|
|
|
|
static func calculateUHexValue(clientPublicKeyHexValue: String,
|
|
serverPublicKeyHexValue: String) throws -> String {
|
|
guard let clientPublicNum = BigInt(clientPublicKeyHexValue, radix: 16) else {
|
|
throw SRPError.numberConversion
|
|
}
|
|
guard let serverPublicNum = BigInt(serverPublicKeyHexValue, radix: 16) else {
|
|
throw SRPError.numberConversion
|
|
}
|
|
let signedClientPublicKey = AmplifyBigIntHelper.getSignedData(num: clientPublicNum)
|
|
let signedServerPublicKey = AmplifyBigIntHelper.getSignedData(num: serverPublicNum)
|
|
|
|
let u = SRPClientState.calculcateU(publicClientKey: signedClientPublicKey,
|
|
publicServerKey: signedServerPublicKey)
|
|
|
|
return u.asString(radix: 16)
|
|
}
|
|
|
|
static func generateAuthenticationKey(sharedSecretHexValue: String, uHexValue: String) throws -> Data {
|
|
guard let sharedSecretNum = BigInt(sharedSecretHexValue, radix: 16) else {
|
|
throw SRPError.numberConversion
|
|
}
|
|
guard let uNum = BigInt(uHexValue, radix: 16) else {
|
|
throw SRPError.numberConversion
|
|
}
|
|
let keyingMaterial = AmplifyBigIntHelper.getSignedData(num: sharedSecretNum)
|
|
let salt = AmplifyBigIntHelper.getSignedData(num: uNum)
|
|
|
|
let authenticationkey = HMACKeyDerivationFunction.generateDerivedKey(
|
|
keyingMaterial: Data(keyingMaterial),
|
|
salt: Data(salt),
|
|
info: "Caldera Derived Key",
|
|
outputLength: 16)
|
|
return authenticationkey
|
|
}
|
|
|
|
func generateDevicePasswordVerifier(
|
|
deviceGroupKey: String,
|
|
deviceKey: String,
|
|
password: String) -> (salt: Data, passwordVerifier: Data) {
|
|
|
|
let passwordVerifier = SRPClientState.calculateDevicePasswordVerifier(
|
|
deviceGroupKey: deviceGroupKey,
|
|
deviceKey: deviceKey,
|
|
password: password,
|
|
commonState: commonState)
|
|
|
|
let verifierData = Data(AmplifyBigIntHelper.getSignedData(
|
|
num: passwordVerifier.passwordVerifier))
|
|
let saltData = Data(AmplifyBigIntHelper.getSignedData(
|
|
num: passwordVerifier.salt))
|
|
|
|
return (saltData, verifierData)
|
|
}
|
|
|
|
}
|