WireGuardKit: Add wrappers for PrivateKey, PublicKey, PreSharedKey

Signed-off-by: Andrej Mihajlov <and@mullvad.net>
This commit is contained in:
Andrej Mihajlov 2020-11-26 17:23:50 +01:00
parent 76c8487a56
commit 4deaf905c1
21 changed files with 176 additions and 220 deletions

View 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

View 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, ); }; };
@ -109,8 +107,6 @@
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 */; };
@ -286,9 +282,6 @@
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>"; };
@ -482,16 +475,6 @@
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 = (
@ -689,7 +672,6 @@
isa = PBXGroup;
children = (
6F919ED3218C65C50023B400 /* Resources */,
6F6899A32180445A0012E523 /* Crypto */,
6F7774DD217181B1006A79B3 /* UI */,
6F7774ED21722D0C006A79B3 /* Tunnel */,
6FDEF7E72186320E00D8FBF6 /* ZipArchive */,
@ -1160,8 +1142,6 @@
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 */,
@ -1233,7 +1213,6 @@
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 */,
@ -1252,7 +1231,6 @@
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 */,

View File

@ -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)
}
}

View 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)!]

View 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

View 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"))
}

View 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)

View 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 = ""
}

View File

@ -1,4 +1,3 @@
#include "x25519.h"
#include "unzip.h"
#include "zip.h"
#include "ringlogger.h"

View 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)
}

View File

@ -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
}
}
}

View 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
}
}

View 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() {

View 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")
}
}
}

View File

@ -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)
)
}
}
}
}

View 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")
}

View File

@ -2,3 +2,4 @@
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
#include "../key.h"
#include "../x25519.h"

View 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);
}

View 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