mirror of https://github.com/oxen-io/session-ios
				
				
				
			
			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.
		
		
		
		
		
			
		
			
				
	
	
		
			85 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			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()
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |