// // EncryptionProxy.swift // TunnelKit // // Created by Davide De Rosa on 2/8/17. // Copyright © 2018 London Trust Media. All rights reserved. // import Foundation import __TunnelKitNative /// Bridges native encryption for high-level operations. public class EncryptionProxy { private static let maxHmacLength = 100 private let box: CryptoBox /** Initializes the PRNG. Must be issued before using `SessionProxy`. - Parameter seedLength: The length in bytes of the pseudorandom seed that will feed the PRNG. */ public static func prepareRandomNumberGenerator(seedLength: Int) -> Bool { let seed: ZeroingData do { seed = try SecureRandom.safeData(length: seedLength) } catch { return false } return CryptoBox.preparePRNG(withSeed: seed.bytes, length: seed.count) } // Ruby: keys_prf private static func keysPRF( _ label: String, _ secret: ZeroingData, _ clientSeed: ZeroingData, _ serverSeed: ZeroingData, _ clientSessionId: Data?, _ serverSessionId: Data?, _ size: Int) throws -> ZeroingData { let seed = Z(label) seed.append(clientSeed) seed.append(serverSeed) if let csi = clientSessionId { seed.append(Z(csi)) } if let ssi = serverSessionId { seed.append(Z(ssi)) } let len = secret.count / 2 let lenx = len + (secret.count & 1) let secret1 = secret.withOffset(0, count: lenx) let secret2 = secret.withOffset(len, count: lenx) let hash1 = try keysHash("md5", secret1, seed, size) let hash2 = try keysHash("sha1", secret2, seed, size) let prf = Z() for i in 0.. ZeroingData { let out = Z() let buffer = Z(count: EncryptionProxy.maxHmacLength) var chain = try EncryptionProxy.hmac(buffer, digestName, secret, seed) while (out.count < size) { out.append(try EncryptionProxy.hmac(buffer, digestName, secret, chain.appending(seed))) chain = try EncryptionProxy.hmac(buffer, digestName, secret, chain) } return out.withOffset(0, count: size) } // Ruby: hmac private static func hmac(_ buffer: ZeroingData, _ digestName: String, _ secret: ZeroingData, _ data: ZeroingData) throws -> ZeroingData { var length = 0 try CryptoBox.hmac( withDigestName: digestName, secret: secret.bytes, secretLength: secret.count, data: data.bytes, dataLength: data.count, hmac: buffer.mutableBytes, hmacLength: &length ) return buffer.withOffset(0, count: length) } convenience init(_ cipher: String, _ digest: String, _ auth: Authenticator, _ sessionId: Data, _ remoteSessionId: Data) throws { guard let serverRandom1 = auth.serverRandom1, let serverRandom2 = auth.serverRandom2 else { fatalError("Configuring encryption without server randoms") } let masterData = try EncryptionProxy.keysPRF( CoreConfiguration.label1, auth.preMaster, auth.random1, serverRandom1, nil, nil, CoreConfiguration.preMasterLength ) let keysData = try EncryptionProxy.keysPRF( CoreConfiguration.label2, masterData, auth.random2, serverRandom2, sessionId, remoteSessionId, CoreConfiguration.keysCount * CoreConfiguration.keyLength ) var keysArray = [ZeroingData]() for i in 0.. DataPathEncrypter { return box.encrypter().dataPathEncrypter() } func decrypter() -> DataPathDecrypter { return box.decrypter().dataPathDecrypter() } }