]> git.ipfire.org Git - thirdparty/wireguard-apple.git/commitdiff
WireGuardKit: Add wrappers for PrivateKey, PublicKey, PreSharedKey
authorAndrej Mihajlov <and@mullvad.net>
Thu, 26 Nov 2020 16:23:50 +0000 (17:23 +0100)
committerAndrej Mihajlov <and@mullvad.net>
Wed, 2 Dec 2020 10:08:09 +0000 (11:08 +0100)
Signed-off-by: Andrej Mihajlov <and@mullvad.net>
21 files changed:
WireGuard/Shared/Model/TunnelConfiguration+WgQuickConfig.swift
WireGuard/WireGuard.xcodeproj/project.pbxproj
WireGuard/WireGuard/Crypto/Curve25519.swift [deleted file]
WireGuard/WireGuard/Tunnel/MockTunnels.swift
WireGuard/WireGuard/Tunnel/TunnelConfiguration+UapiConfig.swift
WireGuard/WireGuard/UI/TunnelViewModel.swift
WireGuard/WireGuard/UI/iOS/ViewController/TunnelEditTableViewController.swift
WireGuard/WireGuard/UI/macOS/ViewController/TunnelEditViewController.swift
WireGuard/WireGuard/WireGuard-Bridging-Header.h
WireGuard/WireGuard/ZipArchive/ZipArchive.swift
WireGuardKit/Sources/WireGuardKit/Data+KeyEncoding.swift [deleted file]
WireGuardKit/Sources/WireGuardKit/InterfaceConfiguration.swift
WireGuardKit/Sources/WireGuardKit/PacketTunnelSettingsGenerator.swift
WireGuardKit/Sources/WireGuardKit/PeerConfiguration.swift
WireGuardKit/Sources/WireGuardKit/PrivateKey.swift [new file with mode: 0644]
WireGuardKit/Sources/WireGuardKit/TunnelConfiguration.swift
WireGuardKit/Sources/WireGuardKitCTarget/include/WireGuardKitCTarget.h
WireGuardKit/Sources/WireGuardKitCTarget/key.c
WireGuardKit/Sources/WireGuardKitCTarget/key.h
WireGuardKit/Sources/WireGuardKitCTarget/x25519.c [moved from WireGuard/WireGuard/Crypto/x25519.c with 100% similarity]
WireGuardKit/Sources/WireGuardKitCTarget/x25519.h [moved from WireGuard/WireGuard/Crypto/x25519.h with 100% similarity]

index d0c87e0b41c6bf37c7cb3a63010e9757ea1529e5..7fd65d62ae74f4ce22e6f72c13cb80d6d02c884d 100644 (file)
@@ -112,7 +112,7 @@ extension TunnelConfiguration {
         }
 
         let peerPublicKeysArray = peerConfigurations.map { $0.publicKey }
-        let peerPublicKeysSet = Set<Data>(peerPublicKeysArray)
+        let peerPublicKeysSet = Set<PublicKey>(peerPublicKeysArray)
         if peerPublicKeysArray.count != peerPublicKeysSet.count {
             throw ParseError.multiplePeersWithSamePublicKey
         }
