Convert encryption tests to proper unit tests (#348)
This commit is contained in:
parent
6a8607b77f
commit
8ca928a13b
|
@ -55,6 +55,7 @@
|
||||||
if ((self = [super init])) {
|
if ((self = [super init])) {
|
||||||
_count = count;
|
_count = count;
|
||||||
_bytes = allocate_safely(count);
|
_bytes = allocate_safely(count);
|
||||||
|
bzero(_bytes, _count);
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
|
@ -151,13 +151,15 @@ const NSInteger CryptoCBCMaxHMACLength = 100;
|
||||||
int code = 1;
|
int code = 1;
|
||||||
|
|
||||||
if (self.cipher) {
|
if (self.cipher) {
|
||||||
if (RAND_bytes(outIV, self.cipherIVLength) != 1) {
|
if (!flags || !flags->forTesting) {
|
||||||
if (error) {
|
if (RAND_bytes(outIV, self.cipherIVLength) != 1) {
|
||||||
*error = OpenVPNErrorWithCode(OpenVPNErrorCodeCryptoRandomGenerator);
|
if (error) {
|
||||||
|
*error = OpenVPNErrorWithCode(OpenVPNErrorCodeCryptoRandomGenerator);
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
}
|
}
|
||||||
return NO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TUNNEL_CRYPTO_TRACK_STATUS(code) EVP_CipherInit(self.cipherCtxEnc, NULL, NULL, outIV, -1);
|
TUNNEL_CRYPTO_TRACK_STATUS(code) EVP_CipherInit(self.cipherCtxEnc, NULL, NULL, outIV, -1);
|
||||||
TUNNEL_CRYPTO_TRACK_STATUS(code) EVP_CipherUpdate(self.cipherCtxEnc, outEncrypted, &l1, bytes, (int)length);
|
TUNNEL_CRYPTO_TRACK_STATUS(code) EVP_CipherUpdate(self.cipherCtxEnc, outEncrypted, &l1, bytes, (int)length);
|
||||||
TUNNEL_CRYPTO_TRACK_STATUS(code) EVP_CipherFinal_ex(self.cipherCtxEnc, outEncrypted + l1, &l2);
|
TUNNEL_CRYPTO_TRACK_STATUS(code) EVP_CipherFinal_ex(self.cipherCtxEnc, outEncrypted + l1, &l2);
|
||||||
|
@ -203,8 +205,6 @@ const NSInteger CryptoCBCMaxHMACLength = 100;
|
||||||
|
|
||||||
- (BOOL)decryptBytes:(const uint8_t *)bytes length:(NSInteger)length dest:(uint8_t *)dest destLength:(NSInteger *)destLength flags:(const CryptoFlags * _Nullable)flags error:(NSError * _Nullable __autoreleasing * _Nullable)error
|
- (BOOL)decryptBytes:(const uint8_t *)bytes length:(NSInteger)length dest:(uint8_t *)dest destLength:(NSInteger *)destLength flags:(const CryptoFlags * _Nullable)flags error:(NSError * _Nullable __autoreleasing * _Nullable)error
|
||||||
{
|
{
|
||||||
NSAssert(self.cipher, @"No cipher provided");
|
|
||||||
|
|
||||||
const uint8_t *iv = bytes + self.digestLength;
|
const uint8_t *iv = bytes + self.digestLength;
|
||||||
const uint8_t *encrypted = bytes + self.digestLength + self.cipherIVLength;
|
const uint8_t *encrypted = bytes + self.digestLength + self.cipherIVLength;
|
||||||
int l1 = 0, l2 = 0;
|
int l1 = 0, l2 = 0;
|
||||||
|
@ -221,11 +221,18 @@ const NSInteger CryptoCBCMaxHMACLength = 100;
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
TUNNEL_CRYPTO_TRACK_STATUS(code) EVP_CipherInit(self.cipherCtxDec, NULL, NULL, iv, -1);
|
if (self.cipher) {
|
||||||
TUNNEL_CRYPTO_TRACK_STATUS(code) EVP_CipherUpdate(self.cipherCtxDec, dest, &l1, encrypted, (int)length - self.digestLength - self.cipherIVLength);
|
TUNNEL_CRYPTO_TRACK_STATUS(code) EVP_CipherInit(self.cipherCtxDec, NULL, NULL, iv, -1);
|
||||||
TUNNEL_CRYPTO_TRACK_STATUS(code) EVP_CipherFinal_ex(self.cipherCtxDec, dest + l1, &l2);
|
TUNNEL_CRYPTO_TRACK_STATUS(code) EVP_CipherUpdate(self.cipherCtxDec, dest, &l1, encrypted, (int)length - self.digestLength - self.cipherIVLength);
|
||||||
|
TUNNEL_CRYPTO_TRACK_STATUS(code) EVP_CipherFinal_ex(self.cipherCtxDec, dest + l1, &l2);
|
||||||
|
|
||||||
*destLength = l1 + l2;
|
*destLength = l1 + l2;
|
||||||
|
} else {
|
||||||
|
l2 = (int)length - l1;
|
||||||
|
memcpy(dest, bytes + l1, l2);
|
||||||
|
|
||||||
|
*destLength = l2;
|
||||||
|
}
|
||||||
|
|
||||||
TUNNEL_CRYPTO_RETURN_STATUS(code)
|
TUNNEL_CRYPTO_RETURN_STATUS(code)
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,7 @@ typedef struct {
|
||||||
NSInteger ivLength;
|
NSInteger ivLength;
|
||||||
const uint8_t *_Nullable ad;
|
const uint8_t *_Nullable ad;
|
||||||
NSInteger adLength;
|
NSInteger adLength;
|
||||||
|
BOOL forTesting;
|
||||||
} CryptoFlags;
|
} CryptoFlags;
|
||||||
|
|
||||||
// WARNING: dest must be able to hold ciphertext
|
// WARNING: dest must be able to hold ciphertext
|
||||||
|
|
|
@ -282,7 +282,7 @@ extension OpenVPN.ControlChannel {
|
||||||
var decryptedCount = 0
|
var decryptedCount = 0
|
||||||
try packet.withUnsafeBytes {
|
try packet.withUnsafeBytes {
|
||||||
let src = $0.bytePointer
|
let src = $0.bytePointer
|
||||||
var flags = CryptoFlags(iv: nil, ivLength: 0, ad: src, adLength: adLength)
|
var flags = CryptoFlags(iv: nil, ivLength: 0, ad: src, adLength: adLength, forTesting: false)
|
||||||
try decryptedPacket.withUnsafeMutableBytes {
|
try decryptedPacket.withUnsafeMutableBytes {
|
||||||
let dest = $0.bytePointer
|
let dest = $0.bytePointer
|
||||||
try decrypter.decryptBytes(src + flags.adLength, length: encryptedCount, dest: dest + headerLength, destLength: &decryptedCount, flags: &flags)
|
try decrypter.decryptBytes(src + flags.adLength, length: encryptedCount, dest: dest + headerLength, destLength: &decryptedCount, flags: &flags)
|
||||||
|
|
|
@ -48,15 +48,8 @@ class RandomTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testRandom1() {
|
func testRandom1() {
|
||||||
print(try! SecureRandom.uint32())
|
|
||||||
print(try! SecureRandom.uint32())
|
|
||||||
print(try! SecureRandom.uint32())
|
|
||||||
print(try! SecureRandom.uint32())
|
|
||||||
print(try! SecureRandom.uint32())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testRandom2() {
|
func testRandom2() {
|
||||||
print("random UInt32: \(try! SecureRandom.uint32())")
|
|
||||||
print("random bytes: \(try! SecureRandom.data(length: 12).toHex())")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,6 @@ class RoutingTests: XCTestCase {
|
||||||
|
|
||||||
func testEntryMatch4() {
|
func testEntryMatch4() {
|
||||||
let entry24 = RoutingTableEntry(iPv4Network: "192.168.1.0/24", gateway: nil, networkInterface: "en0")
|
let entry24 = RoutingTableEntry(iPv4Network: "192.168.1.0/24", gateway: nil, networkInterface: "en0")
|
||||||
print(entry24.networkMask()!)
|
|
||||||
for i in 0x0...0xff {
|
for i in 0x0...0xff {
|
||||||
XCTAssertTrue(entry24.matchesDestination("192.168.1.\(i)"))
|
XCTAssertTrue(entry24.matchesDestination("192.168.1.\(i)"))
|
||||||
}
|
}
|
||||||
|
@ -47,7 +46,6 @@ class RoutingTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
let entry28 = RoutingTableEntry(iPv4Network: "192.168.1.0/28", gateway: nil, networkInterface: "en0")
|
let entry28 = RoutingTableEntry(iPv4Network: "192.168.1.0/28", gateway: nil, networkInterface: "en0")
|
||||||
print(entry28.networkMask()!)
|
|
||||||
for i in 0x0...0xf {
|
for i in 0x0...0xf {
|
||||||
XCTAssertTrue(entry28.matchesDestination("192.168.1.\(i)"))
|
XCTAssertTrue(entry28.matchesDestination("192.168.1.\(i)"))
|
||||||
}
|
}
|
||||||
|
@ -70,13 +68,10 @@ class RoutingTests: XCTestCase {
|
||||||
let table = RoutingTable()
|
let table = RoutingTable()
|
||||||
|
|
||||||
for entry in table.ipv4() {
|
for entry in table.ipv4() {
|
||||||
print(entry)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let defaultGateway = table.defaultGateway4()?.gateway() {
|
if let defaultGateway = table.defaultGateway4()?.gateway() {
|
||||||
print("Default gateway: \(defaultGateway)")
|
|
||||||
if let lan = table.broadestRoute4(matchingDestination: defaultGateway) {
|
if let lan = table.broadestRoute4(matchingDestination: defaultGateway) {
|
||||||
print("Gateway LAN: \(lan.network())/\(lan.prefix())")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,13 +80,10 @@ class RoutingTests: XCTestCase {
|
||||||
let table = RoutingTable()
|
let table = RoutingTable()
|
||||||
|
|
||||||
for entry in table.ipv6() {
|
for entry in table.ipv6() {
|
||||||
print(entry)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let defaultGateway = table.defaultGateway6()?.gateway() {
|
if let defaultGateway = table.defaultGateway6()?.gateway() {
|
||||||
print("Default gateway: \(defaultGateway)")
|
|
||||||
if let lan = table.broadestRoute6(matchingDestination: defaultGateway) {
|
if let lan = table.broadestRoute6(matchingDestination: defaultGateway) {
|
||||||
print("Gateway LAN: \(lan.network())/\(lan.prefix())")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,6 @@ class CompressionTests: XCTestCase {
|
||||||
|
|
||||||
override func setUp() {
|
override func setUp() {
|
||||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||||
// print("LZO version: \(LZO.versionString())")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDown() {
|
override func tearDown() {
|
||||||
|
@ -51,8 +50,6 @@ class CompressionTests: XCTestCase {
|
||||||
XCTFail("Unable to decompress data")
|
XCTFail("Unable to decompress data")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
print("BEFORE: \(src)")
|
|
||||||
print("AFTER : \(dstDecompressed)")
|
|
||||||
XCTAssertEqual(src, dstDecompressed)
|
XCTAssertEqual(src, dstDecompressed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,6 @@ class AppExtensionTests: XCTestCase {
|
||||||
guard let pc = proto.providerConfiguration else {
|
guard let pc = proto.providerConfiguration else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
print("\(pc)")
|
|
||||||
|
|
||||||
let ovpn = pc["configuration"] as? [String: Any]
|
let ovpn = pc["configuration"] as? [String: Any]
|
||||||
XCTAssertEqual(pc["appGroup"] as? String, appGroup)
|
XCTAssertEqual(pc["appGroup"] as? String, appGroup)
|
||||||
|
@ -107,11 +106,11 @@ class AppExtensionTests: XCTestCase {
|
||||||
exp.fulfill()
|
exp.fulfill()
|
||||||
}
|
}
|
||||||
switch $0 {
|
switch $0 {
|
||||||
case .success(let records):
|
case .success:
|
||||||
print("\(records)")
|
break
|
||||||
|
|
||||||
case .failure:
|
case .failure:
|
||||||
print("Can't resolve")
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
waitForExpectations(timeout: 5.0, handler: nil)
|
waitForExpectations(timeout: 5.0, handler: nil)
|
||||||
|
@ -159,7 +158,6 @@ class AppExtensionTests: XCTestCase {
|
||||||
guard let remote = strategy.currentRemote else {
|
guard let remote = strategy.currentRemote else {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
print("\(i): \(remote)")
|
|
||||||
XCTAssertEqual(remote.originalEndpoint.description, expected[i])
|
XCTAssertEqual(remote.originalEndpoint.description, expected[i])
|
||||||
i += 1
|
i += 1
|
||||||
guard strategy.tryNextEndpoint() else {
|
guard strategy.tryNextEndpoint() else {
|
||||||
|
@ -190,7 +188,6 @@ class AppExtensionTests: XCTestCase {
|
||||||
// var i = 0
|
// var i = 0
|
||||||
// while strategy.hasEndpoint() {
|
// while strategy.hasEndpoint() {
|
||||||
// let endpoint = strategy.currentEndpoint()
|
// let endpoint = strategy.currentEndpoint()
|
||||||
// print("\(endpoint)")
|
|
||||||
// XCTAssertEqual(endpoint.description, expected[i])
|
// XCTAssertEqual(endpoint.description, expected[i])
|
||||||
// i += 1
|
// i += 1
|
||||||
// strategy.tryNextEndpoint()
|
// strategy.tryNextEndpoint()
|
||||||
|
@ -219,7 +216,6 @@ class AppExtensionTests: XCTestCase {
|
||||||
// var i = 0
|
// var i = 0
|
||||||
// while strategy.hasEndpoint() {
|
// while strategy.hasEndpoint() {
|
||||||
// let endpoint = strategy.currentEndpoint()
|
// let endpoint = strategy.currentEndpoint()
|
||||||
// print("\(endpoint)")
|
|
||||||
// XCTAssertEqual(endpoint.description, expected[i])
|
// XCTAssertEqual(endpoint.description, expected[i])
|
||||||
// i += 1
|
// i += 1
|
||||||
// strategy.tryNextEndpoint()
|
// strategy.tryNextEndpoint()
|
||||||
|
|
|
@ -118,8 +118,7 @@ class ConfigurationParserTests: XCTestCase {
|
||||||
|
|
||||||
func testStripped() throws {
|
func testStripped() throws {
|
||||||
let lines = try OpenVPN.ConfigurationParser.parsed(fromURL: url(withName: "pia-hungary"), returnsStripped: true).strippedLines!
|
let lines = try OpenVPN.ConfigurationParser.parsed(fromURL: url(withName: "pia-hungary"), returnsStripped: true).strippedLines!
|
||||||
let stripped = lines.joined(separator: "\n")
|
_ = lines.joined(separator: "\n")
|
||||||
print(stripped)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testEncryptedCertificateKey() throws {
|
func testEncryptedCertificateKey() throws {
|
||||||
|
|
|
@ -60,7 +60,6 @@ class ControlChannelTests: XCTestCase {
|
||||||
let hmac = Data(hex: "e67c9137933a412a711c0d0514aca6db6476d17d")
|
let hmac = Data(hex: "e67c9137933a412a711c0d0514aca6db6476d17d")
|
||||||
let subject = Data(hex: "000000015b96c94738858fe14742fdae400000000000")
|
let subject = Data(hex: "000000015b96c94738858fe14742fdae400000000000")
|
||||||
let data = hmac + subject
|
let data = hmac + subject
|
||||||
print(data.toHex())
|
|
||||||
|
|
||||||
XCTAssertNoThrow(try server.decrypter().verifyData(data, flags: nil))
|
XCTAssertNoThrow(try server.decrypter().verifyData(data, flags: nil))
|
||||||
}
|
}
|
||||||
|
@ -98,8 +97,6 @@ class ControlChannelTests: XCTestCase {
|
||||||
XCTAssertNil(error)
|
XCTAssertNil(error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
print("raw: \(raw.toHex())")
|
|
||||||
print("org: \(original.toHex())")
|
|
||||||
XCTAssertEqual(raw, original)
|
XCTAssertEqual(raw, original)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,8 +127,6 @@ class ControlChannelTests: XCTestCase {
|
||||||
XCTAssertNil(error)
|
XCTAssertNil(error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
print("raw: \(raw.toHex())")
|
|
||||||
print("org: \(original.toHex())")
|
|
||||||
XCTAssertEqual(raw, original)
|
XCTAssertEqual(raw, original)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
//
|
||||||
|
// CryptoAEADTests.swift
|
||||||
|
// TunnelKitOpenVPNTests
|
||||||
|
//
|
||||||
|
// Created by Davide De Rosa on 12/12/23.
|
||||||
|
// Copyright (c) 2023 Davide De Rosa. All rights reserved.
|
||||||
|
//
|
||||||
|
// https://github.com/passepartoutvpn
|
||||||
|
//
|
||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
import XCTest
|
||||||
|
@testable import TunnelKitCore
|
||||||
|
@testable import TunnelKitOpenVPNCore
|
||||||
|
import CTunnelKitCore
|
||||||
|
import CTunnelKitOpenVPNProtocol
|
||||||
|
|
||||||
|
class CryptoAEADTests: XCTestCase {
|
||||||
|
private let cipherKey = ZeroingData(count: 32)
|
||||||
|
|
||||||
|
private let hmacKey = ZeroingData(count: 32)
|
||||||
|
|
||||||
|
private let plainData = Data(hex: "00112233ffddaa")
|
||||||
|
|
||||||
|
func test_givenData_whenEncrypt_thenDecrypts() {
|
||||||
|
let encryptedData: Data
|
||||||
|
var flags = cryptoFlags
|
||||||
|
|
||||||
|
let sut1 = CryptoAEAD(cipherName: "aes-256-gcm")
|
||||||
|
sut1.configureEncryption(withCipherKey: cipherKey, hmacKey: hmacKey)
|
||||||
|
do {
|
||||||
|
encryptedData = try sut1.encryptData(plainData, flags: &flags)
|
||||||
|
} catch {
|
||||||
|
XCTFail("Cannot encrypt: \(error)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let sut2 = CryptoAEAD(cipherName: "aes-256-gcm")
|
||||||
|
sut2.configureDecryption(withCipherKey: cipherKey, hmacKey: hmacKey)
|
||||||
|
do {
|
||||||
|
let returnedData = try sut2.decryptData(encryptedData, flags: &flags)
|
||||||
|
XCTAssertEqual(returnedData, plainData)
|
||||||
|
} catch {
|
||||||
|
XCTFail("Cannot decrypt: \(error)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var cryptoFlags: CryptoFlags {
|
||||||
|
let packetId: [UInt8] = [0x56, 0x34, 0x12, 0x00]
|
||||||
|
let ad: [UInt8] = [0x00, 0x12, 0x34, 0x56]
|
||||||
|
return packetId.withUnsafeBufferPointer { iv in
|
||||||
|
ad.withUnsafeBufferPointer { ad in
|
||||||
|
CryptoFlags(iv: iv.baseAddress,
|
||||||
|
ivLength: packetId.count,
|
||||||
|
ad: ad.baseAddress,
|
||||||
|
adLength: ad.count,
|
||||||
|
forTesting: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,117 @@
|
||||||
|
//
|
||||||
|
// CryptoCBCTests.swift
|
||||||
|
// TunnelKitOpenVPNTests
|
||||||
|
//
|
||||||
|
// Created by Davide De Rosa on 12/12/23.
|
||||||
|
// Copyright (c) 2023 Davide De Rosa. All rights reserved.
|
||||||
|
//
|
||||||
|
// https://github.com/passepartoutvpn
|
||||||
|
//
|
||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
import XCTest
|
||||||
|
@testable import TunnelKitCore
|
||||||
|
@testable import TunnelKitOpenVPNCore
|
||||||
|
import CTunnelKitCore
|
||||||
|
import CTunnelKitOpenVPNProtocol
|
||||||
|
|
||||||
|
class CryptoCBCTests: XCTestCase {
|
||||||
|
private let cipherKey = ZeroingData(count: 32)
|
||||||
|
|
||||||
|
private let hmacKey = ZeroingData(count: 32)
|
||||||
|
|
||||||
|
private let plainData = Data(hex: "00112233ffddaa")
|
||||||
|
|
||||||
|
private let plainHMACData = Data(hex: "8dd324c81ca32f52e4aa1aa35139deba799a68460e80b0e5ac8bceb043edf6e500112233ffddaa")
|
||||||
|
|
||||||
|
private let encryptedHMACData = Data(hex: "fea3fe87ee68eb21c697e62d3c29f7bea2f5b457d9a7fa66291322fc9c2fe6f700000000000000000000000000000000ebe197e706c3c5dcad026f4e3af1048b")
|
||||||
|
|
||||||
|
func test_givenDecrypted_whenEncryptWithoutCipher_thenEncodesWithHMAC() {
|
||||||
|
let sut = CryptoCBC(cipherName: nil, digestName: "sha256")
|
||||||
|
sut.configureEncryption(withCipherKey: nil, hmacKey: hmacKey)
|
||||||
|
|
||||||
|
var flags = cryptoFlags
|
||||||
|
do {
|
||||||
|
let returnedData = try sut.encryptData(plainData, flags: &flags)
|
||||||
|
XCTAssertEqual(returnedData, plainHMACData)
|
||||||
|
} catch {
|
||||||
|
XCTFail("Cannot encrypt: \(error)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_givenDecrypted_whenEncryptWithCipher_thenEncryptsWithHMAC() {
|
||||||
|
let sut = CryptoCBC(cipherName: "aes-128-cbc", digestName: "sha256")
|
||||||
|
sut.configureEncryption(withCipherKey: cipherKey, hmacKey: hmacKey)
|
||||||
|
|
||||||
|
var flags = cryptoFlags
|
||||||
|
do {
|
||||||
|
let returnedData = try sut.encryptData(plainData, flags: &flags)
|
||||||
|
XCTAssertEqual(returnedData, encryptedHMACData)
|
||||||
|
} catch {
|
||||||
|
XCTFail("Cannot encrypt: \(error)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_givenEncodedWithHMAC_thenDecodes() {
|
||||||
|
let sut = CryptoCBC(cipherName: nil, digestName: "sha256")
|
||||||
|
sut.configureDecryption(withCipherKey: nil, hmacKey: hmacKey)
|
||||||
|
|
||||||
|
var flags = cryptoFlags
|
||||||
|
do {
|
||||||
|
let returnedData = try sut.decryptData(plainHMACData, flags: &flags)
|
||||||
|
XCTAssertEqual(returnedData, plainData)
|
||||||
|
} catch {
|
||||||
|
XCTFail("Cannot decrypt: \(error)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_givenEncryptedWithHMAC_thenDecrypts() {
|
||||||
|
let sut = CryptoCBC(cipherName: "aes-128-cbc", digestName: "sha256")
|
||||||
|
sut.configureDecryption(withCipherKey: cipherKey, hmacKey: hmacKey)
|
||||||
|
|
||||||
|
var flags = cryptoFlags
|
||||||
|
do {
|
||||||
|
let returnedData = try sut.decryptData(encryptedHMACData, flags: &flags)
|
||||||
|
XCTAssertEqual(returnedData, plainData)
|
||||||
|
} catch {
|
||||||
|
XCTFail("Cannot decrypt: \(error)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_givenHMAC_thenVerifies() {
|
||||||
|
let sut = CryptoCBC(cipherName: nil, digestName: "sha256")
|
||||||
|
sut.configureDecryption(withCipherKey: nil, hmacKey: hmacKey)
|
||||||
|
|
||||||
|
var flags = cryptoFlags
|
||||||
|
XCTAssertNoThrow(try sut.verifyData(plainHMACData, flags: &flags))
|
||||||
|
XCTAssertNoThrow(try sut.verifyData(encryptedHMACData, flags: &flags))
|
||||||
|
}
|
||||||
|
|
||||||
|
private var cryptoFlags: CryptoFlags {
|
||||||
|
let packetId: [UInt8] = [0x56, 0x34, 0x12, 0x00]
|
||||||
|
let ad: [UInt8] = [0x00, 0x12, 0x34, 0x56]
|
||||||
|
return packetId.withUnsafeBufferPointer { iv in
|
||||||
|
ad.withUnsafeBufferPointer { ad in
|
||||||
|
CryptoFlags(iv: iv.baseAddress,
|
||||||
|
ivLength: packetId.count,
|
||||||
|
ad: ad.baseAddress,
|
||||||
|
adLength: ad.count,
|
||||||
|
forTesting: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
//
|
||||||
|
// CryptoCTRTests.swift
|
||||||
|
// TunnelKitOpenVPNTests
|
||||||
|
//
|
||||||
|
// Created by Davide De Rosa on 12/12/23.
|
||||||
|
// Copyright (c) 2023 Davide De Rosa. All rights reserved.
|
||||||
|
//
|
||||||
|
// https://github.com/passepartoutvpn
|
||||||
|
//
|
||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
import XCTest
|
||||||
|
@testable import TunnelKitCore
|
||||||
|
@testable import TunnelKitOpenVPNCore
|
||||||
|
import CTunnelKitCore
|
||||||
|
import CTunnelKitOpenVPNProtocol
|
||||||
|
|
||||||
|
class CryptoCTRTests: XCTestCase {
|
||||||
|
private let cipherKey = ZeroingData(count: 32)
|
||||||
|
|
||||||
|
private let hmacKey = ZeroingData(count: 32)
|
||||||
|
|
||||||
|
private let plainData = Data(hex: "00112233ffddaa")
|
||||||
|
|
||||||
|
func test_givenData_whenEncrypt_thenDecrypts() {
|
||||||
|
let encryptedData: Data
|
||||||
|
var flags = cryptoFlags
|
||||||
|
|
||||||
|
let sut1 = CryptoCTR(cipherName: "aes-128-ctr", digestName: "sha256")
|
||||||
|
sut1.configureEncryption(withCipherKey: cipherKey, hmacKey: hmacKey)
|
||||||
|
do {
|
||||||
|
encryptedData = try sut1.encryptData(plainData, flags: &flags)
|
||||||
|
} catch {
|
||||||
|
XCTFail("Cannot encrypt: \(error)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let sut2 = CryptoCTR(cipherName: "aes-128-ctr", digestName: "sha256")
|
||||||
|
sut2.configureDecryption(withCipherKey: cipherKey, hmacKey: hmacKey)
|
||||||
|
do {
|
||||||
|
let returnedData = try sut2.decryptData(encryptedData, flags: &flags)
|
||||||
|
XCTAssertEqual(returnedData, plainData)
|
||||||
|
} catch {
|
||||||
|
XCTFail("Cannot decrypt: \(error)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var cryptoFlags: CryptoFlags {
|
||||||
|
let packetId: [UInt8] = [0x56, 0x34, 0x12, 0x00]
|
||||||
|
let ad: [UInt8] = [0x00, 0x12, 0x34, 0x56]
|
||||||
|
return packetId.withUnsafeBufferPointer { iv in
|
||||||
|
ad.withUnsafeBufferPointer { ad in
|
||||||
|
CryptoFlags(iv: iv.baseAddress,
|
||||||
|
ivLength: packetId.count,
|
||||||
|
ad: ad.baseAddress,
|
||||||
|
adLength: ad.count,
|
||||||
|
forTesting: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -108,9 +108,7 @@ class DataPathEncryptionTests: XCTestCase {
|
||||||
let key: UInt8 = 4
|
let key: UInt8 = 4
|
||||||
|
|
||||||
let encrypted = try! path.encryptPackets([expectedPayload], key: key)
|
let encrypted = try! path.encryptPackets([expectedPayload], key: key)
|
||||||
print(encrypted.map { $0.toHex() })
|
|
||||||
let decrypted = try! path.decryptPackets(encrypted, keepAlive: nil)
|
let decrypted = try! path.decryptPackets(encrypted, keepAlive: nil)
|
||||||
print(decrypted.map { $0.toHex() })
|
|
||||||
let payload = decrypted.first!
|
let payload = decrypted.first!
|
||||||
|
|
||||||
XCTAssertEqual(payload, expectedPayload)
|
XCTAssertEqual(payload, expectedPayload)
|
||||||
|
|
|
@ -82,7 +82,6 @@ class DataPathPerformanceTests: XCTestCase {
|
||||||
// decryptedPackets = try! self.swiftDP.decryptPackets(encryptedPackets, keepAlive: nil)
|
// decryptedPackets = try! self.swiftDP.decryptPackets(encryptedPackets, keepAlive: nil)
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
//// print(">>> \(packets?.count) packets")
|
|
||||||
// XCTAssertEqual(decryptedPackets, packets)
|
// XCTAssertEqual(decryptedPackets, packets)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
@ -97,7 +96,6 @@ class DataPathPerformanceTests: XCTestCase {
|
||||||
decryptedPackets = try! self.dataPath.decryptPackets(encryptedPackets, keepAlive: nil)
|
decryptedPackets = try! self.dataPath.decryptPackets(encryptedPackets, keepAlive: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// print(">>> \(packets?.count) packets")
|
|
||||||
XCTAssertEqual(decryptedPackets, packets)
|
XCTAssertEqual(decryptedPackets, packets)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,11 @@ class EncryptionPerformanceTests: XCTestCase {
|
||||||
let suite = TestUtils.generateDataSuite(1000, 100000)
|
let suite = TestUtils.generateDataSuite(1000, 100000)
|
||||||
let ad: [UInt8] = [0x11, 0x22, 0x33, 0x44]
|
let ad: [UInt8] = [0x11, 0x22, 0x33, 0x44]
|
||||||
var flags = ad.withUnsafeBufferPointer {
|
var flags = ad.withUnsafeBufferPointer {
|
||||||
return CryptoFlags(iv: nil, ivLength: 0, ad: $0.baseAddress, adLength: ad.count)
|
CryptoFlags(iv: nil,
|
||||||
|
ivLength: 0,
|
||||||
|
ad: $0.baseAddress,
|
||||||
|
adLength: ad.count,
|
||||||
|
forTesting: true)
|
||||||
}
|
}
|
||||||
measure {
|
measure {
|
||||||
for data in suite {
|
for data in suite {
|
||||||
|
|
|
@ -82,9 +82,13 @@ class EncryptionTests: XCTestCase {
|
||||||
|
|
||||||
let packetId: [UInt8] = [0x56, 0x34, 0x12, 0x00]
|
let packetId: [UInt8] = [0x56, 0x34, 0x12, 0x00]
|
||||||
let ad: [UInt8] = [0x00, 0x12, 0x34, 0x56]
|
let ad: [UInt8] = [0x00, 0x12, 0x34, 0x56]
|
||||||
var flags = packetId.withUnsafeBufferPointer { (iv) in
|
var flags = packetId.withUnsafeBufferPointer { iv in
|
||||||
return ad.withUnsafeBufferPointer { (ad) in
|
ad.withUnsafeBufferPointer { ad in
|
||||||
return CryptoFlags(iv: iv.baseAddress, ivLength: packetId.count, ad: ad.baseAddress, adLength: ad.count)
|
CryptoFlags(iv: iv.baseAddress,
|
||||||
|
ivLength: packetId.count,
|
||||||
|
ad: ad.baseAddress,
|
||||||
|
adLength: ad.count,
|
||||||
|
forTesting: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let plain = Data(hex: "00112233445566778899")
|
let plain = Data(hex: "00112233445566778899")
|
||||||
|
@ -99,16 +103,18 @@ class EncryptionTests: XCTestCase {
|
||||||
let original = Data(hex: "0000000000")
|
let original = Data(hex: "0000000000")
|
||||||
let ad: [UInt8] = [UInt8](Data(hex: "38afa8f1162096081e000000015ba35373"))
|
let ad: [UInt8] = [UInt8](Data(hex: "38afa8f1162096081e000000015ba35373"))
|
||||||
var flags = ad.withUnsafeBufferPointer {
|
var flags = ad.withUnsafeBufferPointer {
|
||||||
CryptoFlags(iv: nil, ivLength: 0, ad: $0.baseAddress, adLength: ad.count)
|
CryptoFlags(iv: nil,
|
||||||
|
ivLength: 0,
|
||||||
|
ad: $0.baseAddress,
|
||||||
|
adLength: ad.count,
|
||||||
|
forTesting: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// let expEncrypted = Data(hex: "319bb8e7f8f7930cc4625079dd32a6ef9540c2fc001c53f909f712037ae9818af840b88714")
|
// let expEncrypted = Data(hex: "319bb8e7f8f7930cc4625079dd32a6ef9540c2fc001c53f909f712037ae9818af840b88714")
|
||||||
let encrypted = try! client.encrypter().encryptData(original, flags: &flags)
|
let encrypted = try! client.encrypter().encryptData(original, flags: &flags)
|
||||||
print(encrypted.toHex())
|
|
||||||
// XCTAssertEqual(encrypted, expEncrypted)
|
// XCTAssertEqual(encrypted, expEncrypted)
|
||||||
|
|
||||||
let decrypted = try! server.decrypter().decryptData(encrypted, flags: &flags)
|
let decrypted = try! server.decrypter().decryptData(encrypted, flags: &flags)
|
||||||
print(decrypted.toHex())
|
|
||||||
XCTAssertEqual(decrypted, original)
|
XCTAssertEqual(decrypted, original)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,7 +122,6 @@ class EncryptionTests: XCTestCase {
|
||||||
let path = Bundle.module.path(forResource: "pia-2048", ofType: "pem")!
|
let path = Bundle.module.path(forResource: "pia-2048", ofType: "pem")!
|
||||||
let md5 = try! TLSBox.md5(forCertificatePath: path)
|
let md5 = try! TLSBox.md5(forCertificatePath: path)
|
||||||
let exp = "e2fccccaba712ccc68449b1c56427ac1"
|
let exp = "e2fccccaba712ccc68449b1c56427ac1"
|
||||||
print(md5)
|
|
||||||
XCTAssertEqual(md5, exp)
|
XCTAssertEqual(md5, exp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,10 +137,8 @@ class EncryptionTests: XCTestCase {
|
||||||
|
|
||||||
XCTAssertThrowsError(try TLSBox.decryptedPrivateKey(fromPath: encryptedPath, passphrase: "wrongone"))
|
XCTAssertThrowsError(try TLSBox.decryptedPrivateKey(fromPath: encryptedPath, passphrase: "wrongone"))
|
||||||
let decryptedViaPath = try! TLSBox.decryptedPrivateKey(fromPath: encryptedPath, passphrase: "foobar")
|
let decryptedViaPath = try! TLSBox.decryptedPrivateKey(fromPath: encryptedPath, passphrase: "foobar")
|
||||||
print(decryptedViaPath)
|
|
||||||
let encryptedPEM = try! String(contentsOfFile: encryptedPath, encoding: .utf8)
|
let encryptedPEM = try! String(contentsOfFile: encryptedPath, encoding: .utf8)
|
||||||
let decryptedViaString = try! TLSBox.decryptedPrivateKey(fromPEM: encryptedPEM, passphrase: "foobar")
|
let decryptedViaString = try! TLSBox.decryptedPrivateKey(fromPEM: encryptedPEM, passphrase: "foobar")
|
||||||
print(decryptedViaString)
|
|
||||||
XCTAssertEqual(decryptedViaPath, decryptedViaString)
|
XCTAssertEqual(decryptedViaPath, decryptedViaString)
|
||||||
|
|
||||||
let expDecrypted = try! String(contentsOfFile: decryptedPath)
|
let expDecrypted = try! String(contentsOfFile: decryptedPath)
|
||||||
|
|
|
@ -152,7 +152,6 @@ class LinkTests: XCTestCase {
|
||||||
enqueueControl(&q, &id, p) {
|
enqueueControl(&q, &id, p) {
|
||||||
hdl.append($0)
|
hdl.append($0)
|
||||||
}
|
}
|
||||||
print()
|
|
||||||
}
|
}
|
||||||
return hdl
|
return hdl
|
||||||
}
|
}
|
||||||
|
@ -163,10 +162,7 @@ class LinkTests: XCTestCase {
|
||||||
return (p1 < p2)
|
return (p1 < p2)
|
||||||
}
|
}
|
||||||
|
|
||||||
print("q = \(q)")
|
|
||||||
print("id = \(id)")
|
|
||||||
for p in q {
|
for p in q {
|
||||||
print("test(\(p))")
|
|
||||||
if p < id {
|
if p < id {
|
||||||
q.removeFirst()
|
q.removeFirst()
|
||||||
continue
|
continue
|
||||||
|
@ -176,7 +172,6 @@ class LinkTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
h(p)
|
h(p)
|
||||||
print("handle(\(p))")
|
|
||||||
id += 1
|
id += 1
|
||||||
q.removeFirst()
|
q.removeFirst()
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,8 +48,6 @@ class PacketTests: XCTestCase {
|
||||||
|
|
||||||
let serialized = ControlPacket(code: code, key: key, sessionId: sessionId, packetId: id, payload: payload).serialized()
|
let serialized = ControlPacket(code: code, key: key, sessionId: sessionId, packetId: id, payload: payload).serialized()
|
||||||
let expected = Data(hex: "2311223344556677880000001456932748238742397591704891")
|
let expected = Data(hex: "2311223344556677880000001456932748238742397591704891")
|
||||||
print("Serialized: \(serialized.toHex())")
|
|
||||||
print("Expected : \(expected.toHex())")
|
|
||||||
|
|
||||||
XCTAssertEqual(serialized, expected)
|
XCTAssertEqual(serialized, expected)
|
||||||
}
|
}
|
||||||
|
@ -62,8 +60,6 @@ class PacketTests: XCTestCase {
|
||||||
|
|
||||||
let serialized = ControlPacket(key: key, sessionId: sessionId, ackIds: acks as [NSNumber], ackRemoteSessionId: remoteSessionId).serialized()
|
let serialized = ControlPacket(key: key, sessionId: sessionId, ackIds: acks as [NSNumber], ackRemoteSessionId: remoteSessionId).serialized()
|
||||||
let expected = Data(hex: "2b112233445566778805000000aa000000bb000000cc000000dd000000eea639328cbf03490e")
|
let expected = Data(hex: "2b112233445566778805000000aa000000bb000000cc000000dd000000eea639328cbf03490e")
|
||||||
print("Serialized: \(serialized.toHex())")
|
|
||||||
print("Expected : \(expected.toHex())")
|
|
||||||
|
|
||||||
XCTAssertEqual(serialized, expected)
|
XCTAssertEqual(serialized, expected)
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,11 +31,6 @@ import XCTest
|
||||||
|
|
||||||
private extension OpenVPN.PushReply {
|
private extension OpenVPN.PushReply {
|
||||||
func debug() {
|
func debug() {
|
||||||
print("Compression framing: \(options.compressionFraming?.description ?? "disabled")")
|
|
||||||
print("Compression algorithm: \(options.compressionAlgorithm?.description ?? "disabled")")
|
|
||||||
print("IPv4: \(options.ipv4?.description ?? "none")")
|
|
||||||
print("IPv6: \(options.ipv6?.description ?? "none")")
|
|
||||||
print("DNS: \(options.dnsServers?.description ?? "none")")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,7 +169,6 @@ class PushTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPeerInfo() {
|
func testPeerInfo() {
|
||||||
let peerInfo = CoreConfiguration.OpenVPN.peerInfo()
|
_ = CoreConfiguration.OpenVPN.peerInfo()
|
||||||
print(peerInfo)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue