You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
session-ios/SessionSnodeKit/Models/ONSResolveResponse.swift

85 lines
3.2 KiB
Swift

// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import Foundation
import Sodium
import SessionUtilitiesKit
extension SnodeAPI {
public class ONSResolveResponse: SnodeResponse {
private struct Result: Codable {
enum CodingKeys: String, CodingKey {
case nonce
case encryptedValue = "encrypted_value"
}
fileprivate let nonce: String?
fileprivate let encryptedValue: String
}
enum CodingKeys: String, CodingKey {
case result
}
private let result: Result
// MARK: - Initialization
required init(from decoder: Decoder) throws {
let container: KeyedDecodingContainer<CodingKeys> = try decoder.container(keyedBy: CodingKeys.self)
result = try container.decode(Result.self, forKey: .result)
try super.init(from: decoder)
}
// MARK: - Convenience
func sessionId(sodium: Sodium, nameBytes: [UInt8], nameHashBytes: [UInt8]) throws -> String {
let ciphertext: [UInt8] = Data(hex: result.encryptedValue).bytes
// Handle old Argon2-based encryption used before HF16
guard let hexEncodedNonce: String = result.nonce else {
let salt: [UInt8] = Data(repeating: 0, count: sodium.pwHash.SaltBytes).bytes
guard
let key: [UInt8] = sodium.pwHash.hash(
outputLength: sodium.secretBox.KeyBytes,
passwd: nameBytes,
salt: salt,
opsLimit: sodium.pwHash.OpsLimitModerate,
memLimit: sodium.pwHash.MemLimitModerate,
alg: .Argon2ID13
)
else { throw SnodeAPIError.hashingFailed }
let nonce: [UInt8] = Data(repeating: 0, count: sodium.secretBox.NonceBytes).bytes
guard let sessionIdAsData: [UInt8] = sodium.secretBox.open(authenticatedCipherText: ciphertext, secretKey: key, nonce: nonce) else {
throw SnodeAPIError.decryptionFailed
}
return sessionIdAsData.toHexString()
}
let nonceBytes: [UInt8] = Data(hex: hexEncodedNonce).bytes
// xchacha-based encryption
// key = H(name, key=H(name))
guard let key: [UInt8] = sodium.genericHash.hash(message: nameBytes, key: nameHashBytes) else {
throw SnodeAPIError.hashingFailed
}
guard
// Should always be equal in practice
ciphertext.count >= (SessionId.byteCount + sodium.aead.xchacha20poly1305ietf.ABytes),
let sessionIdAsData = sodium.aead.xchacha20poly1305ietf.decrypt(
authenticatedCipherText: ciphertext,
secretKey: key,
nonce: nonceBytes
)
else { throw SnodeAPIError.decryptionFailed }
return sessionIdAsData.toHexString()
}
}
}