@@ -126,9 +126,7 @@ extension TunnelConfiguration {
 
     func asWgQuickConfig() -> String {
         var output = "[Interface]\n"
-        if let privateKey = interface.privateKey.base64Key() {
-            output.append("PrivateKey = \(privateKey)\n")
-        }
+        output.append("PrivateKey = \(interface.privateKey.base64Key)\n")
         if let listenPort = interface.listenPort {
             output.append("ListenPort = \(listenPort)\n")
         }
@@ -146,10 +144,8 @@ extension TunnelConfiguration {
 
         for peer in peers {
             output.append("\n[Peer]\n")
-            if let publicKey = peer.publicKey.base64Key() {
-                output.append("PublicKey = \(publicKey)\n")
-            }
-            if let preSharedKey = peer.preSharedKey?.base64Key() {
+            output.append("PublicKey = \(peer.publicKey.base64Key)\n")
+            if let preSharedKey = peer.preSharedKey?.base64Key {
                 output.append("PresharedKey = \(preSharedKey)\n")
             }
             if !peer.allowedIPs.isEmpty {
@@ -171,7 +167,7 @@ extension TunnelConfiguration {
         guard let privateKeyString = attributes["privatekey"] else {
             throw ParseError.interfaceHasNoPrivateKey
         }
-        guard let privateKey = Data(base64Key: privateKeyString), privateKey.count == TunnelConfiguration.keyLength else {
+        guard let privateKey = PrivateKey(base64Key: privateKeyString) else {
             throw ParseError.interfaceHasInvalidPrivateKey(privateKeyString)
         }
         var interface = InterfaceConfiguration(privateKey: privateKey)
@@ -214,12 +210,12 @@ extension TunnelConfiguration {
         guard let publicKeyString = attributes["publickey"] else {
             throw ParseError.peerHasNoPublicKey
         }
-        guard let publicKey = Data(base64Key: publicKeyString), publicKey.count == TunnelConfiguration.keyLength else {
+        guard let publicKey = PublicKey(base64Key: publicKeyString) else {
             throw ParseError.peerHasInvalidPublicKey(publicKeyString)
         }
         var peer = PeerConfiguration(publicKey: publicKey)
         if let preSharedKeyString = attributes["presharedkey"] {
-            guard let preSharedKey = Data(base64Key: preSharedKeyString), preSharedKey.count == TunnelConfiguration.keyLength else {
+            guard let preSharedKey = PreSharedKey(base64Key: preSharedKeyString) else {
                 throw ParseError.peerHasInvalidPreSharedKey(preSharedKeyString)
             }
             peer.preSharedKey = preSharedKey
index 8ab8858f9387ceb3191b7d68a64c542605466795..de5770921b47933b26651a704a2334c7994df541 100644 (file)
@@ -63,8 +63,6 @@
                6F628C3D217F09E9003482A3 /* TunnelViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F628C3C217F09E9003482A3 /* TunnelViewModel.swift */; };
                6F628C41217F47DB003482A3 /* TunnelDetailTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F628C40217F47DB003482A3 /* TunnelDetailTableViewController.swift */; };
                6F6483E7229293300075BA15 /* LaunchedAtLoginDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F6483E6229293300075BA15 /* LaunchedAtLoginDetector.swift */; };
-               6F6899A62180447E0012E523 /* x25519.c in Sources */ = {isa = PBXBuildFile; fileRef = 6F6899A52180447E0012E523 /* x25519.c */; };
-               6F6899A8218044FC0012E523 /* Curve25519.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F6899A7218044FC0012E523 /* Curve25519.swift */; };
                6F70E20E221058E1008BDFB4 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6F70E20C221058DF008BDFB4 /* InfoPlist.strings */; };
                6F70E20F221058E1008BDFB4 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6F70E20C221058DF008BDFB4 /* InfoPlist.strings */; };
                6F70E23D22109E15008BDFB4 /* WireGuardLoginItemHelper.app in Embed Login Item Helper */ = {isa = PBXBuildFile; fileRef = 6F70E22922106A2D008BDFB4 /* WireGuardLoginItemHelper.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
                6FB1BDC021D50F0200A991BF /* NETunnelProviderProtocol+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5D942194454A0001E2F7 /* NETunnelProviderProtocol+Extension.swift */; };
                6FB1BDC121D50F0200A991BF /* String+ArrayConversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F4541B121CBFAEE00994C13 /* String+ArrayConversion.swift */; };
                6FB1BDC921D50F0300A991BF /* FileManager+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5A2B4421AFDE020081EDD8 /* FileManager+Extension.swift */; };
-               6FB1BDCA21D50F1700A991BF /* x25519.c in Sources */ = {isa = PBXBuildFile; fileRef = 6F6899A52180447E0012E523 /* x25519.c */; };
-               6FB1BDCB21D50F1700A991BF /* Curve25519.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F6899A7218044FC0012E523 /* Curve25519.swift */; };
                6FB1BDCC21D50F5300A991BF /* TunnelsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7774EE21722D97006A79B3 /* TunnelsManager.swift */; };
                6FB1BDCD21D50F5300A991BF /* ActivateOnDemandOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5DA32197085D0001E2F7 /* ActivateOnDemandOption.swift */; };
                6FB1BDCE21D50F5300A991BF /* TunnelStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F4541A821C451D100994C13 /* TunnelStatus.swift */; };
                6F628C40217F47DB003482A3 /* TunnelDetailTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TunnelDetailTableViewController.swift; sourceTree = "<group>"; };
                6F6483E6229293300075BA15 /* LaunchedAtLoginDetector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchedAtLoginDetector.swift; sourceTree = "<group>"; };
                6F689999218043390012E523 /* WireGuard-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "WireGuard-Bridging-Header.h"; sourceTree = "<group>"; };
-               6F6899A42180447E0012E523 /* x25519.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = x25519.h; sourceTree = "<group>"; };
-               6F6899A52180447E0012E523 /* x25519.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = x25519.c; sourceTree = "<group>"; };
-               6F6899A7218044FC0012E523 /* Curve25519.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Curve25519.swift; sourceTree = "<group>"; };
                6F70E20D221058DF008BDFB4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = WireGuard/Base.lproj/InfoPlist.strings; sourceTree = "<group>"; };
                6F70E22922106A2D008BDFB4 /* WireGuardLoginItemHelper.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WireGuardLoginItemHelper.app; sourceTree = BUILT_PRODUCTS_DIR; };
                6F70E23222106A31008BDFB4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
                        path = Shared;
                        sourceTree = "<group>";
                };
-               6F6899A32180445A0012E523 /* Crypto */ = {
-                       isa = PBXGroup;
-                       children = (
-                               6F6899A52180447E0012E523 /* x25519.c */,
-                               6F6899A42180447E0012E523 /* x25519.h */,
-                               6F6899A7218044FC0012E523 /* Curve25519.swift */,
-                       );
-                       path = Crypto;
-                       sourceTree = "<group>";
-               };
                6F70E22A22106A2D008BDFB4 /* LoginItemHelper */ = {
                        isa = PBXGroup;
                        children = (
                        isa = PBXGroup;
                        children = (
                                6F919ED3218C65C50023B400 /* Resources */,
-                               6F6899A32180445A0012E523 /* Crypto */,
                                6F7774DD217181B1006A79B3 /* UI */,
                                6F7774ED21722D0C006A79B3 /* Tunnel */,
                                6FDEF7E72186320E00D8FBF6 /* ZipArchive */,
                                6F89E17C21F090CC00C97BB9 /* TunnelsTracker.swift in Sources */,
                                6B62E460220A6FA900EF34A6 /* PrivateDataConfirmation.swift in Sources */,
                                6FCD99B121E0EDA900BA4C82 /* TunnelEditViewController.swift in Sources */,
-                               6FB1BDCA21D50F1700A991BF /* x25519.c in Sources */,
-                               6FB1BDCB21D50F1700A991BF /* Curve25519.swift in Sources */,
                                6FB17946222FD5960018AE71 /* OnDemandWiFiControls.swift in Sources */,
                                6FB1BDBB21D50F0200A991BF /* Localizable.strings in Sources */,
                                6FB1BDBC21D50F0200A991BF /* ringlogger.c in Sources */,
                                5F4541A921C451D100994C13 /* TunnelStatus.swift in Sources */,
                                6F8F0D7422267AD2000E8335 /* ChevronCell.swift in Sources */,
                                6F61F1E921B932F700483816 /* WireGuardAppError.swift in Sources */,
-                               6F6899A62180447E0012E523 /* x25519.c in Sources */,
                                6F7774E2217181B1006A79B3 /* AppDelegate.swift in Sources */,
                                6FDEF80021863C0100D8FBF6 /* ioapi.c in Sources */,
                                6F7F7E5F21C7D74B00527607 /* TunnelErrors.swift in Sources */,
                                6FE254FB219C10800028284D /* ZipImporter.swift in Sources */,
                                6FDEF7FB21863B6100D8FBF6 /* unzip.c in Sources */,
                                6F29A9432278518D00DC6A6B /* RecentTunnelsTracker.swift in Sources */,
-                               6F6899A8218044FC0012E523 /* Curve25519.swift in Sources */,
                                6F0F44C9222D55BB00B0FF04 /* TextCell.swift in Sources */,
                                5F4541A021C2D6B700994C13 /* TunnelListCell.swift in Sources */,
                                5F9696B021CD7128008063FE /* TunnelConfiguration+WgQuickConfig.swift in Sources */,
diff --git a/WireGuard/WireGuard/Crypto/Curve25519.swift b/WireGuard/WireGuard/Crypto/Curve25519.swift
deleted file mode 100644 (file)
index 07341ef..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-// SPDX-License-Identifier: MIT
-// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
-
-import Foundation
-import WireGuardKit
-
-struct Curve25519 {
-
-    static let keyLength: Int = 32
-
-    static func generatePrivateKey() -> Data {
-        var privateKey = Data(repeating: 0, count: TunnelConfiguration.keyLength)
-        privateKey.withUnsafeMutableUInt8Bytes { bytes in
-            curve25519_generate_private_key(bytes)
-        }
-        assert(privateKey.count == TunnelConfiguration.keyLength)
-        return privateKey
-    }
-
-    static func generatePublicKey(fromPrivateKey privateKey: Data) -> Data {
-        assert(privateKey.count == TunnelConfiguration.keyLength)
-        var publicKey = Data(repeating: 0, count: TunnelConfiguration.keyLength)
-        privateKey.withUnsafeUInt8Bytes { privateKeyBytes in
-            publicKey.withUnsafeMutableUInt8Bytes { bytes in
-                curve25519_derive_public_key(bytes, privateKeyBytes)
-            }
-        }
-        assert(publicKey.count == TunnelConfiguration.keyLength)
-        return publicKey
-    }
-}
-
-extension InterfaceConfiguration {
-    var publicKey: Data {
-        return Curve25519.generatePublicKey(fromPrivateKey: privateKey)
-    }
-}
index f04e9291e721415c3abc5de0f40a5308b8289fd3..1ffa99c99e963e54c66371ca103aa14939a38a56 100644 (file)
@@ -27,11 +27,11 @@ class MockTunnels {
     static func createMockTunnels() -> [NETunnelProviderManager] {
         return tunnelNames.map { tunnelName -> NETunnelProviderManager in
 
-            var interface = InterfaceConfiguration(privateKey: Curve25519.generatePrivateKey())
+            var interface = InterfaceConfiguration(privateKey: PrivateKey())
             interface.addresses = [IPAddressRange(from: String(format: address, Int.random(in: 1 ... 10), Int.random(in: 1 ... 254)))!]
             interface.dns = dnsServers.map { DNSServer(from: $0)! }
 
-            var peer = PeerConfiguration(publicKey: Curve25519.generatePublicKey(fromPrivateKey: Curve25519.generatePrivateKey()))
+            var peer = PeerConfiguration(publicKey: PrivateKey().publicKey)
             peer.endpoint = Endpoint(from: endpoint)
             peer.allowedIPs = [IPAddressRange(from: allowedIPs)!]
 
index 18e478e6f742c23f1eb3878a79b3e748e9fc6de9..fcd6a31d6a151bc7fcd1aebd185ed470bb5bc53c 100644 (file)
@@ -68,7 +68,7 @@ extension TunnelConfiguration {
         }
 
         let peerPublicKeysArray = peerConfigurations.map { $0.publicKey }
-        let peerPublicKeysSet = Set<Data>(peerPublicKeysArray)
+        let peerPublicKeysSet = Set<PublicKey>(peerPublicKeysArray)
         if peerPublicKeysArray.count != peerPublicKeysSet.count {
             throw ParseError.multiplePeersWithSamePublicKey
         }
@@ -88,7 +88,7 @@ extension TunnelConfiguration {
         guard let privateKeyString = attributes["private_key"] else {
             throw ParseError.interfaceHasNoPrivateKey
         }
-        guard let privateKey = Data(hexKey: privateKeyString), privateKey.count == TunnelConfiguration.keyLength else {
+        guard let privateKey = PrivateKey(hexKey: privateKeyString) else {
             throw ParseError.interfaceHasInvalidPrivateKey(privateKeyString)
         }
         var interface = InterfaceConfiguration(privateKey: privateKey)
@@ -107,18 +107,18 @@ extension TunnelConfiguration {
         guard let publicKeyString = attributes["public_key"] else {
             throw ParseError.peerHasNoPublicKey
         }
-        guard let publicKey = Data(hexKey: publicKeyString), publicKey.count == TunnelConfiguration.keyLength else {
+        guard let publicKey = PublicKey(hexKey: publicKeyString) else {
             throw ParseError.peerHasInvalidPublicKey(publicKeyString)
         }
         var peer = PeerConfiguration(publicKey: publicKey)
         if let preSharedKeyString = attributes["preshared_key"] {
-            guard let preSharedKey = Data(hexKey: preSharedKeyString), preSharedKey.count == TunnelConfiguration.keyLength else {
+            guard let preSharedKey = PreSharedKey(hexKey: preSharedKeyString) else {
                 throw ParseError.peerHasInvalidPreSharedKey(preSharedKeyString)
             }
             // TODO(zx2c4): does the compiler optimize this away?
             var accumulator: UInt8 = 0
-            for index in 0..<preSharedKey.count {
-                accumulator |= preSharedKey[index]
+            for index in 0..<preSharedKey.rawValue.count {
+                accumulator |= preSharedKey.rawValue[index]
             }
             if accumulator != 0 {
                 peer.preSharedKey = preSharedKey
index eafe79d84654d9f8b69e8715eae0c2bead6d7704..3215b70f224b49b3d8a71ce42722cce7e745b250 100644 (file)
@@ -110,9 +110,9 @@ class TunnelViewModel {
                     scratchpad[field] = stringValue
                 }
                 if field == .privateKey {
-                    if stringValue.count == TunnelViewModel.keyLengthInBase64, let privateKey = Data(base64Key: stringValue), privateKey.count == TunnelConfiguration.keyLength {
-                        let publicKey = Curve25519.generatePublicKey(fromPrivateKey: privateKey).base64Key() ?? ""
-                        scratchpad[.publicKey] = publicKey
+                    if stringValue.count == TunnelViewModel.keyLengthInBase64,
+                       let privateKey = PrivateKey(base64Key: stringValue) {
+                        scratchpad[.publicKey] = privateKey.publicKey.base64Key
                     } else {
                         scratchpad.removeValue(forKey: .publicKey)
                     }
@@ -129,8 +129,8 @@ class TunnelViewModel {
         private static func createScratchPad(from config: InterfaceConfiguration, name: String) -> [InterfaceField: String] {
             var scratchpad = [InterfaceField: String]()
             scratchpad[.name] = name
-            scratchpad[.privateKey] = config.privateKey.base64Key() ?? ""
-            scratchpad[.publicKey] = config.publicKey.base64Key() ?? ""
+            scratchpad[.privateKey] = config.privateKey.base64Key
+            scratchpad[.publicKey] = config.privateKey.publicKey.base64Key
             if !config.addresses.isEmpty {
                 scratchpad[.addresses] = config.addresses.map { $0.stringRepresentation }.joined(separator: ", ")
             }
@@ -159,7 +159,7 @@ class TunnelViewModel {
                 fieldsWithError.insert(.privateKey)
                 return .error(tr("alertInvalidInterfaceMessagePrivateKeyRequired"))
             }
-            guard let privateKey = Data(base64Key: privateKeyString), privateKey.count == TunnelConfiguration.keyLength else {
+            guard let privateKey = PrivateKey(base64Key: privateKeyString) else {
                 fieldsWithError.insert(.privateKey)
                 return .error(tr("alertInvalidInterfaceMessagePrivateKeyInvalid"))
             }
@@ -252,12 +252,12 @@ class TunnelViewModel {
         var scratchpad = [PeerField: String]()
         var fieldsWithError = Set<PeerField>()
         var validatedConfiguration: PeerConfiguration?
-        var publicKey: Data? {
+        var publicKey: PublicKey? {
             if let validatedConfiguration = validatedConfiguration {
                 return validatedConfiguration.publicKey
             }
             if let scratchPadPublicKey = scratchpad[.publicKey] {
-                return Data(base64Key: scratchPadPublicKey)
+                return PublicKey(base64Key: scratchPadPublicKey)
             }
             return nil
         }
@@ -302,10 +302,8 @@ class TunnelViewModel {
 
         private static func createScratchPad(from config: PeerConfiguration) -> [PeerField: String] {
             var scratchpad = [PeerField: String]()
-            if let publicKey = config.publicKey.base64Key() {
-                scratchpad[.publicKey] = publicKey
-            }
-            if let preSharedKey = config.preSharedKey?.base64Key() {
+            scratchpad[.publicKey] = config.publicKey.base64Key
+            if let preSharedKey = config.preSharedKey?.base64Key {
                 scratchpad[.preSharedKey] = preSharedKey
             }
             if !config.allowedIPs.isEmpty {
@@ -338,14 +336,14 @@ class TunnelViewModel {
                 fieldsWithError.insert(.publicKey)
                 return .error(tr("alertInvalidPeerMessagePublicKeyRequired"))
             }
-            guard let publicKey = Data(base64Key: publicKeyString), publicKey.count == TunnelConfiguration.keyLength else {
+            guard let publicKey = PublicKey(base64Key: publicKeyString) 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(base64Key: preSharedKeyString), preSharedKey.count == TunnelConfiguration.keyLength {
+                if let preSharedKey = PreSharedKey(base64Key: preSharedKeyString) {
                     config.preSharedKey = preSharedKey
                 } else {
                     fieldsWithError.insert(.preSharedKey)
@@ -560,7 +558,7 @@ class TunnelViewModel {
             }
 
             let peerPublicKeysArray = peerConfigurations.map { $0.publicKey }
-            let peerPublicKeysSet = Set<Data>(peerPublicKeysArray)
+            let peerPublicKeysSet = Set<PublicKey>(peerPublicKeysArray)
             if peerPublicKeysArray.count != peerPublicKeysSet.count {
                 return .error(tr("alertInvalidPeerMessagePublicKeyDuplicated"))
             }
index e9c09957d9376851eed85c257b02c9f779cf0c3a..ecad2f6c931b8c2792747aca75fcf778ab16ae67 100644 (file)
@@ -2,6 +2,7 @@
 // Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
 
 import UIKit
+import WireGuardKit
 
 protocol TunnelEditTableViewControllerDelegate: class {
     func tunnelSaved(tunnel: TunnelContainer)
@@ -214,7 +215,7 @@ extension TunnelEditTableViewController {
         cell.onTapped = { [weak self] in
             guard let self = self else { return }
 
-            self.tunnelViewModel.interfaceData[.privateKey] = Curve25519.generatePrivateKey().base64Key() ?? ""
+            self.tunnelViewModel.interfaceData[.privateKey] = PrivateKey().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)
index de2423e223fb53874559ee1ceabd09ffe8020866..97eaf8f12818076f0f2c51c35be445691f2ce1a4 100644 (file)
@@ -108,27 +108,24 @@ class TunnelEditViewController: NSViewController {
             let tunnelConfiguration = tunnel.tunnelConfiguration!
             nameRow.value = tunnel.name
             textView.string = tunnelConfiguration.asWgQuickConfig()
-            publicKeyRow.value = tunnelConfiguration.interface.publicKey.base64Key() ?? ""
-            textView.privateKeyString = tunnelConfiguration.interface.privateKey.base64Key() ?? ""
+            publicKeyRow.value = tunnelConfiguration.interface.privateKey.publicKey.base64Key
+            textView.privateKeyString = tunnelConfiguration.interface.privateKey.base64Key
             let singlePeer = tunnelConfiguration.peers.count == 1 ? tunnelConfiguration.peers.first : nil
             updateExcludePrivateIPsVisibility(singlePeerAllowedIPs: singlePeer?.allowedIPs.map { $0.stringRepresentation })
             dnsServersAddedToAllowedIPs = excludePrivateIPsCheckbox.state == .on ? tunnelConfiguration.interface.dns.map { $0.stringRepresentation }.joined(separator: ", ") : nil
         } else {
             // Creating a new tunnel
-            let privateKey = Curve25519.generatePrivateKey()
-            let publicKey = Curve25519.generatePublicKey(fromPrivateKey: privateKey)
-            let bootstrappingText = "[Interface]\nPrivateKey = \(privateKey.base64Key() ?? "")\n"
-            publicKeyRow.value = publicKey.base64Key() ?? ""
+            let privateKey = PrivateKey()
+            let bootstrappingText = "[Interface]\nPrivateKey = \(privateKey.base64Key)\n"
+            publicKeyRow.value = privateKey.publicKey.base64Key
             textView.string = bootstrappingText
             updateExcludePrivateIPsVisibility(singlePeerAllowedIPs: nil)
             dnsServersAddedToAllowedIPs = nil
         }
         privateKeyObservationToken = textView.observe(\.privateKeyString) { [weak publicKeyRow] textView, _ in
             if let privateKeyString = textView.privateKeyString,
-                let privateKey = Data(base64Key: privateKeyString),
-                privateKey.count == TunnelConfiguration.keyLength {
-                let publicKey = Curve25519.generatePublicKey(fromPrivateKey: privateKey)
-                publicKeyRow?.value = publicKey.base64Key() ?? ""
+               let privateKey = PrivateKey(base64Key: privateKeyString) {
+                publicKeyRow?.value = privateKey.publicKey.base64Key
             } else {
                 publicKeyRow?.value = ""
             }
index 1cd98ee134a711f4b1e91a717dfb8d30370b11e5..955412e54cab4bf6c488a017d4e0b63811c361a0 100644 (file)
@@ -1,4 +1,3 @@
-#include "x25519.h"
 #include "unzip.h"
 #include "zip.h"
 #include "ringlogger.h"
index c946e24f6320cc0d0e176a7ba86ffdf8ae76bed5..9c2f634727697f3af433804f5351d1cdfd7bf4f2 100644 (file)
@@ -23,7 +23,9 @@ enum ZipArchiveError: WireGuardAppError {
     }
 }
 
-class ZipArchive {
+enum ZipArchive {}
+
+extension ZipArchive {
 
     static func archive(inputs: [(fileName: String, contents: Data)], to destinationURL: URL) throws {
         let destinationPath = destinationURL.path
@@ -34,8 +36,8 @@ class ZipArchive {
             let fileName = input.fileName
             let contents = input.contents
             zipOpenNewFileInZip(zipFile, fileName.cString(using: .utf8), nil, nil, 0, nil, 0, nil, Z_DEFLATED, Z_DEFAULT_COMPRESSION)
-            contents.withUnsafeUInt8Bytes { ptr -> Void in
-                zipWriteInFileInZip(zipFile, UnsafeRawPointer(ptr), UInt32(contents.count))
+            contents.withUnsafeBytes { rawBufferPointer -> Void in
+                zipWriteInFileInZip(zipFile, rawBufferPointer.baseAddress, UInt32(contents.count))
             }
             zipCloseFileInZip(zipFile)
         }
diff --git a/WireGuardKit/Sources/WireGuardKit/Data+KeyEncoding.swift b/WireGuardKit/Sources/WireGuardKit/Data+KeyEncoding.swift
deleted file mode 100644 (file)
index 5c7aee9..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-// SPDX-License-Identifier: MIT
-// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
-
-import Foundation
-
-extension Data {
-    func isKey() -> Bool {
-        return self.count == WG_KEY_LEN
-    }
-
-    func hexKey() -> String? {
-        if self.count != WG_KEY_LEN {
-            return nil
-        }
-        var out = Data(repeating: 0, count: Int(WG_KEY_LEN_HEX))
-        out.withUnsafeMutableInt8Bytes { outBytes in
-            self.withUnsafeUInt8Bytes { inBytes in
-                key_to_hex(outBytes, inBytes)
-            }
-        }
-        out.removeLast()
-        return String(data: out, encoding: .ascii)
-    }
-
-    init?(hexKey hexString: String) {
-        self.init(repeating: 0, count: Int(WG_KEY_LEN))
-
-        if !self.withUnsafeMutableUInt8Bytes { key_from_hex($0, hexString) } {
-            return nil
-        }
-    }
-
-    func base64Key() -> String? {
-        if self.count != WG_KEY_LEN {
-            return nil
-        }
-        var out = Data(repeating: 0, count: Int(WG_KEY_LEN_BASE64))
-        out.withUnsafeMutableInt8Bytes { outBytes in
-            self.withUnsafeUInt8Bytes { inBytes in
-                key_to_base64(outBytes, inBytes)
-            }
-        }
-        out.removeLast()
-        return String(data: out, encoding: .ascii)
-    }
-
-    init?(base64Key base64String: String) {
-        self.init(repeating: 0, count: Int(WG_KEY_LEN))
-
-        if !self.withUnsafeMutableUInt8Bytes { key_from_base64($0, base64String) } {
-            return nil
-        }
-    }
-}
-
-extension Data {
-    func withUnsafeUInt8Bytes<R>(_ body: (UnsafePointer<UInt8>) -> R) -> R {
-        assert(!isEmpty)
-        return self.withUnsafeBytes { (ptr: UnsafeRawBufferPointer) -> R in
-            let bytes = ptr.bindMemory(to: UInt8.self)
-            return body(bytes.baseAddress!) // might crash if self.count == 0
-        }
-    }
-
-    mutating func withUnsafeMutableUInt8Bytes<R>(_ body: (UnsafeMutablePointer<UInt8>) -> R) -> R {
-        assert(!isEmpty)
-        return self.withUnsafeMutableBytes { (ptr: UnsafeMutableRawBufferPointer) -> R in
-            let bytes = ptr.bindMemory(to: UInt8.self)
-            return body(bytes.baseAddress!) // might crash if self.count == 0
-        }
-    }
-
-    mutating func withUnsafeMutableInt8Bytes<R>(_ body: (UnsafeMutablePointer<Int8>) -> R) -> R {
-        assert(!isEmpty)
-        return self.withUnsafeMutableBytes { (ptr: UnsafeMutableRawBufferPointer) -> R in
-            let bytes = ptr.bindMemory(to: Int8.self)
-            return body(bytes.baseAddress!) // might crash if self.count == 0
-        }
-    }
-}
index 16a904626a7c9440ca15c9a6768dd1a73f7afec6..db84e71daa9522ba076d06e98fa6b801fa0a7966 100644 (file)
@@ -5,16 +5,13 @@ import Foundation
 import Network
 
 public struct InterfaceConfiguration {
-    public var privateKey: Data
+    public var privateKey: PrivateKey
     public var addresses = [IPAddressRange]()
     public var listenPort: UInt16?
     public var mtu: UInt16?
     public var dns = [DNSServer]()
 
-    public init(privateKey: Data) {
-        if privateKey.count != TunnelConfiguration.keyLength {
-            fatalError("Invalid private key")
-        }
+    public init(privateKey: PrivateKey) {
         self.privateKey = privateKey
     }
 }
index c1cd3f7197e02b2ee3fc7fd729afc86fe1a3b1ba..5922b2c1b5c9620337808e03e7929c33dfbd2015 100644 (file)
@@ -18,9 +18,7 @@ class PacketTunnelSettingsGenerator {
     func endpointUapiConfiguration() -> String {
         var wgSettings = ""
         for (index, peer) in tunnelConfiguration.peers.enumerated() {
-            if let publicKey = peer.publicKey.hexKey() {
-                wgSettings.append("public_key=\(publicKey)\n")
-            }
+            wgSettings.append("public_key=\(peer.publicKey.hexKey)\n")
             if let endpoint = resolvedEndpoints[index]?.withReresolvedIP() {
                 if case .name(_, _) = endpoint.host { assert(false, "Endpoint is not resolved") }
                 wgSettings.append("endpoint=\(endpoint.stringRepresentation)\n")
@@ -31,9 +29,7 @@ class PacketTunnelSettingsGenerator {
 
     func uapiConfiguration() -> String {
         var wgSettings = ""
-        if let privateKey = tunnelConfiguration.interface.privateKey.hexKey() {
-            wgSettings.append("private_key=\(privateKey)\n")
-        }
+        wgSettings.append("private_key=\(tunnelConfiguration.interface.privateKey.hexKey)\n")
         if let listenPort = tunnelConfiguration.interface.listenPort {
             wgSettings.append("listen_port=\(listenPort)\n")
         }
@@ -42,10 +38,8 @@ class PacketTunnelSettingsGenerator {
         }
         assert(tunnelConfiguration.peers.count == resolvedEndpoints.count)
         for (index, peer) in tunnelConfiguration.peers.enumerated() {
-            if let publicKey = peer.publicKey.hexKey() {
-                wgSettings.append("public_key=\(publicKey)\n")
-            }
-            if let preSharedKey = peer.preSharedKey?.hexKey() {
+            wgSettings.append("public_key=\(peer.publicKey.hexKey)\n")
+            if let preSharedKey = peer.preSharedKey?.hexKey {
                 wgSettings.append("preshared_key=\(preSharedKey)\n")
             }
             if let endpoint = resolvedEndpoints[index]?.withReresolvedIP() {
index 4d92dc6fcaf6b084efede3029e591a159be27b0a..f11b4733d6d0d172f46cf92679a4566ae783b5f4 100644 (file)
@@ -4,16 +4,8 @@
 import Foundation
 
 public struct PeerConfiguration {
-    public var publicKey: Data
-    public var preSharedKey: Data? {
-        didSet(value) {
-            if let value = value {
-                if value.count != TunnelConfiguration.keyLength {
-                    fatalError("Invalid preshared key")
-                }
-            }
-        }
-    }
+    public var publicKey: PublicKey
+    public var preSharedKey: PreSharedKey?
     public var allowedIPs = [IPAddressRange]()
     public var endpoint: Endpoint?
     public var persistentKeepAlive: UInt16?
@@ -21,11 +13,8 @@ public struct PeerConfiguration {
     public var txBytes: UInt64?
     public var lastHandshakeTime: Date?
 
-    public init(publicKey: Data) {
+    public init(publicKey: PublicKey) {
         self.publicKey = publicKey
-        if publicKey.count != TunnelConfiguration.keyLength {
-            fatalError("Invalid public key")
-        }
     }
 }
 
diff --git a/WireGuardKit/Sources/WireGuardKit/PrivateKey.swift b/WireGuardKit/Sources/WireGuardKit/PrivateKey.swift
new file mode 100644 (file)
index 0000000..48dc3eb
--- /dev/null
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: MIT
+// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
+
+import Foundation
+import WireGuardKitCTarget
+
+/// The class describing a private key used by WireGuard.
+public class PrivateKey: _BaseKey {
+    /// Derived public key
+    public var publicKey: PublicKey {
+        return rawValue.withUnsafeBytes { (privateKeyBufferPointer: UnsafeRawBufferPointer) -> PublicKey in
+            var publicKeyData = Data(repeating: 0, count: Int(WG_KEY_LEN))
+            let privateKeyBytes = privateKeyBufferPointer.baseAddress!.assumingMemoryBound(to: UInt8.self)
+
+            publicKeyData.withUnsafeMutableBytes { (publicKeyBufferPointer: UnsafeMutableRawBufferPointer) in
+                let publicKeyBytes = publicKeyBufferPointer.baseAddress!.assumingMemoryBound(to: UInt8.self)
+                curve25519_derive_public_key(publicKeyBytes, privateKeyBytes)
+            }
+
+            return PublicKey(rawValue: publicKeyData)!
+        }
+    }
+
+    /// Initialize new private key
+    convenience public init() {
+        var privateKeyData = Data(repeating: 0, count: Int(WG_KEY_LEN))
+        privateKeyData.withUnsafeMutableBytes { (rawBufferPointer: UnsafeMutableRawBufferPointer) in
+            let privateKeyBytes = rawBufferPointer.baseAddress!.assumingMemoryBound(to: UInt8.self)
+            curve25519_generate_private_key(privateKeyBytes)
+        }
+        self.init(rawValue: privateKeyData)!
+    }
+}
+
+/// The class describing a public key used by WireGuard.
+public class PublicKey: _BaseKey {}
+
+/// The class describing a pre-shared key used by WireGuard.
+public class PreSharedKey: _BaseKey {}
+
+/// The base key implementation. Should not be used directly.
+public class _BaseKey: RawRepresentable, Equatable, Hashable {
+    /// Raw key representation
+    public let rawValue: Data
+
+    /// Hex encoded representation
+    public var hexKey: String {
+        return rawValue.withUnsafeBytes { (rawBufferPointer: UnsafeRawBufferPointer) -> String in
+            let inBytes = rawBufferPointer.baseAddress!.assumingMemoryBound(to: UInt8.self)
+            var outBytes = [CChar](repeating: 0, count: Int(WG_KEY_LEN_HEX))
+            key_to_hex(&outBytes, inBytes)
+            return String(cString: outBytes, encoding: .ascii)!
+        }
+    }
+
+    /// Base64 encoded representation
+    public var base64Key: String {
+        return rawValue.withUnsafeBytes { (rawBufferPointer: UnsafeRawBufferPointer) -> String in
+            let inBytes = rawBufferPointer.baseAddress!.assumingMemoryBound(to: UInt8.self)
+            var outBytes = [CChar](repeating: 0, count: Int(WG_KEY_LEN_BASE64))
+            key_to_base64(&outBytes, inBytes)
+            return String(cString: outBytes, encoding: .ascii)!
+        }
+    }
+
+    /// Initialize the key with existing raw representation
+    required public init?(rawValue: Data) {
+        if rawValue.count == WG_KEY_LEN {
+            self.rawValue = rawValue
+        } else {
+            return nil
+        }
+    }
+
+    /// Initialize the key with hex representation
+    public convenience init?(hexKey: String) {
+        var bytes = Data(repeating: 0, count: Int(WG_KEY_LEN))
+        let success = bytes.withUnsafeMutableBytes { (bufferPointer: UnsafeMutableRawBufferPointer) -> Bool in
+            return key_from_hex(bufferPointer.baseAddress!.assumingMemoryBound(to: UInt8.self), hexKey)
+        }
+        if success {
+            self.init(rawValue: bytes)
+        } else {
+            return nil
+        }
+    }
+
+    /// Initialize the key with base64 representation
+    public convenience init?(base64Key: String) {
+        var bytes = Data(repeating: 0, count: Int(WG_KEY_LEN))
+        let success = bytes.withUnsafeMutableBytes { (bufferPointer: UnsafeMutableRawBufferPointer) -> Bool in
+            return key_from_base64(bufferPointer.baseAddress!.assumingMemoryBound(to: UInt8.self), base64Key)
+        }
+        if success {
+            self.init(rawValue: bytes)
+        } else {
+            return nil
+        }
+    }
+
+    public static func == (lhs: _BaseKey, rhs: _BaseKey) -> Bool {
+        return lhs.rawValue.withUnsafeBytes { (lhsBytes: UnsafeRawBufferPointer) -> Bool in
+            return rhs.rawValue.withUnsafeBytes { (rhsBytes: UnsafeRawBufferPointer) -> Bool in
+                return key_eq(
+                    lhsBytes.baseAddress!.assumingMemoryBound(to: UInt8.self),
+                    rhsBytes.baseAddress!.assumingMemoryBound(to: UInt8.self)
+                )
+            }
+        }
+    }
+}
index b1ca442404dae8f2e18dbaec3d11465aa1b9d68d..dad3484755e608039f0280470b46298dfd967438 100644 (file)
@@ -8,15 +8,13 @@ public final class TunnelConfiguration {
     public var interface: InterfaceConfiguration
     public let peers: [PeerConfiguration]
 
-    public static let keyLength = 32
-
     public init(name: String?, interface: InterfaceConfiguration, peers: [PeerConfiguration]) {
         self.interface = interface
         self.peers = peers
         self.name = name
 
         let peerPublicKeysArray = peers.map { $0.publicKey }
-        let peerPublicKeysSet = Set<Data>(peerPublicKeysArray)
+        let peerPublicKeysSet = Set<PublicKey>(peerPublicKeysArray)
         if peerPublicKeysArray.count != peerPublicKeysSet.count {
             fatalError("Two or more peers cannot have the same public key")
         }
index f0795013dd5dc27a623fdd41a356399c3a4466db..30a24e4a03a1b5750498b2bff6f1ce44a279d9b9 100644 (file)
@@ -2,3 +2,4 @@
 // Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
 
 #include "../key.h"
+#include "../x25519.h"
index 6c64443208f046be8998395b1c2086c24021f962..140f278d78552ed9c4af05a197ba7c00f0bbaed5 100644 (file)
@@ -112,3 +112,13 @@ bool key_from_hex(uint8_t key[static WG_KEY_LEN], const char *hex)
 
        return 1 & ((ret - 1) >> 8);
 }
+
+bool key_eq(const uint8_t key1[static WG_KEY_LEN], const uint8_t key2[static WG_KEY_LEN])
+{
+       volatile uint8_t acc = 0;
+       for (unsigned int i = 0; i < WG_KEY_LEN; ++i) {
+               acc |= key1[i] ^ key2[i];
+               asm volatile("" : "=r"(acc) : "0"(acc));
+       }
+       return 1 & ((acc - 1) >> 8);
+}
index bd22a942ed1e1e09849cac45b4d0ea63206f021b..149e4ed8dbcaaafd51ceb44f4cf5a71781795001 100644 (file)
@@ -19,4 +19,6 @@ bool key_from_base64(uint8_t key[static WG_KEY_LEN], const char *base64);
 void key_to_hex(char hex[static WG_KEY_LEN_HEX], const uint8_t key[static WG_KEY_LEN]);
 bool key_from_hex(uint8_t key[static WG_KEY_LEN], const char *hex);
 
+bool key_eq(const uint8_t key1[static WG_KEY_LEN], const uint8_t key2[static WG_KEY_LEN]);
+
 #endif