From 5c8c361fceae26d0f1d5b54f33c730e3d3e446f7 Mon Sep 17 00:00:00 2001 From: Davide De Rosa Date: Tue, 11 Sep 2018 00:06:38 +0200 Subject: [PATCH] Add StaticKey class for static OpenVPN keys --- .jazzy.yaml | 1 + TunnelKit.xcodeproj/project.pbxproj | 6 ++ TunnelKit/Sources/Core/StaticKey.swift | 109 +++++++++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 TunnelKit/Sources/Core/StaticKey.swift diff --git a/.jazzy.yaml b/.jazzy.yaml index c96fb76..423a0de 100644 --- a/.jazzy.yaml +++ b/.jazzy.yaml @@ -19,6 +19,7 @@ custom_categories: - TunnelInterface - PacketStream - BidirectionalState + - StaticKey - SessionProxy - SessionProxyDelegate - SessionReply diff --git a/TunnelKit.xcodeproj/project.pbxproj b/TunnelKit.xcodeproj/project.pbxproj index 0b79270..71c6f76 100644 --- a/TunnelKit.xcodeproj/project.pbxproj +++ b/TunnelKit.xcodeproj/project.pbxproj @@ -78,6 +78,8 @@ 0ECE352A212EB88E0040F253 /* CryptoContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECE3527212EB7770040F253 /* CryptoContainer.swift */; }; 0ED9C8642138139000621BA3 /* SessionProxy+CompressionFraming.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED9C8632138139000621BA3 /* SessionProxy+CompressionFraming.swift */; }; 0ED9C8652138139000621BA3 /* SessionProxy+CompressionFraming.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED9C8632138139000621BA3 /* SessionProxy+CompressionFraming.swift */; }; + 0EE3B3E421471C3A0027AB17 /* StaticKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE3B3E321471C3A0027AB17 /* StaticKey.swift */; }; + 0EE3B3E521471C3A0027AB17 /* StaticKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE3B3E321471C3A0027AB17 /* StaticKey.swift */; }; 0EE7A79820F6296F00B42E6A /* PacketMacros.m in Sources */ = {isa = PBXBuildFile; fileRef = 0EE7A79720F6296F00B42E6A /* PacketMacros.m */; }; 0EE7A79920F6296F00B42E6A /* PacketMacros.m in Sources */ = {isa = PBXBuildFile; fileRef = 0EE7A79720F6296F00B42E6A /* PacketMacros.m */; }; 0EE7A7A120F664AC00B42E6A /* DataPathEncryptionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE7A7A020F664AB00B42E6A /* DataPathEncryptionTests.swift */; }; @@ -239,6 +241,7 @@ 0EC1BBA720D7D803007C4C7B /* ConnectionStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionStrategy.swift; sourceTree = ""; }; 0ECE3527212EB7770040F253 /* CryptoContainer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CryptoContainer.swift; sourceTree = ""; }; 0ED9C8632138139000621BA3 /* SessionProxy+CompressionFraming.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SessionProxy+CompressionFraming.swift"; sourceTree = ""; }; + 0EE3B3E321471C3A0027AB17 /* StaticKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StaticKey.swift; sourceTree = ""; }; 0EE7A79420F61EDC00B42E6A /* PacketMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PacketMacros.h; sourceTree = ""; }; 0EE7A79720F6296F00B42E6A /* PacketMacros.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PacketMacros.m; sourceTree = ""; }; 0EE7A79D20F6488400B42E6A /* DataPathCrypto.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DataPathCrypto.h; sourceTree = ""; }; @@ -481,6 +484,7 @@ 0E749F5E2178885500BB2701 /* SessionProxy+PIA.swift */, 0E3E0F202108A8CC00B371C1 /* SessionProxy+PushReply.swift */, 0EFEB42B2006D3C800F81029 /* SessionProxy+SessionKey.swift */, + 0EE3B3E321471C3A0027AB17 /* StaticKey.swift */, 0EFEB4442006D3C800F81029 /* TLSBox.h */, 0EFEB4302006D3C800F81029 /* TLSBox.m */, 0EFEB42F2006D3C800F81029 /* TunnelInterface.swift */, @@ -879,6 +883,7 @@ 0EFEB4AE2007625E00F81029 /* Keychain.swift in Sources */, 0E749F5F2178885500BB2701 /* SessionProxy+PIA.swift in Sources */, 0EBBF3002085196000E36B40 /* NWTCPConnectionState+Description.swift in Sources */, + 0EE3B3E421471C3A0027AB17 /* StaticKey.swift in Sources */, 0EFEB4622006D3C800F81029 /* SecureRandom.swift in Sources */, 0EFEB45D2006D3C800F81029 /* CryptoBox.m in Sources */, 0EBBF2FA2085061600E36B40 /* NETCPInterface.swift in Sources */, @@ -935,6 +940,7 @@ 0EFEB4A02006D7F300F81029 /* ReplayProtector.m in Sources */, 0E749F602178885500BB2701 /* SessionProxy+PIA.swift in Sources */, 0EFEB4992006D7F300F81029 /* SessionProxy.swift in Sources */, + 0EE3B3E521471C3A0027AB17 /* StaticKey.swift in Sources */, 0EBBF3012085196000E36B40 /* NWTCPConnectionState+Description.swift in Sources */, 0EFEB4962006D7F300F81029 /* ProtocolMacros.swift in Sources */, 0EFEB48A2006D7C400F81029 /* TunnelKitProvider.swift in Sources */, diff --git a/TunnelKit/Sources/Core/StaticKey.swift b/TunnelKit/Sources/Core/StaticKey.swift new file mode 100644 index 0000000..920e781 --- /dev/null +++ b/TunnelKit/Sources/Core/StaticKey.swift @@ -0,0 +1,109 @@ +// +// StaticKey.swift +// TunnelKit +// +// Created by Davide De Rosa on 9/10/18. +// Copyright (c) 2018 Davide De Rosa. All rights reserved. +// +// https://github.com/keeshux +// +// This file is part of TunnelKit. +// +// TunnelKit is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// TunnelKit is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with TunnelKit. If not, see . +// + +import Foundation +import __TunnelKitNative + +/// Represents an OpenVPN static key file (as generated with --genkey) +public class StaticKey: Codable { + enum CodingKeys: CodingKey { + case data + + case dir + } + + /// The key-direction field, usually 0 on servers and 1 on clients. + public enum Direction: Int, Codable { + + /// Conventional server direction. + case server = 0 + + /// Conventional client direction. + case client = 1 + } + + private static let contentLength = 256 // 2048-bit + + private static let keyCount = 4 + + private static let keyLength = StaticKey.contentLength / StaticKey.keyCount + + private let secureData: ZeroingData + + private let direction: Direction? + + /** + Initializes with data and direction. + + - Parameter data: The key data. + - Parameter direction: The key direction, or bidirectional if nil. + */ + public init(data: Data, direction: Direction?) { + precondition(data.count == StaticKey.contentLength) + secureData = Z(data) + self.direction = direction + } + + /** + Initializes as bidirectional. + + - Parameter biData: The key data. + */ + public convenience init(biData data: Data) { + self.init(data: data, direction: nil) + } + + private func key(at: Int) -> ZeroingData { + let size = secureData.count / StaticKey.keyCount // 64 bytes each + assert(size == StaticKey.keyLength) + return secureData.withOffset(at * size, count: size) + } + + /// :nodoc: + public static func deserialized(_ data: Data) throws -> StaticKey { + return try JSONDecoder().decode(StaticKey.self, from: data) + } + + /// :nodoc: + public func serialized() -> Data? { + return try? JSONEncoder().encode(self) + } + + // MARK: Codable + + /// :nodoc: + public required init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + secureData = Z(try container.decode(Data.self, forKey: .data)) + direction = try container.decodeIfPresent(Direction.self, forKey: .dir) + } + + /// :nodoc: + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(secureData.toData(), forKey: .data) + try container.encodeIfPresent(direction, forKey: .dir) + } +}