From e2c717212be20413594f969359668bd42a1ae23a Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Fri, 8 Feb 2019 00:44:14 +0100 Subject: [PATCH] Key: Constant time encoding --- WireGuard/.swiftlint.yml | 3 + WireGuard/Shared/Model/Key.swift | 148 ++++++++++++++++++ .../TunnelConfiguration+WgQuickConfig.swift | 18 ++- WireGuard/WireGuard.xcodeproj/project.pbxproj | 10 ++ .../TunnelConfiguration+UapiConfig.swift | 27 +--- WireGuard/WireGuard/UI/TunnelViewModel.swift | 26 +-- .../TunnelEditTableViewController.swift | 2 +- .../TunnelEditViewController.swift | 12 +- .../PacketTunnelSettingsGenerator.swift | 23 ++- 9 files changed, 207 insertions(+), 62 deletions(-) create mode 100644 WireGuard/Shared/Model/Key.swift diff --git a/WireGuard/.swiftlint.yml b/WireGuard/.swiftlint.yml index 93c7ab3..5c66629 100644 --- a/WireGuard/.swiftlint.yml +++ b/WireGuard/.swiftlint.yml @@ -22,3 +22,6 @@ cyclomatic_complexity: error: 25 function_body_length: warning: 45 +variable_name: + min_length: + warning: 0 diff --git a/WireGuard/Shared/Model/Key.swift b/WireGuard/Shared/Model/Key.swift new file mode 100644 index 0000000..17e25a0 --- /dev/null +++ b/WireGuard/Shared/Model/Key.swift @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: MIT +// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved. + +import Foundation + +extension Data { + func isKey() -> Bool { + return self.count == 32 + } + + func hexKey() -> String? { + if self.count != 32 { + return nil + } + var nibble1, nibble2: UInt + var hex: [UInt8] = Array(repeating: 0, count: 64) + + for i in 0..<32 { + let n = UInt(self[i]) + nibble1 = 87 + (n >> 4) + nibble1 += (((UInt(bitPattern: Int(n >> 4) - 10)) >> 8) & 217) + nibble2 = 87 + (n & 0xf) + nibble2 += (((UInt(bitPattern: Int(n & 0xf) - 10)) >> 8) & 217) + hex[i * 2] = UInt8(truncatingIfNeeded: nibble1) + hex[i * 2 + 1] = UInt8(truncatingIfNeeded: nibble2) + } + return String(bytes: hex, encoding: .ascii) + } + + private func decodeHex(c: UInt8) -> (UInt8, UInt8) { + var alpha0, alpha, num0, num, val, ret: UInt8 + + num = c ^ 48 + num0 = UInt8(truncatingIfNeeded: UInt(bitPattern: Int(num) - 10) >> 8) + + alpha = UInt8(truncatingIfNeeded: Int(c & 223) - 55) + alpha0 = UInt8(truncatingIfNeeded: (UInt(bitPattern: Int(alpha) - 10) ^ UInt(bitPattern: Int(alpha) - 16)) >> 8) + + ret = UInt8(truncatingIfNeeded: UInt(bitPattern: Int(num0 | alpha0) - 1) >> 8) + val = (num0 & num) | (alpha0 & alpha) + + return (val, ret) + } + + init?(hexKey hexString: String) { + let hex = [UInt8](hexString.utf8) + if hex.count != 64 { + return nil + } + self.init(repeating: 0, count: 32) + + var ret: UInt8 = 0 + for i in stride(from: 0, to: 64, by: 2) { + var v1, v2, r: UInt8 + + (v1, r) = decodeHex(c: hex[i]) + ret |= r + + (v2, r) = decodeHex(c: hex[i + 1]) + ret |= r + + self[i / 2] = (v1 << 4) | v2 + } + + if 1 & (UInt8(truncatingIfNeeded: Int(ret) - 1) >> 8) != 0 { + return nil + } + } + + + private func encodeBase64(dest: inout ArraySlice, src: T) where T.Index == Int, T.Element == UInt8 { + let a = Int((src[src.startIndex + 0] >> 2) & 63) + let b = Int(((src[src.startIndex + 0] << 4) | (src[src.startIndex + 1] >> 4)) & 63) + let c = Int(((src[src.startIndex + 1] << 2) | (src[src.startIndex + 2] >> 6)) & 63) + let d = Int(src[src.startIndex + 2] & 63) + + for (i, x) in [a, b, c, d].enumerated() { + var y: Int = x + 65 + y += ((25 - x) >> 8) & 6 + y -= ((51 - x) >> 8) & 75 + y -= ((61 - x) >> 8) & 15 + y += ((62 - x) >> 8) & 3 + dest[dest.startIndex + i] = UInt8(y) + } + } + + func base64Key() -> String? { + if self.count != 32 { + return nil + } + var base64: [UInt8] = Array(repeating: 0, count: 44) + + for i in 0..<(32 / 3) { + encodeBase64(dest: &base64[(i * 4)..<(i * 4 + 4)], src: self[(i * 3)..<(i * 3 + 3)]) + } + encodeBase64(dest: &base64[40..<44], src: [self[30], self[31], 0]) + base64[43] = 61 + + return String(bytes: base64, encoding: .ascii) + } + + private func decodeBase64(src: T) -> Int where T.Index == Int, T.Element == UInt8 { + var val: Int = 0 + for i in 0..<4 { + let n = Int(src[src.startIndex + i]) + var a: Int = -1 + var b: Int + b = ((((65 - 1) - n) & (n - (90 + 1))) >> 8) + a += b & (n - 64) + b = ((((97 - 1) - n) & (n - (122 + 1))) >> 8) + a += b & (n - 70) + b = ((((48 - 1) - n) & (n - (57 + 1))) >> 8) + a += b & (n + 5) + b = ((((43 - 1) - n) & (n - (43 + 1))) >> 8) + a += b & 63 + b = ((((47 - 1) - n) & (n - (47 + 1))) >> 8) + a += b & 64 + val |= a << (18 - 6 * i) + } + return val + } + + init?(base64Key base64String: String) { + let base64 = [UInt8](base64String.utf8) + if base64.count != 44 || base64[43] != 61 { + return nil + } + self.init(repeating: 0, count: 32) + + var ret: UInt8 = 0 + var val: Int + for i in 0..<(32/3) { + val = decodeBase64(src: base64[(i * 4)..<(i * 4 + 4)]) + ret |= UInt8(UInt32(val) >> UInt32(31)) + self[i * 3 + 0] = UInt8((val >> 16) & 0xff) + self[i * 3 + 1] = UInt8((val >> 8) & 0xff) + self[i * 3 + 2] = UInt8(val & 0xff) + } + val = decodeBase64(src: [base64[40], base64[41], base64[42], 65]) + ret |= UInt8((UInt32(val) >> 31) | UInt32(val & 0xff)) + self[30] = UInt8((val >> 16) & 0xff) + self[31] = UInt8((val >> 8) & 0xff) + + if 1 & (UInt8(truncatingIfNeeded: Int(ret) - 1) >> 8) != 0 { + return nil + } + } +} diff --git a/WireGuard/Shared/Model/TunnelConfiguration+WgQuickConfig.swift b/WireGuard/Shared/Model/TunnelConfiguration+WgQuickConfig.swift index fa32de2..b3f5198 100644 --- a/WireGuard/Shared/Model/TunnelConfiguration+WgQuickConfig.swift +++ b/WireGuard/Shared/Model/TunnelConfiguration+WgQuickConfig.swift @@ -126,7 +126,9 @@ extension TunnelConfiguration { func asWgQuickConfig() -> String { var output = "[Interface]\n" - output.append("PrivateKey = \(interface.privateKey.base64EncodedString())\n") + if let privateKey = interface.privateKey.base64Key() { + output.append("PrivateKey = \(privateKey)\n") + } if let listenPort = interface.listenPort { output.append("ListenPort = \(listenPort)\n") } @@ -144,9 +146,11 @@ extension TunnelConfiguration { for peer in peers { output.append("\n[Peer]\n") - output.append("PublicKey = \(peer.publicKey.base64EncodedString())\n") - if let preSharedKey = peer.preSharedKey { - output.append("PresharedKey = \(preSharedKey.base64EncodedString())\n") + if let publicKey = peer.publicKey.base64Key() { + output.append("PublicKey = \(publicKey)\n") + } + if let preSharedKey = peer.preSharedKey?.base64Key { + output.append("PresharedKey = \(preSharedKey)\n") } if !peer.allowedIPs.isEmpty { let allowedIPsString = peer.allowedIPs.map { $0.stringRepresentation }.joined(separator: ", ") @@ -168,7 +172,7 @@ extension TunnelConfiguration { guard let privateKeyString = attributes["privatekey"] else { throw ParseError.interfaceHasNoPrivateKey } - guard let privateKey = Data(base64Encoded: privateKeyString), privateKey.count == TunnelConfiguration.keyLength else { + guard let privateKey = Data(base64Key: privateKeyString), privateKey.count == TunnelConfiguration.keyLength else { throw ParseError.interfaceHasInvalidPrivateKey(privateKeyString) } var interface = InterfaceConfiguration(privateKey: privateKey) @@ -212,12 +216,12 @@ extension TunnelConfiguration { guard let publicKeyString = attributes["publickey"] else { throw ParseError.peerHasNoPublicKey } - guard let publicKey = Data(base64Encoded: publicKeyString), publicKey.count == TunnelConfiguration.keyLength else { + guard let publicKey = Data(base64Key: publicKeyString), publicKey.count == TunnelConfiguration.keyLength else { throw ParseError.peerHasInvalidPublicKey(publicKeyString) } var peer = PeerConfiguration(publicKey: publicKey) if let preSharedKeyString = attributes["presharedkey"] { - guard let preSharedKey = Data(base64Encoded: preSharedKeyString), preSharedKey.count == TunnelConfiguration.keyLength else { + guard let preSharedKey = Data(base64Key: preSharedKeyString), preSharedKey.count == TunnelConfiguration.keyLength else { throw ParseError.peerHasInvalidPreSharedKey(preSharedKeyString) } peer.preSharedKey = preSharedKey diff --git a/WireGuard/WireGuard.xcodeproj/project.pbxproj b/WireGuard/WireGuard.xcodeproj/project.pbxproj index 351d1f6..b0034cb 100644 --- a/WireGuard/WireGuard.xcodeproj/project.pbxproj +++ b/WireGuard/WireGuard.xcodeproj/project.pbxproj @@ -29,6 +29,10 @@ 5FF7B96521CC95FA00A7DD74 /* PeerConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FF7B96421CC95FA00A7DD74 /* PeerConfiguration.swift */; }; 5FF7B96621CC95FA00A7DD74 /* PeerConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FF7B96421CC95FA00A7DD74 /* PeerConfiguration.swift */; }; 6B586C51220CACB600427C51 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6FF4AC462120B9E0002C96EB /* NetworkExtension.framework */; }; + 6B586C53220CBA6D00427C51 /* Key.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B586C52220CBA6D00427C51 /* Key.swift */; }; + 6B586C54220CBA6D00427C51 /* Key.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B586C52220CBA6D00427C51 /* Key.swift */; }; + 6B586C55220CBA6D00427C51 /* Key.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B586C52220CBA6D00427C51 /* Key.swift */; }; + 6B586C56220CBA6D00427C51 /* Key.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B586C52220CBA6D00427C51 /* Key.swift */; }; 6B5C5E27220A48D30024272E /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B5C5E26220A48D30024272E /* Keychain.swift */; }; 6B5C5E28220A48D30024272E /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B5C5E26220A48D30024272E /* Keychain.swift */; }; 6B5C5E29220A48D30024272E /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B5C5E26220A48D30024272E /* Keychain.swift */; }; @@ -240,6 +244,7 @@ 5F9696AF21CD7128008063FE /* TunnelConfiguration+WgQuickConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TunnelConfiguration+WgQuickConfig.swift"; sourceTree = ""; }; 5FF7B96121CC95DE00A7DD74 /* InterfaceConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterfaceConfiguration.swift; sourceTree = ""; }; 5FF7B96421CC95FA00A7DD74 /* PeerConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeerConfiguration.swift; sourceTree = ""; }; + 6B586C52220CBA6D00427C51 /* Key.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Key.swift; sourceTree = ""; }; 6B5C5E26220A48D30024272E /* Keychain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Keychain.swift; sourceTree = ""; }; 6B62E45E220A6FA900EF34A6 /* PrivateDataConfirmation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivateDataConfirmation.swift; sourceTree = ""; }; 6B707D8321F918D4000A8F73 /* TunnelConfiguration+UapiConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TunnelConfiguration+UapiConfig.swift"; sourceTree = ""; }; @@ -488,6 +493,7 @@ 6F628C3E217F3413003482A3 /* DNSServer.swift */, 5FF7B96121CC95DE00A7DD74 /* InterfaceConfiguration.swift */, 5FF7B96421CC95FA00A7DD74 /* PeerConfiguration.swift */, + 6B586C52220CBA6D00427C51 /* Key.swift */, ); path = Model; sourceTree = ""; @@ -1087,6 +1093,7 @@ 5FF7B96621CC95FA00A7DD74 /* PeerConfiguration.swift in Sources */, 5F9696AE21CD6F72008063FE /* String+ArrayConversion.swift in Sources */, 6FFA5D8F2194370D0001E2F7 /* IPAddressRange.swift in Sources */, + 6B586C54220CBA6D00427C51 /* Key.swift in Sources */, 6FFA5D902194370D0001E2F7 /* Endpoint.swift in Sources */, 5FF7B96321CC95DE00A7DD74 /* InterfaceConfiguration.swift in Sources */, 6FFA5D9321943BC90001E2F7 /* DNSResolver.swift in Sources */, @@ -1129,6 +1136,7 @@ 6FCD99B121E0EDA900BA4C82 /* TunnelEditViewController.swift in Sources */, 6FB1BDCA21D50F1700A991BF /* x25519.c in Sources */, 6FB1BDCB21D50F1700A991BF /* Curve25519.swift in Sources */, + 6B586C55220CBA6D00427C51 /* Key.swift in Sources */, 6F9B582921E8D6D100544D02 /* PopupRow.swift in Sources */, 6FB1BDBB21D50F0200A991BF /* Localizable.strings in Sources */, 6FB1BDBC21D50F0200A991BF /* ringlogger.c in Sources */, @@ -1175,6 +1183,7 @@ 6FB1BDA621D4F53300A991BF /* NETunnelProviderProtocol+Extension.swift in Sources */, 6FB1BDA721D4F53300A991BF /* String+ArrayConversion.swift in Sources */, 6FB1BDA921D4F53300A991BF /* TunnelConfiguration.swift in Sources */, + 6B586C56220CBA6D00427C51 /* Key.swift in Sources */, 6FB1BDAA21D4F53300A991BF /* IPAddressRange.swift in Sources */, 6FB1BDAB21D4F53300A991BF /* Endpoint.swift in Sources */, 6FB1BDAC21D4F53300A991BF /* DNSServer.swift in Sources */, @@ -1196,6 +1205,7 @@ 5F45417D21C1B23600994C13 /* UITableViewCell+Reuse.swift in Sources */, 5F45419221C2D55800994C13 /* CheckmarkCell.swift in Sources */, 6FE254FF219C60290028284D /* ZipExporter.swift in Sources */, + 6B586C53220CBA6D00427C51 /* Key.swift in Sources */, 6F693A562179E556008551C1 /* Endpoint.swift in Sources */, 6FDEF7E62185EFB200D8FBF6 /* QRScanViewController.swift in Sources */, 6FFA5D952194454A0001E2F7 /* NETunnelProviderProtocol+Extension.swift in Sources */, diff --git a/WireGuard/WireGuard/Tunnel/TunnelConfiguration+UapiConfig.swift b/WireGuard/WireGuard/Tunnel/TunnelConfiguration+UapiConfig.swift index 63a8570..b72223d 100644 --- a/WireGuard/WireGuard/Tunnel/TunnelConfiguration+UapiConfig.swift +++ b/WireGuard/WireGuard/Tunnel/TunnelConfiguration+UapiConfig.swift @@ -88,7 +88,7 @@ extension TunnelConfiguration { guard let privateKeyString = attributes["private_key"] else { throw ParseError.interfaceHasNoPrivateKey } - guard let privateKey = Data(hexEncoded: privateKeyString), privateKey.count == TunnelConfiguration.keyLength else { + guard let privateKey = Data(hexKey: privateKeyString), privateKey.count == TunnelConfiguration.keyLength else { throw ParseError.interfaceHasInvalidPrivateKey(privateKeyString) } var interface = InterfaceConfiguration(privateKey: privateKey) @@ -108,12 +108,12 @@ extension TunnelConfiguration { guard let publicKeyString = attributes["public_key"] else { throw ParseError.peerHasNoPublicKey } - guard let publicKey = Data(hexEncoded: publicKeyString), publicKey.count == TunnelConfiguration.keyLength else { + guard let publicKey = Data(hexKey: publicKeyString), publicKey.count == TunnelConfiguration.keyLength else { throw ParseError.peerHasInvalidPublicKey(publicKeyString) } var peer = PeerConfiguration(publicKey: publicKey) if let preSharedKeyString = attributes["preshared_key"] { - guard let preSharedKey = Data(hexEncoded: preSharedKeyString), preSharedKey.count == TunnelConfiguration.keyLength else { + guard let preSharedKey = Data(hexKey: preSharedKeyString), preSharedKey.count == TunnelConfiguration.keyLength else { throw ParseError.peerHasInvalidPreSharedKey(preSharedKeyString) } // TODO(zx2c4): does the compiler optimize this away? @@ -184,24 +184,3 @@ extension TunnelConfiguration { return peer } } - -extension Data { - //swiftlint:disable identifier_name - init?(hexEncoded hexString: String) { - if hexString.count % 2 != 0 { - return nil - } - let len = hexString.count / 2 - self.init(capacity: len) - for i in 0.. [InterfaceField: String] { var scratchpad = [InterfaceField: String]() scratchpad[.name] = name - scratchpad[.privateKey] = config.privateKey.base64EncodedString() - scratchpad[.publicKey] = config.publicKey.base64EncodedString() + scratchpad[.privateKey] = config.privateKey.base64Key() ?? "" + scratchpad[.publicKey] = config.publicKey.base64Key() ?? "" if !config.addresses.isEmpty { scratchpad[.addresses] = config.addresses.map { $0.stringRepresentation }.joined(separator: ", ") } @@ -155,7 +155,7 @@ class TunnelViewModel { fieldsWithError.insert(.privateKey) return .error(tr("alertInvalidInterfaceMessagePrivateKeyRequired")) } - guard let privateKey = Data(base64Encoded: privateKeyString), privateKey.count == TunnelConfiguration.keyLength else { + guard let privateKey = Data(base64Key: privateKeyString), privateKey.count == TunnelConfiguration.keyLength else { fieldsWithError.insert(.privateKey) return .error(tr("alertInvalidInterfaceMessagePrivateKeyInvalid")) } @@ -255,7 +255,7 @@ class TunnelViewModel { return validatedConfiguration.publicKey } if let scratchPadPublicKey = scratchpad[.publicKey] { - return Data(base64Encoded: scratchPadPublicKey) + return Data(base64Key: scratchPadPublicKey) } return nil } @@ -300,9 +300,11 @@ class TunnelViewModel { private static func createScratchPad(from config: PeerConfiguration) -> [PeerField: String] { var scratchpad = [PeerField: String]() - scratchpad[.publicKey] = config.publicKey.base64EncodedString() - if let preSharedKey = config.preSharedKey { - scratchpad[.preSharedKey] = preSharedKey.base64EncodedString() + if let publicKey = config.publicKey.base64Key() { + scratchpad[.publicKey] = publicKey + } + if let preSharedKey = config.preSharedKey?.base64Key() { + scratchpad[.preSharedKey] = preSharedKey } if !config.allowedIPs.isEmpty { scratchpad[.allowedIPs] = config.allowedIPs.map { $0.stringRepresentation }.joined(separator: ", ") @@ -335,14 +337,14 @@ class TunnelViewModel { fieldsWithError.insert(.publicKey) return .error(tr("alertInvalidPeerMessagePublicKeyRequired")) } - guard let publicKey = Data(base64Encoded: publicKeyString), publicKey.count == TunnelConfiguration.keyLength else { + guard let publicKey = Data(base64Key: publicKeyString), publicKey.count == TunnelConfiguration.keyLength else { fieldsWithError.insert(.publicKey) return .error(tr("alertInvalidPeerMessagePublicKeyInvalid")) } var config = PeerConfiguration(publicKey: publicKey) var errorMessages = [String]() if let preSharedKeyString = scratchpad[.preSharedKey] { - if let preSharedKey = Data(base64Encoded: preSharedKeyString), preSharedKey.count == TunnelConfiguration.keyLength { + if let preSharedKey = Data(base64Key: preSharedKeyString), preSharedKey.count == TunnelConfiguration.keyLength { config.preSharedKey = preSharedKey } else { fieldsWithError.insert(.preSharedKey) diff --git a/WireGuard/WireGuard/UI/iOS/ViewController/TunnelEditTableViewController.swift b/WireGuard/WireGuard/UI/iOS/ViewController/TunnelEditTableViewController.swift index f4bf157..01fed49 100644 --- a/WireGuard/WireGuard/UI/iOS/ViewController/TunnelEditTableViewController.swift +++ b/WireGuard/WireGuard/UI/iOS/ViewController/TunnelEditTableViewController.swift @@ -213,7 +213,7 @@ extension TunnelEditTableViewController { cell.onTapped = { [weak self] in guard let self = self else { return } - self.tunnelViewModel.interfaceData[.privateKey] = Curve25519.generatePrivateKey().base64EncodedString() + self.tunnelViewModel.interfaceData[.privateKey] = Curve25519.generatePrivateKey().base64Key() ?? "" if let privateKeyRow = self.interfaceFieldsBySection[indexPath.section].firstIndex(of: .privateKey), let publicKeyRow = self.interfaceFieldsBySection[indexPath.section].firstIndex(of: .publicKey) { let privateKeyIndex = IndexPath(row: privateKeyRow, section: indexPath.section) diff --git a/WireGuard/WireGuard/UI/macOS/ViewController/TunnelEditViewController.swift b/WireGuard/WireGuard/UI/macOS/ViewController/TunnelEditViewController.swift index 27d60c7..395eeb4 100644 --- a/WireGuard/WireGuard/UI/macOS/ViewController/TunnelEditViewController.swift +++ b/WireGuard/WireGuard/UI/macOS/ViewController/TunnelEditViewController.swift @@ -104,8 +104,8 @@ class TunnelEditViewController: NSViewController { let tunnelConfiguration = tunnel.tunnelConfiguration! nameRow.value = tunnel.name textView.string = tunnelConfiguration.asWgQuickConfig() - publicKeyRow.value = tunnelConfiguration.interface.publicKey.base64EncodedString() - textView.privateKeyString = tunnelConfiguration.interface.privateKey.base64EncodedString() + publicKeyRow.value = tunnelConfiguration.interface.publicKey.base64Key() ?? "" + textView.privateKeyString = tunnelConfiguration.interface.privateKey.base64Key() ?? "" if tunnel.activateOnDemandSetting.isActivateOnDemandEnabled { selectedActivateOnDemandOption = tunnel.activateOnDemandSetting.activateOnDemandOption } else { @@ -115,17 +115,17 @@ class TunnelEditViewController: NSViewController { // Creating a new tunnel let privateKey = Curve25519.generatePrivateKey() let publicKey = Curve25519.generatePublicKey(fromPrivateKey: privateKey) - let bootstrappingText = "[Interface]\nPrivateKey = \(privateKey.base64EncodedString())\n" - publicKeyRow.value = publicKey.base64EncodedString() + let bootstrappingText = "[Interface]\nPrivateKey = \(privateKey.base64Key() ?? "")\n" + publicKeyRow.value = publicKey.base64Key() ?? "" textView.string = bootstrappingText selectedActivateOnDemandOption = .none } privateKeyObservationToken = textView.observe(\.privateKeyString) { [weak publicKeyRow] textView, _ in if let privateKeyString = textView.privateKeyString, - let privateKey = Data(base64Encoded: privateKeyString), + let privateKey = Data(base64Key: privateKeyString), privateKey.count == TunnelConfiguration.keyLength { let publicKey = Curve25519.generatePublicKey(fromPrivateKey: privateKey) - publicKeyRow?.value = publicKey.base64EncodedString() + publicKeyRow?.value = publicKey.base64Key() ?? "" } else { publicKeyRow?.value = "" } diff --git a/WireGuard/WireGuardNetworkExtension/PacketTunnelSettingsGenerator.swift b/WireGuard/WireGuardNetworkExtension/PacketTunnelSettingsGenerator.swift index 02588c3..a4ff7dd 100644 --- a/WireGuard/WireGuardNetworkExtension/PacketTunnelSettingsGenerator.swift +++ b/WireGuard/WireGuardNetworkExtension/PacketTunnelSettingsGenerator.swift @@ -17,7 +17,9 @@ class PacketTunnelSettingsGenerator { func endpointUapiConfiguration() -> String { var wgSettings = "" for (index, peer) in tunnelConfiguration.peers.enumerated() { - wgSettings.append("public_key=\(peer.publicKey.hexEncodedString())\n") + if let publicKey = peer.publicKey.hexKey() { + wgSettings.append("public_key=\(publicKey)\n") + } if let endpoint = resolvedEndpoints[index]?.withReresolvedIP() { if case .name(_, _) = endpoint.host { assert(false, "Endpoint is not resolved") } wgSettings.append("endpoint=\(endpoint.stringRepresentation)\n") @@ -28,8 +30,9 @@ class PacketTunnelSettingsGenerator { func uapiConfiguration() -> String { var wgSettings = "" - let privateKey = tunnelConfiguration.interface.privateKey.hexEncodedString() - wgSettings.append("private_key=\(privateKey)\n") + if let privateKey = tunnelConfiguration.interface.privateKey.hexKey() { + wgSettings.append("private_key=\(privateKey)\n") + } if let listenPort = tunnelConfiguration.interface.listenPort { wgSettings.append("listen_port=\(listenPort)\n") } @@ -38,9 +41,11 @@ class PacketTunnelSettingsGenerator { } assert(tunnelConfiguration.peers.count == resolvedEndpoints.count) for (index, peer) in tunnelConfiguration.peers.enumerated() { - wgSettings.append("public_key=\(peer.publicKey.hexEncodedString())\n") - if let preSharedKey = peer.preSharedKey { - wgSettings.append("preshared_key=\(preSharedKey.hexEncodedString())\n") + if let publicKey = peer.publicKey.hexKey() { + wgSettings.append("public_key=\(publicKey)\n") + } + if let preSharedKey = peer.preSharedKey?.hexKey() { + wgSettings.append("preshared_key=\(preSharedKey)\n") } if let endpoint = resolvedEndpoints[index]?.withReresolvedIP() { if case .name(_, _) = endpoint.host { assert(false, "Endpoint is not resolved") } @@ -149,9 +154,3 @@ class PacketTunnelSettingsGenerator { return (ipv4IncludedRoutes, ipv6IncludedRoutes) } } - -private extension Data { - func hexEncodedString() -> String { - return self.map { String(format: "%02x", $0) }.joined() - } -}