mirror of
https://github.com/passepartoutvpn/passepartout-apple.git
synced 2025-02-01 21:42:10 +00:00
Minimize dependencies of VPN implementations (#1057)
### OpenVPN - Make CPassepartoutCryptoOpenSSL agnostic of PassepartoutKit - Move Allocation/ZeroingData from PassepartoutKit to package for internal use - Rename ZeroingData.count to .length for consistency with NSData - Duplicate some Data manipulation code in CryptoOpenSSL - Retain a simplified version of ZeroingData in PassepartoutKit (AutoerasingData) ### WireGuard - Make WireGuardKit imports `internal`
This commit is contained in:
parent
53ee7ba457
commit
7b8dbfe84a
@ -133,10 +133,10 @@ extension OpenVPN.XORMethod: StyledLocalizableEntity {
|
||||
private var longDescription: String {
|
||||
switch self {
|
||||
case .xormask(let mask):
|
||||
return "\(shortDescription) \(mask.zData.toHex())"
|
||||
return "\(shortDescription) \(mask.toHex())"
|
||||
|
||||
case .obfuscate(let mask):
|
||||
return "\(shortDescription) \(mask.zData.toHex())"
|
||||
return "\(shortDescription) \(mask.toHex())"
|
||||
|
||||
default:
|
||||
return shortDescription
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 358cd688354a7ab4f6ad46a471b4ab192525a692
|
||||
Subproject commit c4901c59970d8314ba75fa7453c016c3508f4074
|
@ -31,14 +31,14 @@ let package = Package(
|
||||
targets: [
|
||||
.target(
|
||||
name: "CPassepartoutCryptoOpenSSL",
|
||||
dependencies: [
|
||||
"openssl-apple",
|
||||
"PassepartoutKit-Framework"
|
||||
]
|
||||
dependencies: ["openssl-apple",]
|
||||
),
|
||||
.target(
|
||||
name: "CPassepartoutOpenVPNOpenSSL",
|
||||
dependencies: ["CPassepartoutCryptoOpenSSL"],
|
||||
dependencies: [
|
||||
"CPassepartoutCryptoOpenSSL",
|
||||
"PassepartoutKit-Framework"
|
||||
],
|
||||
exclude: [
|
||||
"lib/COPYING",
|
||||
"lib/Makefile",
|
||||
@ -58,7 +58,7 @@ let package = Package(
|
||||
]
|
||||
),
|
||||
.testTarget(
|
||||
name: "PassepartoutCryptoOpenSSLTests",
|
||||
name: "CPassepartoutCryptoOpenSSLTests",
|
||||
dependencies: ["PassepartoutCryptoOpenSSL"]
|
||||
),
|
||||
.testTarget(
|
||||
|
@ -25,10 +25,4 @@
|
||||
|
||||
#import "Crypto.h"
|
||||
|
||||
#define MAX_BLOCK_SIZE 16 // AES only, block is 128-bit
|
||||
|
||||
size_t pp_alloc_crypto_capacity(size_t size, size_t overhead) {
|
||||
|
||||
// encryption, byte-alignment, overhead (e.g. IV, digest)
|
||||
return 2 * size + MAX_BLOCK_SIZE + overhead;
|
||||
}
|
||||
NSString *const PassepartoutCryptoErrorDomain = @"PassepartoutCrypto";
|
||||
|
@ -34,11 +34,12 @@
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#import <PassepartoutKit/PassepartoutKit.h>
|
||||
#import <openssl/evp.h>
|
||||
|
||||
#import "Allocation.h"
|
||||
#import "Crypto.h"
|
||||
#import "CryptoAEAD.h"
|
||||
#import "CryptoMacros.h"
|
||||
#import "ZeroingData.h"
|
||||
|
||||
@interface CryptoAEAD ()
|
||||
|
||||
@ -75,8 +76,8 @@
|
||||
|
||||
self.cipherCtxEnc = EVP_CIPHER_CTX_new();
|
||||
self.cipherCtxDec = EVP_CIPHER_CTX_new();
|
||||
self.cipherIVEnc = pp_alloc(self.cipherIVLength);
|
||||
self.cipherIVDec = pp_alloc(self.cipherIVLength);
|
||||
self.cipherIVEnc = pp_alloc_crypto(self.cipherIVLength);
|
||||
self.cipherIVDec = pp_alloc_crypto(self.cipherIVLength);
|
||||
|
||||
self.mappedError = ^NSError *(CryptoAEADError errorCode) {
|
||||
return [NSError errorWithDomain:PassepartoutCryptoErrorDomain code:0 userInfo:nil];
|
||||
@ -116,7 +117,7 @@
|
||||
|
||||
- (void)configureEncryptionWithCipherKey:(ZeroingData *)cipherKey hmacKey:(ZeroingData *)hmacKey
|
||||
{
|
||||
NSParameterAssert(cipherKey.count >= self.cipherKeyLength);
|
||||
NSParameterAssert(cipherKey.length >= self.cipherKeyLength);
|
||||
NSParameterAssert(hmacKey);
|
||||
|
||||
EVP_CIPHER_CTX_reset(self.cipherCtxEnc);
|
||||
@ -157,7 +158,7 @@
|
||||
|
||||
- (void)configureDecryptionWithCipherKey:(ZeroingData *)cipherKey hmacKey:(ZeroingData *)hmacKey
|
||||
{
|
||||
NSParameterAssert(cipherKey.count >= self.cipherKeyLength);
|
||||
NSParameterAssert(cipherKey.length >= self.cipherKeyLength);
|
||||
NSParameterAssert(hmacKey);
|
||||
|
||||
EVP_CIPHER_CTX_reset(self.cipherCtxDec);
|
||||
|
@ -34,12 +34,13 @@
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#import <PassepartoutKit/PassepartoutKit.h>
|
||||
#import <openssl/evp.h>
|
||||
#import <openssl/rand.h>
|
||||
|
||||
#import "Allocation.h"
|
||||
#import "Crypto.h"
|
||||
#import "CryptoCBC.h"
|
||||
#import "CryptoMacros.h"
|
||||
#import "ZeroingData.h"
|
||||
|
||||
const NSInteger CryptoCBCMaxHMACLength = 100;
|
||||
|
||||
@ -103,7 +104,7 @@ const NSInteger CryptoCBCMaxHMACLength = 100;
|
||||
macParams[1] = OSSL_PARAM_construct_end();
|
||||
self.macParams = macParams;
|
||||
|
||||
self.bufferDecHMAC = pp_alloc(CryptoCBCMaxHMACLength);
|
||||
self.bufferDecHMAC = pp_alloc_crypto(CryptoCBCMaxHMACLength);
|
||||
|
||||
self.mappedError = ^NSError *(CryptoCBCError errorCode) {
|
||||
return [NSError errorWithDomain:PassepartoutCryptoErrorDomain code:0 userInfo:nil];
|
||||
@ -147,16 +148,16 @@ const NSInteger CryptoCBCMaxHMACLength = 100;
|
||||
- (void)configureEncryptionWithCipherKey:(ZeroingData *)cipherKey hmacKey:(ZeroingData *)hmacKey
|
||||
{
|
||||
NSParameterAssert(hmacKey);
|
||||
NSParameterAssert(hmacKey.count >= self.hmacKeyLength);
|
||||
NSParameterAssert(hmacKey.length >= self.hmacKeyLength);
|
||||
|
||||
if (self.cipher) {
|
||||
NSParameterAssert(cipherKey.count >= self.cipherKeyLength);
|
||||
NSParameterAssert(cipherKey.length >= self.cipherKeyLength);
|
||||
|
||||
EVP_CIPHER_CTX_reset(self.cipherCtxEnc);
|
||||
EVP_CipherInit(self.cipherCtxEnc, self.cipher, cipherKey.bytes, NULL, 1);
|
||||
}
|
||||
|
||||
self.hmacKeyEnc = [[ZeroingData alloc] initWithBytes:hmacKey.bytes count:self.hmacKeyLength];
|
||||
self.hmacKeyEnc = [[ZeroingData alloc] initWithBytes:hmacKey.bytes length:self.hmacKeyLength];
|
||||
}
|
||||
|
||||
- (BOOL)encryptBytes:(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
|
||||
@ -188,7 +189,7 @@ const NSInteger CryptoCBCMaxHMACLength = 100;
|
||||
l1 = (int)length;
|
||||
}
|
||||
EVP_MAC_CTX *ctx = EVP_MAC_CTX_new(self.mac);
|
||||
CRYPTO_OPENSSL_TRACK_STATUS(code) EVP_MAC_init(ctx, self.hmacKeyEnc.bytes, self.hmacKeyEnc.count, self.macParams);
|
||||
CRYPTO_OPENSSL_TRACK_STATUS(code) EVP_MAC_init(ctx, self.hmacKeyEnc.bytes, self.hmacKeyEnc.length, self.macParams);
|
||||
CRYPTO_OPENSSL_TRACK_STATUS(code) EVP_MAC_update(ctx, outIV, l1 + l2 + self.cipherIVLength);
|
||||
CRYPTO_OPENSSL_TRACK_STATUS(code) EVP_MAC_final(ctx, dest, &l3, self.digestLength);
|
||||
EVP_MAC_CTX_free(ctx);
|
||||
@ -203,16 +204,16 @@ const NSInteger CryptoCBCMaxHMACLength = 100;
|
||||
- (void)configureDecryptionWithCipherKey:(ZeroingData *)cipherKey hmacKey:(ZeroingData *)hmacKey
|
||||
{
|
||||
NSParameterAssert(hmacKey);
|
||||
NSParameterAssert(hmacKey.count >= self.hmacKeyLength);
|
||||
NSParameterAssert(hmacKey.length >= self.hmacKeyLength);
|
||||
|
||||
if (self.cipher) {
|
||||
NSParameterAssert(cipherKey.count >= self.cipherKeyLength);
|
||||
NSParameterAssert(cipherKey.length >= self.cipherKeyLength);
|
||||
|
||||
EVP_CIPHER_CTX_reset(self.cipherCtxDec);
|
||||
EVP_CipherInit(self.cipherCtxDec, self.cipher, cipherKey.bytes, NULL, 0);
|
||||
}
|
||||
|
||||
self.hmacKeyDec = [[ZeroingData alloc] initWithBytes:hmacKey.bytes count:self.hmacKeyLength];
|
||||
self.hmacKeyDec = [[ZeroingData alloc] initWithBytes:hmacKey.bytes length:self.hmacKeyLength];
|
||||
}
|
||||
|
||||
- (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
|
||||
@ -223,7 +224,7 @@ const NSInteger CryptoCBCMaxHMACLength = 100;
|
||||
int code = 1;
|
||||
|
||||
EVP_MAC_CTX *ctx = EVP_MAC_CTX_new(self.mac);
|
||||
CRYPTO_OPENSSL_TRACK_STATUS(code) EVP_MAC_init(ctx, self.hmacKeyDec.bytes, self.hmacKeyDec.count, self.macParams);
|
||||
CRYPTO_OPENSSL_TRACK_STATUS(code) EVP_MAC_init(ctx, self.hmacKeyDec.bytes, self.hmacKeyDec.length, self.macParams);
|
||||
CRYPTO_OPENSSL_TRACK_STATUS(code) EVP_MAC_update(ctx, bytes + self.digestLength, length - self.digestLength);
|
||||
CRYPTO_OPENSSL_TRACK_STATUS(code) EVP_MAC_final(ctx, self.bufferDecHMAC, &l1, self.digestLength);
|
||||
EVP_MAC_CTX_free(ctx);
|
||||
@ -257,7 +258,7 @@ const NSInteger CryptoCBCMaxHMACLength = 100;
|
||||
int code = 1;
|
||||
|
||||
EVP_MAC_CTX *ctx = EVP_MAC_CTX_new(self.mac);
|
||||
CRYPTO_OPENSSL_TRACK_STATUS(code) EVP_MAC_init(ctx, self.hmacKeyDec.bytes, self.hmacKeyDec.count, self.macParams);
|
||||
CRYPTO_OPENSSL_TRACK_STATUS(code) EVP_MAC_init(ctx, self.hmacKeyDec.bytes, self.hmacKeyDec.length, self.macParams);
|
||||
CRYPTO_OPENSSL_TRACK_STATUS(code) EVP_MAC_update(ctx, bytes + self.digestLength, length - self.digestLength);
|
||||
CRYPTO_OPENSSL_TRACK_STATUS(code) EVP_MAC_final(ctx, self.bufferDecHMAC, &l1, self.digestLength);
|
||||
EVP_MAC_CTX_free(ctx);
|
||||
|
@ -23,11 +23,12 @@
|
||||
// along with PassepartoutKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
#import <PassepartoutKit/PassepartoutKit.h>
|
||||
#import <openssl/evp.h>
|
||||
|
||||
#import "Allocation.h"
|
||||
#import "Crypto.h"
|
||||
#import "CryptoCTR.h"
|
||||
#import "CryptoMacros.h"
|
||||
#import "ZeroingData.h"
|
||||
|
||||
@interface CryptoCTR ()
|
||||
|
||||
@ -92,7 +93,7 @@
|
||||
macParams[1] = OSSL_PARAM_construct_end();
|
||||
self.macParams = macParams;
|
||||
|
||||
self.bufferDecHMAC = pp_alloc(self.tagLength);
|
||||
self.bufferDecHMAC = pp_alloc_crypto(self.tagLength);
|
||||
|
||||
self.mappedError = ^NSError *(CryptoCTRError errorCode) {
|
||||
return [NSError errorWithDomain:PassepartoutCryptoErrorDomain code:0 userInfo:nil];
|
||||
@ -137,13 +138,13 @@
|
||||
- (void)configureEncryptionWithCipherKey:(ZeroingData *)cipherKey hmacKey:(ZeroingData *)hmacKey
|
||||
{
|
||||
NSParameterAssert(hmacKey);
|
||||
NSParameterAssert(hmacKey.count >= self.hmacKeyLength);
|
||||
NSParameterAssert(cipherKey.count >= self.cipherKeyLength);
|
||||
NSParameterAssert(hmacKey.length >= self.hmacKeyLength);
|
||||
NSParameterAssert(cipherKey.length >= self.cipherKeyLength);
|
||||
|
||||
EVP_CIPHER_CTX_reset(self.cipherCtxEnc);
|
||||
EVP_CipherInit(self.cipherCtxEnc, self.cipher, cipherKey.bytes, NULL, 1);
|
||||
|
||||
self.hmacKeyEnc = [[ZeroingData alloc] initWithBytes:hmacKey.bytes count:self.hmacKeyLength];
|
||||
self.hmacKeyEnc = [[ZeroingData alloc] initWithBytes:hmacKey.bytes length:self.hmacKeyLength];
|
||||
}
|
||||
|
||||
- (BOOL)encryptBytes:(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
|
||||
@ -156,7 +157,7 @@
|
||||
int code = 1;
|
||||
|
||||
EVP_MAC_CTX *ctx = EVP_MAC_CTX_new(self.mac);
|
||||
CRYPTO_OPENSSL_TRACK_STATUS(code) EVP_MAC_init(ctx, self.hmacKeyEnc.bytes, self.hmacKeyEnc.count, self.macParams);
|
||||
CRYPTO_OPENSSL_TRACK_STATUS(code) EVP_MAC_init(ctx, self.hmacKeyEnc.bytes, self.hmacKeyEnc.length, self.macParams);
|
||||
CRYPTO_OPENSSL_TRACK_STATUS(code) EVP_MAC_update(ctx, flags->ad, flags->adLength);
|
||||
CRYPTO_OPENSSL_TRACK_STATUS(code) EVP_MAC_update(ctx, bytes, length);
|
||||
CRYPTO_OPENSSL_TRACK_STATUS(code) EVP_MAC_final(ctx, dest, &l3, self.digestLength);
|
||||
@ -178,13 +179,13 @@
|
||||
- (void)configureDecryptionWithCipherKey:(ZeroingData *)cipherKey hmacKey:(ZeroingData *)hmacKey
|
||||
{
|
||||
NSParameterAssert(hmacKey);
|
||||
NSParameterAssert(hmacKey.count >= self.hmacKeyLength);
|
||||
NSParameterAssert(cipherKey.count >= self.cipherKeyLength);
|
||||
NSParameterAssert(hmacKey.length >= self.hmacKeyLength);
|
||||
NSParameterAssert(cipherKey.length >= self.cipherKeyLength);
|
||||
|
||||
EVP_CIPHER_CTX_reset(self.cipherCtxDec);
|
||||
EVP_CipherInit(self.cipherCtxDec, self.cipher, cipherKey.bytes, NULL, 0);
|
||||
|
||||
self.hmacKeyDec = [[ZeroingData alloc] initWithBytes:hmacKey.bytes count:self.hmacKeyLength];
|
||||
self.hmacKeyDec = [[ZeroingData alloc] initWithBytes:hmacKey.bytes length:self.hmacKeyLength];
|
||||
}
|
||||
|
||||
- (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
|
||||
@ -205,7 +206,7 @@
|
||||
*destLength = l1 + l2;
|
||||
|
||||
EVP_MAC_CTX *ctx = EVP_MAC_CTX_new(self.mac);
|
||||
CRYPTO_OPENSSL_TRACK_STATUS(code) EVP_MAC_init(ctx, self.hmacKeyDec.bytes, self.hmacKeyDec.count, self.macParams);
|
||||
CRYPTO_OPENSSL_TRACK_STATUS(code) EVP_MAC_init(ctx, self.hmacKeyDec.bytes, self.hmacKeyDec.length, self.macParams);
|
||||
CRYPTO_OPENSSL_TRACK_STATUS(code) EVP_MAC_update(ctx, flags->ad, flags->adLength);
|
||||
CRYPTO_OPENSSL_TRACK_STATUS(code) EVP_MAC_update(ctx, dest, *destLength);
|
||||
CRYPTO_OPENSSL_TRACK_STATUS(code) EVP_MAC_final(ctx, self.bufferDecHMAC, &l3, self.digestLength);
|
||||
|
@ -0,0 +1,319 @@
|
||||
//
|
||||
// ZeroingData.m
|
||||
// PassepartoutKit
|
||||
//
|
||||
// Created by Davide De Rosa on 4/28/17.
|
||||
// Copyright (c) 2024 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of PassepartoutKit.
|
||||
//
|
||||
// PassepartoutKit 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.
|
||||
//
|
||||
// PassepartoutKit 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 PassepartoutKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// This file incorporates work covered by the following copyright and
|
||||
// permission notice:
|
||||
//
|
||||
// Copyright (c) 2018-Present Private Internet Access
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#import "ZeroingData.h"
|
||||
#import "Allocation.h"
|
||||
|
||||
@interface ZeroingData () {
|
||||
uint8_t *_bytes;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation ZeroingData
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
return [self initWithBytes:NULL length:0];
|
||||
}
|
||||
|
||||
- (instancetype)initWithLength:(NSInteger)length
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_length = length;
|
||||
_bytes = pp_alloc_crypto(length);
|
||||
bzero(_bytes, _length);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithBytes:(const uint8_t *)bytes length:(NSInteger)length
|
||||
{
|
||||
// NSParameterAssert(bytes);
|
||||
|
||||
if ((self = [super init])) {
|
||||
_length = length;
|
||||
_bytes = pp_alloc_crypto(length);
|
||||
memcpy(_bytes, bytes, length);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithBytesNoCopy:(uint8_t *)bytes length:(NSInteger)length
|
||||
{
|
||||
NSParameterAssert(bytes);
|
||||
|
||||
if ((self = [super init])) {
|
||||
_length = length;
|
||||
_bytes = bytes;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithUInt8:(uint8_t)uint8
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_length = 1;
|
||||
_bytes = pp_alloc_crypto(_length);
|
||||
_bytes[0] = uint8;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithUInt16:(uint16_t)uint16
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_length = 2;
|
||||
_bytes = pp_alloc_crypto(_length);
|
||||
_bytes[0] = (uint16 & 0xff);
|
||||
_bytes[1] = (uint16 >> 8);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithData:(NSData *)data
|
||||
{
|
||||
return [self initWithData:data offset:0 length:data.length];
|
||||
}
|
||||
|
||||
- (instancetype)initWithData:(NSData *)data offset:(NSInteger)offset length:(NSInteger)length
|
||||
{
|
||||
NSParameterAssert(data);
|
||||
NSParameterAssert(length >= 0);
|
||||
NSParameterAssert(offset + length <= data.length);
|
||||
|
||||
if ((self = [super init])) {
|
||||
_length = length;
|
||||
_bytes = pp_alloc_crypto(length);
|
||||
memcpy(_bytes, data.bytes + offset, length);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithString:(NSString *)string nullTerminated:(BOOL)nullTerminated
|
||||
{
|
||||
NSParameterAssert(string);
|
||||
|
||||
if ((self = [super init])) {
|
||||
const int stringLength = (int)string.length;
|
||||
_length = stringLength + (nullTerminated ? 1 : 0);
|
||||
_bytes = pp_alloc_crypto(_length);
|
||||
|
||||
const char *stringBytes = [string cStringUsingEncoding:NSUTF8StringEncoding];
|
||||
if (stringBytes) {
|
||||
memcpy(_bytes, stringBytes, stringLength);
|
||||
} else {
|
||||
NSAssert(stringBytes != NULL, @"Cannot encode string to UTF-8");
|
||||
bzero(_bytes, stringLength);
|
||||
}
|
||||
if (nullTerminated) {
|
||||
_bytes[stringLength] = '\0';
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)copy
|
||||
{
|
||||
return [[ZeroingData alloc] initWithBytes:_bytes length:_length];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
bzero(_bytes, _length);
|
||||
free(_bytes);
|
||||
}
|
||||
|
||||
- (const uint8_t *)bytes
|
||||
{
|
||||
return _bytes;
|
||||
}
|
||||
|
||||
- (uint8_t *)mutableBytes
|
||||
{
|
||||
return _bytes;
|
||||
}
|
||||
|
||||
- (void)appendData:(ZeroingData *)other
|
||||
{
|
||||
NSParameterAssert(other);
|
||||
|
||||
const NSInteger newLength = _length + other.length;
|
||||
uint8_t *newBytes = pp_alloc_crypto(newLength);
|
||||
memcpy(newBytes, _bytes, _length);
|
||||
memcpy(newBytes + _length, other.bytes, other.length);
|
||||
|
||||
bzero(_bytes, _length);
|
||||
free(_bytes);
|
||||
|
||||
_bytes = newBytes;
|
||||
_length = newLength;
|
||||
}
|
||||
|
||||
- (void)truncateToSize:(NSInteger)size
|
||||
{
|
||||
NSParameterAssert(size <= _length);
|
||||
|
||||
uint8_t *newBytes = pp_alloc_crypto(size);
|
||||
memcpy(newBytes, _bytes, size);
|
||||
|
||||
bzero(_bytes, _length);
|
||||
free(_bytes);
|
||||
|
||||
_bytes = newBytes;
|
||||
_length = size;
|
||||
}
|
||||
|
||||
- (void)removeUntilOffset:(NSInteger)until
|
||||
{
|
||||
NSParameterAssert(until <= _length);
|
||||
|
||||
const NSInteger newLength = _length - until;
|
||||
uint8_t *newBytes = pp_alloc_crypto(newLength);
|
||||
memcpy(newBytes, _bytes + until, newLength);
|
||||
|
||||
bzero(_bytes, _length);
|
||||
free(_bytes);
|
||||
|
||||
_bytes = newBytes;
|
||||
_length = newLength;
|
||||
}
|
||||
|
||||
- (void)zero
|
||||
{
|
||||
bzero(_bytes, _length);
|
||||
}
|
||||
|
||||
- (ZeroingData *)appendingData:(ZeroingData *)other
|
||||
{
|
||||
NSParameterAssert(other);
|
||||
|
||||
const NSInteger newLength = _length + other.length;
|
||||
uint8_t *newBytes = pp_alloc_crypto(newLength);
|
||||
memcpy(newBytes, _bytes, _length);
|
||||
memcpy(newBytes + _length, other.bytes, other.length);
|
||||
|
||||
return [[ZeroingData alloc] initWithBytesNoCopy:newBytes length:newLength];
|
||||
}
|
||||
|
||||
- (ZeroingData *)withOffset:(NSInteger)offset length:(NSInteger)length
|
||||
{
|
||||
NSParameterAssert(offset + length <= _length);
|
||||
|
||||
uint8_t *newBytes = pp_alloc_crypto(length);
|
||||
memcpy(newBytes, _bytes + offset, length);
|
||||
|
||||
return [[ZeroingData alloc] initWithBytesNoCopy:newBytes length:length];
|
||||
}
|
||||
|
||||
- (uint16_t)UInt16ValueFromOffset:(NSInteger)from
|
||||
{
|
||||
NSParameterAssert(from + 2 <= _length);
|
||||
|
||||
uint16_t value = 0;
|
||||
value |= _bytes[from];
|
||||
value |= _bytes[from + 1] << 8;
|
||||
return value;
|
||||
}
|
||||
|
||||
- (uint16_t)networkUInt16ValueFromOffset:(NSInteger)from
|
||||
{
|
||||
NSParameterAssert(from + 2 <= _length);
|
||||
|
||||
uint16_t value = 0;
|
||||
value |= _bytes[from];
|
||||
value |= _bytes[from + 1] << 8;
|
||||
return CFSwapInt16BigToHost(value);
|
||||
}
|
||||
|
||||
- (NSString *)nullTerminatedStringFromOffset:(NSInteger)from
|
||||
{
|
||||
NSParameterAssert(from <= _length);
|
||||
|
||||
NSInteger nullOffset = NSNotFound;
|
||||
for (NSInteger i = from; i < _length; ++i) {
|
||||
if (_bytes[i] == 0) {
|
||||
nullOffset = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (nullOffset == NSNotFound) {
|
||||
return nil;
|
||||
}
|
||||
const NSInteger stringLength = nullOffset - from;
|
||||
return [[NSString alloc] initWithBytes:_bytes length:stringLength encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object
|
||||
{
|
||||
NSParameterAssert(object);
|
||||
|
||||
if (![object isKindOfClass:[ZeroingData class]]) {
|
||||
return NO;
|
||||
}
|
||||
ZeroingData *other = (ZeroingData *)object;
|
||||
if (other.length != _length) {
|
||||
return NO;
|
||||
}
|
||||
return !memcmp(_bytes, other.bytes, _length);
|
||||
}
|
||||
|
||||
- (BOOL)isEqualToData:(NSData *)data
|
||||
{
|
||||
NSParameterAssert(data);
|
||||
|
||||
if (data.length != _length) {
|
||||
return NO;
|
||||
}
|
||||
return !memcmp(_bytes, data.bytes, _length);
|
||||
}
|
||||
|
||||
- (NSData *)toData
|
||||
{
|
||||
return [NSData dataWithBytes:_bytes length:_length];
|
||||
}
|
||||
|
||||
- (NSString *)toHex
|
||||
{
|
||||
const NSUInteger capacity = _length * 2;
|
||||
NSMutableString *hexString = [[NSMutableString alloc] initWithCapacity:capacity];
|
||||
for (int i = 0; i < _length; ++i) {
|
||||
[hexString appendFormat:@"%02x", _bytes[i]];
|
||||
}
|
||||
return hexString;
|
||||
}
|
||||
|
||||
@end
|
@ -1,8 +1,8 @@
|
||||
//
|
||||
// CryptoMacros.h
|
||||
// Allocation.h
|
||||
// PassepartoutKit
|
||||
//
|
||||
// Created by Davide De Rosa on 7/6/18.
|
||||
// Created by Davide De Rosa on 3/3/17.
|
||||
// Copyright (c) 2024 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
@ -36,13 +36,24 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#define CRYPTO_OPENSSL_SUCCESS(ret) (ret > 0)
|
||||
#define CRYPTO_OPENSSL_TRACK_STATUS(ret) if (ret > 0) ret =
|
||||
#define CRYPTO_OPENSSL_RETURN_STATUS(ret, raised)\
|
||||
if (ret <= 0) {\
|
||||
if (error) {\
|
||||
*error = raised;\
|
||||
}\
|
||||
return NO;\
|
||||
}\
|
||||
return YES;
|
||||
static inline void *_Nullable pp_alloc_crypto(size_t size) {
|
||||
void *memory = malloc(size);
|
||||
if (!memory) {
|
||||
NSCAssert(NO, @"pp_alloc_crypto: malloc() call failed");
|
||||
abort();
|
||||
return NULL;
|
||||
}
|
||||
return memory;
|
||||
}
|
||||
|
||||
#define MAX_BLOCK_SIZE 16 // AES only, block is 128-bit
|
||||
|
||||
/// - Parameters:
|
||||
/// - size: The base number of bytes.
|
||||
/// - overhead: The extra number of bytes.
|
||||
/// - Returns: The number of bytes to store a crypto buffer safely.
|
||||
static inline size_t pp_alloc_crypto_capacity(size_t size, size_t overhead) {
|
||||
|
||||
// encryption, byte-alignment, overhead (e.g. IV, digest)
|
||||
return 2 * size + MAX_BLOCK_SIZE + overhead;
|
||||
}
|
@ -36,17 +36,18 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class ZeroingData;
|
||||
extern NSString *_Nonnull const PassepartoutCryptoErrorDomain;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
extern NSString *const PassepartoutCryptoErrorDomain;
|
||||
|
||||
/// - Parameters:
|
||||
/// - size: The base number of bytes.
|
||||
/// - overhead: The extra number of bytes.
|
||||
/// - Returns: The number of bytes to store a crypto buffer safely.
|
||||
size_t pp_alloc_crypto_capacity(size_t size, size_t overhead);
|
||||
#define CRYPTO_OPENSSL_SUCCESS(ret) (ret > 0)
|
||||
#define CRYPTO_OPENSSL_TRACK_STATUS(ret) if (ret > 0) ret =
|
||||
#define CRYPTO_OPENSSL_RETURN_STATUS(ret, raised)\
|
||||
if (ret <= 0) {\
|
||||
if (error) {\
|
||||
*error = raised;\
|
||||
}\
|
||||
return NO;\
|
||||
}\
|
||||
return YES;
|
||||
|
||||
/// Custom flags for encryption routines.
|
||||
typedef struct {
|
||||
@ -66,64 +67,3 @@ typedef struct {
|
||||
/// Enable testable (predictable) behavior.
|
||||
BOOL forTesting;
|
||||
} CryptoFlags;
|
||||
|
||||
@protocol Crypto
|
||||
|
||||
/// The digest length or 0.
|
||||
- (int)digestLength;
|
||||
|
||||
/// The tag length or 0.
|
||||
- (int)tagLength;
|
||||
|
||||
/// The preferred encryption capacity.
|
||||
/// - Parameter length: The number of bytes to encrypt.
|
||||
- (NSInteger)encryptionCapacityWithLength:(NSInteger)length;
|
||||
|
||||
@end
|
||||
|
||||
@protocol Encrypter <Crypto>
|
||||
|
||||
/// Configures the object.
|
||||
/// - Parameters:
|
||||
/// - cipherKey: The cipher key data.
|
||||
/// - hmacKey: The HMAC key data.
|
||||
- (void)configureEncryptionWithCipherKey:(nullable ZeroingData *)cipherKey hmacKey:(nullable ZeroingData *)hmacKey;
|
||||
|
||||
/// Encrypts a buffer.
|
||||
/// - Parameters:
|
||||
/// - bytes: Bytes to encrypt.
|
||||
/// - length: The number of bytes.
|
||||
/// - dest: The destination buffer.
|
||||
/// - destLength: The number of bytes written to ``dest``.
|
||||
/// - flags: The optional encryption flags.
|
||||
- (BOOL)encryptBytes:(const uint8_t *)bytes length:(NSInteger)length dest:(uint8_t *)dest destLength:(NSInteger *)destLength flags:(const CryptoFlags *_Nullable)flags error:(NSError **)error;
|
||||
|
||||
@end
|
||||
|
||||
@protocol Decrypter <Crypto>
|
||||
|
||||
/// Configures the object.
|
||||
/// - Parameters:
|
||||
/// - cipherKey: The cipher key data.
|
||||
/// - hmacKey: The HMAC key data.
|
||||
- (void)configureDecryptionWithCipherKey:(nullable ZeroingData *)cipherKey hmacKey:(nullable ZeroingData *)hmacKey;
|
||||
|
||||
/// Decrypts a buffer.
|
||||
/// - Parameters:
|
||||
/// - bytes: Bytes to decrypt.
|
||||
/// - length: The number of bytes.
|
||||
/// - dest: The destination buffer.
|
||||
/// - destLength: The number of bytes written to ``dest``.
|
||||
/// - flags: The optional encryption flags.
|
||||
- (BOOL)decryptBytes:(const uint8_t *)bytes length:(NSInteger)length dest:(uint8_t *)dest destLength:(NSInteger *)destLength flags:(const CryptoFlags *_Nullable)flags error:(NSError **)error;
|
||||
|
||||
/// Verifies an encrypted buffer.
|
||||
/// - Parameters:
|
||||
/// - bytes: Bytes to decrypt.
|
||||
/// - length: The number of bytes.
|
||||
/// - flags: The optional encryption flags.
|
||||
- (BOOL)verifyBytes:(const uint8_t *)bytes length:(NSInteger)length flags:(const CryptoFlags *_Nullable)flags error:(NSError **)error;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
@ -36,6 +36,7 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Crypto.h"
|
||||
#import "CryptoProtocols.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
@ -36,6 +36,7 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Crypto.h"
|
||||
#import "CryptoProtocols.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Crypto.h"
|
||||
#import "CryptoProtocols.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
@ -0,0 +1,91 @@
|
||||
//
|
||||
// CryptoProtocols.swift
|
||||
// PassepartoutKit
|
||||
//
|
||||
// Created by Davide De Rosa on 1/14/25.
|
||||
// Copyright (c) 2024 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of PassepartoutKit.
|
||||
//
|
||||
// PassepartoutKit 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.
|
||||
//
|
||||
// PassepartoutKit 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 PassepartoutKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class ZeroingData;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol Crypto
|
||||
|
||||
/// The digest length or 0.
|
||||
- (int)digestLength;
|
||||
|
||||
/// The tag length or 0.
|
||||
- (int)tagLength;
|
||||
|
||||
/// The preferred encryption capacity.
|
||||
/// - Parameter length: The number of bytes to encrypt.
|
||||
- (NSInteger)encryptionCapacityWithLength:(NSInteger)length;
|
||||
|
||||
@end
|
||||
|
||||
@protocol Encrypter <Crypto>
|
||||
|
||||
/// Configures the object.
|
||||
/// - Parameters:
|
||||
/// - cipherKey: The cipher key data.
|
||||
/// - hmacKey: The HMAC key data.
|
||||
- (void)configureEncryptionWithCipherKey:(nullable ZeroingData *)cipherKey hmacKey:(nullable ZeroingData *)hmacKey;
|
||||
|
||||
/// Encrypts a buffer.
|
||||
/// - Parameters:
|
||||
/// - bytes: Bytes to encrypt.
|
||||
/// - length: The number of bytes.
|
||||
/// - dest: The destination buffer.
|
||||
/// - destLength: The number of bytes written to ``dest``.
|
||||
/// - flags: The optional encryption flags.
|
||||
- (BOOL)encryptBytes:(const uint8_t *)bytes length:(NSInteger)length dest:(uint8_t *)dest destLength:(NSInteger *)destLength flags:(const CryptoFlags *_Nullable)flags error:(NSError **)error;
|
||||
|
||||
@end
|
||||
|
||||
@protocol Decrypter <Crypto>
|
||||
|
||||
/// Configures the object.
|
||||
/// - Parameters:
|
||||
/// - cipherKey: The cipher key data.
|
||||
/// - hmacKey: The HMAC key data.
|
||||
- (void)configureDecryptionWithCipherKey:(nullable ZeroingData *)cipherKey hmacKey:(nullable ZeroingData *)hmacKey;
|
||||
|
||||
/// Decrypts a buffer.
|
||||
/// - Parameters:
|
||||
/// - bytes: Bytes to decrypt.
|
||||
/// - length: The number of bytes.
|
||||
/// - dest: The destination buffer.
|
||||
/// - destLength: The number of bytes written to ``dest``.
|
||||
/// - flags: The optional encryption flags.
|
||||
- (BOOL)decryptBytes:(const uint8_t *)bytes length:(NSInteger)length dest:(uint8_t *)dest destLength:(NSInteger *)destLength flags:(const CryptoFlags *_Nullable)flags error:(NSError **)error;
|
||||
|
||||
/// Verifies an encrypted buffer.
|
||||
/// - Parameters:
|
||||
/// - bytes: Bytes to decrypt.
|
||||
/// - length: The number of bytes.
|
||||
/// - flags: The optional encryption flags.
|
||||
- (BOOL)verifyBytes:(const uint8_t *)bytes length:(NSInteger)length flags:(const CryptoFlags *_Nullable)flags error:(NSError **)error;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
@ -0,0 +1,76 @@
|
||||
//
|
||||
// ZeroingData.h
|
||||
// PassepartoutKit
|
||||
//
|
||||
// Created by Davide De Rosa on 4/28/17.
|
||||
// Copyright (c) 2024 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of PassepartoutKit.
|
||||
//
|
||||
// PassepartoutKit 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.
|
||||
//
|
||||
// PassepartoutKit 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 PassepartoutKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// This file incorporates work covered by the following copyright and
|
||||
// permission notice:
|
||||
//
|
||||
// Copyright (c) 2018-Present Private Internet Access
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// A wrapper to handle data buffers safely. Any formerly allocated bytes are erased before release.
|
||||
@interface ZeroingData : NSObject
|
||||
|
||||
@property (nonatomic, readonly) const uint8_t *bytes;
|
||||
@property (nonatomic, readonly) uint8_t *mutableBytes;
|
||||
@property (nonatomic, readonly) NSInteger length;
|
||||
|
||||
- (instancetype)initWithLength:(NSInteger)length;
|
||||
- (instancetype)initWithBytes:(nullable const uint8_t *)bytes length:(NSInteger)length;
|
||||
- (instancetype)initWithUInt8:(uint8_t)uint8;
|
||||
- (instancetype)initWithUInt16:(uint16_t)uint16;
|
||||
|
||||
- (instancetype)initWithData:(NSData *)data;
|
||||
- (instancetype)initWithData:(NSData *)data offset:(NSInteger)offset length:(NSInteger)length;
|
||||
- (instancetype)initWithString:(NSString *)string nullTerminated:(BOOL)nullTerminated;
|
||||
|
||||
- (instancetype)copy;
|
||||
|
||||
- (void)appendData:(ZeroingData *)other;
|
||||
- (void)truncateToSize:(NSInteger)size;
|
||||
- (void)removeUntilOffset:(NSInteger)until;
|
||||
- (void)zero;
|
||||
|
||||
- (ZeroingData *)appendingData:(ZeroingData *)other;
|
||||
- (ZeroingData *)withOffset:(NSInteger)offset length:(NSInteger)length;
|
||||
- (uint16_t)UInt16ValueFromOffset:(NSInteger)from;
|
||||
- (uint16_t)networkUInt16ValueFromOffset:(NSInteger)from;
|
||||
- (nullable NSString *)nullTerminatedStringFromOffset:(NSInteger)from;
|
||||
|
||||
- (BOOL)isEqualToData:(NSData *)data;
|
||||
- (NSData *)toData; // XXX: unsafe
|
||||
- (NSString *)toHex;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
@ -37,7 +37,7 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "CryptoCBC+OpenVPN.h"
|
||||
#import "CryptoMacros.h"
|
||||
#import "Crypto.h"
|
||||
#import "Errors.h"
|
||||
#import "PacketMacros.h"
|
||||
|
||||
|
@ -37,6 +37,7 @@
|
||||
#import <PassepartoutKit/PassepartoutKit.h>
|
||||
#import <arpa/inet.h>
|
||||
|
||||
#import "Allocation.h"
|
||||
#import "DataPath.h"
|
||||
#import "DataPathCrypto.h"
|
||||
#import "Errors.h"
|
||||
@ -107,11 +108,11 @@
|
||||
self.outPackets = [[NSMutableArray alloc] initWithCapacity:maxPackets];
|
||||
self.outPacketId = 0;
|
||||
self.encBufferCapacity = 65000;
|
||||
self.encBuffer = pp_alloc(self.encBufferCapacity);
|
||||
|
||||
self.encBuffer = pp_alloc_crypto(self.encBufferCapacity);
|
||||
|
||||
self.inPackets = [[NSMutableArray alloc] initWithCapacity:maxPackets];
|
||||
self.decBufferCapacity = 65000;
|
||||
self.decBuffer = pp_alloc(self.decBufferCapacity);
|
||||
self.decBuffer = pp_alloc_crypto(self.decBufferCapacity);
|
||||
if (usesReplayProtection) {
|
||||
self.inReplay = [[ReplayProtector alloc] init];
|
||||
}
|
||||
@ -144,7 +145,7 @@
|
||||
bzero(self.encBuffer, self.encBufferCapacity);
|
||||
free(self.encBuffer);
|
||||
self.encBufferCapacity = neededCapacity;
|
||||
self.encBuffer = pp_alloc(self.encBufferCapacity);
|
||||
self.encBuffer = pp_alloc_crypto(self.encBufferCapacity);
|
||||
}
|
||||
|
||||
- (void)adjustDecBufferToPacketSize:(int)size
|
||||
@ -156,7 +157,7 @@
|
||||
bzero(self.decBuffer, self.decBufferCapacity);
|
||||
free(self.decBuffer);
|
||||
self.decBufferCapacity = neededCapacity;
|
||||
self.decBuffer = pp_alloc(self.decBufferCapacity);
|
||||
self.decBuffer = pp_alloc_crypto(self.decBufferCapacity);
|
||||
}
|
||||
|
||||
- (uint8_t *)encBufferAligned
|
||||
|
@ -65,7 +65,7 @@ static const NSInteger CryptoCTRPayloadLength = PacketOpcodeLength + PacketSessi
|
||||
|
||||
#pragma mark Initialization
|
||||
|
||||
- (instancetype)initWithSeed:(const uint8_t *)seed length:(NSInteger)length
|
||||
- (instancetype)initWithSeed:(ZeroingData *)seed
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
unsigned char x[1];
|
||||
@ -73,7 +73,7 @@ static const NSInteger CryptoCTRPayloadLength = PacketOpcodeLength + PacketSessi
|
||||
if (RAND_bytes(x, 1) != 1) {
|
||||
return nil;
|
||||
}
|
||||
RAND_seed(seed, (int)length);
|
||||
RAND_seed(seed.bytes, (int)seed.length);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
@ -39,6 +39,7 @@
|
||||
#import <openssl/x509v3.h>
|
||||
#import <openssl/err.h>
|
||||
|
||||
#import "Allocation.h"
|
||||
#import "Errors.h"
|
||||
#import "OSSLTLSBox.h"
|
||||
|
||||
@ -128,7 +129,7 @@ static BIO *create_BIO_from_PEM(NSString *pem) {
|
||||
NSAssert(self.options == nil, @"Already configured");
|
||||
self.options = options;
|
||||
self.onFailure = onFailure;
|
||||
self.bufferCipherText = pp_alloc(self.options.bufferLength);
|
||||
self.bufferCipherText = pp_alloc_crypto(self.options.bufferLength);
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <PassepartoutKit/PassepartoutKit.h>
|
||||
|
||||
#import "OpenVPNCryptoProtocol.h"
|
||||
|
||||
|
@ -34,8 +34,7 @@
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#import <PassepartoutKit/PassepartoutKit.h>
|
||||
|
||||
#import "Allocation.h"
|
||||
#import "ReplayProtector.h"
|
||||
|
||||
@import CPassepartoutCryptoOpenSSL;
|
||||
@ -61,7 +60,7 @@
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
self.highestPacketId = 0;
|
||||
self.bitmap = pp_alloc(BITMAP_LEN * sizeof(uint32_t));
|
||||
self.bitmap = pp_alloc_crypto(BITMAP_LEN * sizeof(uint32_t));
|
||||
bzero(self.bitmap, BITMAP_LEN * sizeof(uint32_t));
|
||||
}
|
||||
return self;
|
||||
|
@ -38,12 +38,14 @@
|
||||
|
||||
#import "OpenVPNCryptoProtocol.h"
|
||||
|
||||
@class ZeroingData;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
// WARNING: not thread-safe!
|
||||
@interface OSSLCryptoBox : NSObject <OpenVPNCryptoProtocol>
|
||||
|
||||
- (nullable instancetype)initWithSeed:(const uint8_t *)seed length:(NSInteger)length;
|
||||
- (nullable instancetype)initWithSeed:(ZeroingData *)seed;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -24,8 +24,8 @@
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <PassepartoutKit/PassepartoutKit.h>
|
||||
|
||||
#import "Crypto.h"
|
||||
#import "CryptoProvider.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
@ -23,10 +23,10 @@
|
||||
// along with PassepartoutKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
#import <PassepartoutKit/PassepartoutKit.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "XORMethodNative.h"
|
||||
#import "ZeroingData.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
@ -30,9 +30,9 @@
|
||||
|
||||
static inline void xor_mask(uint8_t *dst, const uint8_t *src, ZeroingData *xorMask, size_t length)
|
||||
{
|
||||
if (xorMask.count > 0) {
|
||||
if (xorMask.length > 0) {
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
dst[i] = src[i] ^ ((uint8_t *)(xorMask.bytes))[i % xorMask.count];
|
||||
dst[i] = src[i] ^ ((uint8_t *)(xorMask.bytes))[i % xorMask.length];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -36,7 +36,6 @@
|
||||
|
||||
internal import CPassepartoutCryptoOpenSSL
|
||||
import Foundation
|
||||
import PassepartoutKit
|
||||
|
||||
extension Encrypter {
|
||||
|
||||
@ -75,3 +74,12 @@ extension Decrypter {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension UnsafeRawBufferPointer {
|
||||
var bytePointer: UnsafePointer<Element> {
|
||||
guard let address = bindMemory(to: Element.self).baseAddress else {
|
||||
fatalError("Cannot bind to self")
|
||||
}
|
||||
return address
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ import PassepartoutKit
|
||||
|
||||
fileprivate extension ZeroingData {
|
||||
func appendSized(_ buf: ZeroingData) {
|
||||
append(Z(UInt16(buf.count).bigEndian))
|
||||
append(Z(UInt16(buf.length).bigEndian))
|
||||
append(buf)
|
||||
}
|
||||
}
|
||||
@ -67,9 +67,9 @@ final class Authenticator {
|
||||
var sslVersion: String?
|
||||
|
||||
init(prng: PRNGProtocol, _ username: String?, _ password: String?) {
|
||||
preMaster = prng.safeData(length: Constants.preMasterLength).zData
|
||||
random1 = prng.safeData(length: Constants.randomLength).zData
|
||||
random2 = prng.safeData(length: Constants.randomLength).zData
|
||||
preMaster = prng.safeData(length: Constants.preMasterLength)
|
||||
random1 = prng.safeData(length: Constants.randomLength)
|
||||
random2 = prng.safeData(length: Constants.randomLength)
|
||||
|
||||
// XXX: not 100% secure, can't erase input username/password
|
||||
if let username = username, let password = password {
|
||||
@ -162,7 +162,7 @@ final class Authenticator {
|
||||
|
||||
pp_log(.openvpn, .info, "TLS.auth: Put plaintext \(raw.asSensitiveBytes)")
|
||||
|
||||
try into.putRawPlainText(raw.bytes, length: raw.count)
|
||||
try into.putRawPlainText(raw.bytes, length: raw.length)
|
||||
}
|
||||
|
||||
// MARK: Server replies
|
||||
@ -175,30 +175,30 @@ final class Authenticator {
|
||||
let prefixLength = ProtocolMacros.tlsPrefix.count
|
||||
|
||||
// TLS prefix + random (x2) + opts length [+ opts]
|
||||
guard controlBuffer.count >= prefixLength + 2 * Constants.randomLength + 2 else {
|
||||
guard controlBuffer.length >= prefixLength + 2 * Constants.randomLength + 2 else {
|
||||
return false
|
||||
}
|
||||
|
||||
let prefix = controlBuffer.withOffset(0, count: prefixLength)
|
||||
let prefix = controlBuffer.withOffset(0, length: prefixLength)
|
||||
guard prefix.isEqual(to: ProtocolMacros.tlsPrefix) else {
|
||||
throw OpenVPNSessionError.wrongControlDataPrefix
|
||||
}
|
||||
|
||||
var offset = ProtocolMacros.tlsPrefix.count
|
||||
|
||||
let serverRandom1 = controlBuffer.withOffset(offset, count: Constants.randomLength)
|
||||
let serverRandom1 = controlBuffer.withOffset(offset, length: Constants.randomLength)
|
||||
offset += Constants.randomLength
|
||||
|
||||
let serverRandom2 = controlBuffer.withOffset(offset, count: Constants.randomLength)
|
||||
let serverRandom2 = controlBuffer.withOffset(offset, length: Constants.randomLength)
|
||||
offset += Constants.randomLength
|
||||
|
||||
let serverOptsLength = Int(controlBuffer.networkUInt16Value(fromOffset: offset))
|
||||
offset += 2
|
||||
|
||||
guard controlBuffer.count >= offset + serverOptsLength else {
|
||||
guard controlBuffer.length >= offset + serverOptsLength else {
|
||||
return false
|
||||
}
|
||||
let serverOpts = controlBuffer.withOffset(offset, count: serverOptsLength)
|
||||
let serverOpts = controlBuffer.withOffset(offset, length: serverOptsLength)
|
||||
offset += serverOptsLength
|
||||
|
||||
pp_log(.openvpn, .info, "TLS.auth: Parsed server random [\(serverRandom1.asSensitiveBytes), \(serverRandom2.asSensitiveBytes)]")
|
||||
|
@ -81,7 +81,7 @@ actor ControlChannel {
|
||||
queue = BidirectionalState(withResetValue: [])
|
||||
currentPacketId = BidirectionalState(withResetValue: 0)
|
||||
pendingAcks = []
|
||||
plainBuffer = Z(count: OpenVPNTLSOptionsDefaultBufferLength)
|
||||
plainBuffer = Z(length: OpenVPNTLSOptionsDefaultBufferLength)
|
||||
sentDates = [:]
|
||||
}
|
||||
}
|
||||
@ -245,6 +245,6 @@ extension ControlChannel {
|
||||
func currentControlData(withTLS tls: OpenVPNTLSProtocol) throws -> ZeroingData {
|
||||
var length = 0
|
||||
try tls.pullRawPlainText(plainBuffer.mutableBytes, length: &length)
|
||||
return plainBuffer.withOffset(0, count: length)
|
||||
return plainBuffer.withOffset(0, length: length)
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@
|
||||
// along with PassepartoutKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
internal import CPassepartoutCryptoOpenSSL
|
||||
internal import CPassepartoutOpenVPNOpenSSL
|
||||
import Foundation
|
||||
import PassepartoutKit
|
||||
|
@ -129,7 +129,7 @@ private extension OpenVPNCryptoProtocol {
|
||||
var keysArray = [ZeroingData]()
|
||||
for i in 0..<Constants.keysCount {
|
||||
let offset = i * Constants.keyLength
|
||||
let zbuf = keysData.withOffset(offset, count: Constants.keyLength)
|
||||
let zbuf = keysData.withOffset(offset, length: Constants.keyLength)
|
||||
keysArray.append(zbuf)
|
||||
}
|
||||
|
||||
@ -156,16 +156,16 @@ private extension OpenVPNCryptoProtocol {
|
||||
if let ssi = parameters.serverSessionId {
|
||||
seed.append(Z(ssi))
|
||||
}
|
||||
let len = parameters.secret.count / 2
|
||||
let lenx = len + (parameters.secret.count & 1)
|
||||
let secret1 = parameters.secret.withOffset(0, count: lenx)
|
||||
let secret2 = parameters.secret.withOffset(len, count: lenx)
|
||||
let len = parameters.secret.length / 2
|
||||
let lenx = len + (parameters.secret.length & 1)
|
||||
let secret1 = parameters.secret.withOffset(0, length: lenx)
|
||||
let secret2 = parameters.secret.withOffset(len, length: lenx)
|
||||
|
||||
let hash1 = try keysHash("md5", secret1, seed, parameters.size)
|
||||
let hash2 = try keysHash("sha1", secret2, seed, parameters.size)
|
||||
|
||||
let prf = Z()
|
||||
for i in 0..<hash1.count {
|
||||
for i in 0..<hash1.length {
|
||||
let h1 = hash1.bytes[i]
|
||||
let h2 = hash2.bytes[i]
|
||||
|
||||
@ -176,13 +176,13 @@ private extension OpenVPNCryptoProtocol {
|
||||
|
||||
func keysHash(_ digestName: String, _ secret: ZeroingData, _ seed: ZeroingData, _ size: Int) throws -> ZeroingData {
|
||||
let out = Z()
|
||||
let buffer = Z(count: maxHmacLength)
|
||||
let buffer = Z(length: maxHmacLength)
|
||||
var chain = try hmac(buffer, digestName, secret, seed)
|
||||
while out.count < size {
|
||||
while out.length < size {
|
||||
out.append(try hmac(buffer, digestName, secret, chain.appending(seed)))
|
||||
chain = try hmac(buffer, digestName, secret, chain)
|
||||
}
|
||||
return out.withOffset(0, count: size)
|
||||
return out.withOffset(0, length: size)
|
||||
}
|
||||
|
||||
func hmac(_ buffer: ZeroingData, _ digestName: String, _ secret: ZeroingData, _ data: ZeroingData) throws -> ZeroingData {
|
||||
@ -191,13 +191,13 @@ private extension OpenVPNCryptoProtocol {
|
||||
try hmac(
|
||||
withDigestName: digestName,
|
||||
secret: secret.bytes,
|
||||
secretLength: secret.count,
|
||||
secretLength: secret.length,
|
||||
data: data.bytes,
|
||||
dataLength: data.count,
|
||||
dataLength: data.length,
|
||||
hmac: buffer.mutableBytes,
|
||||
hmacLength: &length
|
||||
)
|
||||
|
||||
return buffer.withOffset(0, count: length)
|
||||
return buffer.withOffset(0, length: length)
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
//
|
||||
|
||||
import Combine
|
||||
internal import CPassepartoutCryptoOpenSSL
|
||||
internal import CPassepartoutOpenVPNOpenSSL
|
||||
import Foundation
|
||||
import PassepartoutKit
|
||||
|
@ -59,7 +59,7 @@ struct XORProcessor {
|
||||
- Returns: The packet after XOR processing.
|
||||
**/
|
||||
func processPacket(_ packet: Data, outbound: Bool) -> Data {
|
||||
guard let method = method else {
|
||||
guard let method else {
|
||||
return packet
|
||||
}
|
||||
switch method {
|
||||
@ -85,7 +85,7 @@ struct XORProcessor {
|
||||
extension XORProcessor {
|
||||
private static func xormask(packet: Data, mask: ZeroingData) -> Data {
|
||||
Data(packet.enumerated().map { (index, byte) in
|
||||
byte ^ mask.bytes[index % mask.count]
|
||||
byte ^ mask.bytes[index % mask.length]
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,57 @@
|
||||
//
|
||||
// ZeroingData+Extensions.swift
|
||||
// PassepartoutKit
|
||||
//
|
||||
// Created by Davide De Rosa on 1/14/25.
|
||||
// Copyright (c) 2024 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of PassepartoutKit.
|
||||
//
|
||||
// PassepartoutKit 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.
|
||||
//
|
||||
// PassepartoutKit 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 PassepartoutKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
internal import CPassepartoutCryptoOpenSSL
|
||||
import Foundation
|
||||
import PassepartoutKit
|
||||
|
||||
extension PRNGProtocol {
|
||||
func safeData(length: Int) -> ZeroingData {
|
||||
precondition(length > 0)
|
||||
let randomBytes = UnsafeMutablePointer<UInt8>.allocate(capacity: length)
|
||||
defer {
|
||||
bzero(randomBytes, length)
|
||||
randomBytes.deallocate()
|
||||
}
|
||||
|
||||
guard SecRandomCopyBytes(kSecRandomDefault, length, randomBytes) == errSecSuccess else {
|
||||
fatalError("SecRandomCopyBytes failed")
|
||||
}
|
||||
|
||||
return Z(Data(bytes: randomBytes, count: length))
|
||||
}
|
||||
}
|
||||
|
||||
extension SecureData {
|
||||
var zData: ZeroingData {
|
||||
Z(innerData.toData())
|
||||
}
|
||||
}
|
||||
|
||||
extension ZeroingData: @retroactive SensitiveDebugStringConvertible {
|
||||
func debugDescription(withSensitiveData: Bool) -> String {
|
||||
withSensitiveData ? "[\(length) bytes, \(toHex())]" : "[\(length) bytes]"
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
//
|
||||
// ZeroingData.swift
|
||||
// PassepartoutKit
|
||||
//
|
||||
// Created by Davide De Rosa on 1/8/25.
|
||||
// Copyright (c) 2024 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of PassepartoutKit.
|
||||
//
|
||||
// PassepartoutKit 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.
|
||||
//
|
||||
// PassepartoutKit 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 PassepartoutKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
internal import CPassepartoutCryptoOpenSSL
|
||||
import Foundation
|
||||
|
||||
func Z() -> ZeroingData {
|
||||
ZeroingData()
|
||||
}
|
||||
|
||||
func Z(length: Int) -> ZeroingData {
|
||||
ZeroingData(length: length)
|
||||
}
|
||||
|
||||
func Z(bytes: UnsafePointer<UInt8>, length: Int) -> ZeroingData {
|
||||
ZeroingData(bytes: bytes, length: length)
|
||||
}
|
||||
|
||||
func Z(_ uint8: UInt8) -> ZeroingData {
|
||||
ZeroingData(uInt8: uint8)
|
||||
}
|
||||
|
||||
func Z(_ uint16: UInt16) -> ZeroingData {
|
||||
ZeroingData(uInt16: uint16)
|
||||
}
|
||||
|
||||
func Z(_ data: Data) -> ZeroingData {
|
||||
ZeroingData(data: data)
|
||||
}
|
||||
|
||||
func Z(_ data: Data, _ offset: Int, _ length: Int) -> ZeroingData {
|
||||
ZeroingData(data: data, offset: offset, length: length)
|
||||
}
|
||||
|
||||
func Z(_ string: String, nullTerminated: Bool) -> ZeroingData {
|
||||
ZeroingData(string: string, nullTerminated: nullTerminated)
|
||||
}
|
@ -46,7 +46,7 @@ extension OpenVPNConnection {
|
||||
}
|
||||
let cryptoFactory = { @Sendable in
|
||||
let seed = prng.safeData(length: 64)
|
||||
guard let box = OSSLCryptoBox(seed: seed.zData.bytes, length: seed.zData.count) else {
|
||||
guard let box = OSSLCryptoBox(seed: seed) else {
|
||||
fatalError("Unable to create OSSLCryptoBox")
|
||||
}
|
||||
return box
|
||||
|
@ -25,7 +25,6 @@
|
||||
|
||||
internal import CPassepartoutCryptoOpenSSL
|
||||
@testable import PassepartoutCryptoOpenSSL
|
||||
import PassepartoutKit
|
||||
import XCTest
|
||||
|
||||
final class CryptoAEADTests: XCTestCase {
|
||||
@ -54,11 +53,11 @@ final class CryptoAEADTests: XCTestCase {
|
||||
|
||||
private extension CryptoAEADTests {
|
||||
var cipherKey: ZeroingData {
|
||||
ZeroingData(count: 32)
|
||||
ZeroingData(length: 32)
|
||||
}
|
||||
|
||||
var hmacKey: ZeroingData {
|
||||
ZeroingData(count: 32)
|
||||
ZeroingData(length: 32)
|
||||
}
|
||||
|
||||
var plainData: Data {
|
@ -25,7 +25,6 @@
|
||||
|
||||
internal import CPassepartoutCryptoOpenSSL
|
||||
@testable import PassepartoutCryptoOpenSSL
|
||||
import PassepartoutKit
|
||||
import XCTest
|
||||
|
||||
final class CryptoCBCTests: XCTestCase {
|
||||
@ -93,11 +92,11 @@ final class CryptoCBCTests: XCTestCase {
|
||||
|
||||
private extension CryptoCBCTests {
|
||||
var cipherKey: ZeroingData {
|
||||
ZeroingData(count: 32)
|
||||
ZeroingData(length: 32)
|
||||
}
|
||||
|
||||
var hmacKey: ZeroingData {
|
||||
ZeroingData(count: 32)
|
||||
ZeroingData(length: 32)
|
||||
}
|
||||
|
||||
var plainData: Data {
|
@ -25,7 +25,6 @@
|
||||
|
||||
internal import CPassepartoutCryptoOpenSSL
|
||||
@testable import PassepartoutCryptoOpenSSL
|
||||
import PassepartoutKit
|
||||
import XCTest
|
||||
|
||||
final class CryptoCTRTests: XCTestCase {
|
||||
@ -57,11 +56,11 @@ final class CryptoCTRTests: XCTestCase {
|
||||
|
||||
private extension CryptoCTRTests {
|
||||
var cipherKey: ZeroingData {
|
||||
ZeroingData(count: 32)
|
||||
ZeroingData(length: 32)
|
||||
}
|
||||
|
||||
var hmacKey: ZeroingData {
|
||||
ZeroingData(count: 32)
|
||||
ZeroingData(length: 32)
|
||||
}
|
||||
|
||||
var plainData: Data {
|
@ -1,8 +1,8 @@
|
||||
//
|
||||
// CryptoMacros.m
|
||||
// Extensions.swift
|
||||
// PassepartoutKit
|
||||
//
|
||||
// Created by Davide De Rosa on 3/1/24.
|
||||
// Created by Davide De Rosa on 1/14/25.
|
||||
// Copyright (c) 2024 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
@ -23,6 +23,22 @@
|
||||
// along with PassepartoutKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
import Foundation
|
||||
|
||||
NSString *const PassepartoutCryptoErrorDomain = @"PassepartoutCrypto";
|
||||
extension Data {
|
||||
init(hex: String) {
|
||||
assert(hex.count & 1 == 0)
|
||||
var data = Data()
|
||||
var index = hex.startIndex
|
||||
while index < hex.endIndex {
|
||||
let nextIndex = hex.index(index, offsetBy: 2)
|
||||
if let byte = UInt8(hex[index..<nextIndex], radix: 16) {
|
||||
data.append(byte)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
index = nextIndex
|
||||
}
|
||||
self.init(data)
|
||||
}
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
//
|
||||
// ZeroingDataTests.swift
|
||||
// PassepartoutKit
|
||||
//
|
||||
// Created by Davide De Rosa on 4/9/24.
|
||||
// Copyright (c) 2024 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of PassepartoutKit.
|
||||
//
|
||||
// PassepartoutKit 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.
|
||||
//
|
||||
// PassepartoutKit 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 PassepartoutKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
internal import CPassepartoutCryptoOpenSSL
|
||||
import Foundation
|
||||
import PassepartoutCryptoOpenSSL
|
||||
import XCTest
|
||||
|
||||
final class ZeroingDataTests: XCTestCase {
|
||||
func test_givenInput_whenInit_thenReturnsExpected() {
|
||||
XCTAssertEqual(ZeroingData(length: 123).length, 123)
|
||||
XCTAssertEqual(ZeroingData(bytes: [0x11, 0x22, 0x33, 0x44, 0x55], length: 3).length, 3)
|
||||
XCTAssertEqual(ZeroingData(uInt8: UInt8(78)).length, 1)
|
||||
XCTAssertEqual(ZeroingData(uInt16: UInt16(4756)).length, 2)
|
||||
XCTAssertEqual(ZeroingData(data: Data(count: 12)).length, 12)
|
||||
XCTAssertEqual(ZeroingData(data: Data(count: 12), offset: 3, length: 7).length, 7)
|
||||
XCTAssertEqual(ZeroingData(string: "hello", nullTerminated: false).length, 5)
|
||||
XCTAssertEqual(ZeroingData(string: "hello", nullTerminated: true).length, 6)
|
||||
}
|
||||
|
||||
func test_givenData_whenOffset_thenReturnsExpected() {
|
||||
let sut = ZeroingData(string: "Hello", nullTerminated: true)
|
||||
XCTAssertEqual(sut.networkUInt16Value(fromOffset: 3), 0x6c6f)
|
||||
XCTAssertEqual(sut.nullTerminatedString(fromOffset: 0), "Hello")
|
||||
XCTAssertEqual(sut.withOffset(3, length: 2), ZeroingData(string: "lo", nullTerminated: false))
|
||||
}
|
||||
|
||||
func test_givenData_whenAppend_thenIsAppended() {
|
||||
let sut = ZeroingData(string: "this_data", nullTerminated: false)
|
||||
let other = ZeroingData(string: "that_data", nullTerminated: false)
|
||||
|
||||
let merged = sut.copy()
|
||||
merged.append(other)
|
||||
XCTAssertEqual(merged, ZeroingData(string: "this_datathat_data", nullTerminated: false))
|
||||
XCTAssertEqual(merged, sut.appending(other))
|
||||
}
|
||||
|
||||
func test_givenData_whenTruncate_thenIsTruncated() {
|
||||
let data = Data(hex: "438ac4729847fb3975345983")
|
||||
let sut = ZeroingData(data: data)
|
||||
|
||||
sut.truncate(toSize: 5)
|
||||
XCTAssertEqual(sut.length, 5)
|
||||
XCTAssertEqual(sut.toData(), data.subdata(in: 0..<5))
|
||||
}
|
||||
|
||||
func test_givenData_whenRemove_thenIsRemoved() {
|
||||
let data = Data(hex: "438ac4729847fb3975345983")
|
||||
let sut = ZeroingData(data: data)
|
||||
|
||||
sut.remove(untilOffset: 5)
|
||||
XCTAssertEqual(sut.length, data.count - 5)
|
||||
XCTAssertEqual(sut.toData(), data.subdata(in: 5..<data.count))
|
||||
}
|
||||
|
||||
func test_givenData_whenZero_thenIsZeroedOut() {
|
||||
let data = Data(hex: "438ac4729847fb3975345983")
|
||||
let sut = ZeroingData(data: data)
|
||||
|
||||
sut.zero()
|
||||
XCTAssertEqual(sut.length, data.count)
|
||||
XCTAssertEqual(sut.toData(), Data(repeating: 0, count: data.count))
|
||||
}
|
||||
|
||||
func test_givenData_whenCompareEqual_thenIsEqual() {
|
||||
let data = Data(hex: "438ac4729847fb3975345983")
|
||||
let sut = ZeroingData(data: data)
|
||||
let other = ZeroingData(data: data)
|
||||
|
||||
XCTAssertEqual(sut, other)
|
||||
XCTAssertEqual(sut, sut.copy())
|
||||
XCTAssertEqual(other, other.copy())
|
||||
XCTAssertEqual(sut.copy(), other.copy())
|
||||
|
||||
sut.append(ZeroingData(length: 1))
|
||||
XCTAssertNotEqual(sut, other)
|
||||
other.append(ZeroingData(length: 1))
|
||||
XCTAssertEqual(sut, other)
|
||||
}
|
||||
|
||||
func test_givenData_whenManipulate_thenDataIsExpected() {
|
||||
let z1 = ZeroingData()
|
||||
z1.append(ZeroingData(data: Data(hex: "12345678")))
|
||||
z1.append(ZeroingData(data: Data(hex: "abcdef")))
|
||||
let z2 = z1.withOffset(2, length: 3) // 5678ab
|
||||
let z3 = z2.appending(ZeroingData(data: Data(hex: "aaddcc"))) // 5678abaaddcc
|
||||
|
||||
XCTAssertEqual(z1.toData(), Data(hex: "12345678abcdef"))
|
||||
XCTAssertEqual(z2.toData(), Data(hex: "5678ab"))
|
||||
XCTAssertEqual(z3.toData(), Data(hex: "5678abaaddcc"))
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
//
|
||||
// ZeroingDataExtensionsTests.swift
|
||||
// PassepartoutKit
|
||||
//
|
||||
// Created by Davide De Rosa on 1/14/25.
|
||||
// Copyright (c) 2024 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of PassepartoutKit.
|
||||
//
|
||||
// PassepartoutKit 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.
|
||||
//
|
||||
// PassepartoutKit 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 PassepartoutKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import PassepartoutKit
|
||||
@testable import PassepartoutOpenVPNOpenSSL
|
||||
import XCTest
|
||||
|
||||
final class ZeroingDataExtensionsTests: XCTestCase {
|
||||
func test_givenPRNG_whenGenerateSafeData_thenHasGivenLength() {
|
||||
let sut = SecureRandom()
|
||||
XCTAssertEqual(sut.safeData(length: 500).length, 500)
|
||||
}
|
||||
|
||||
func test_givenZeroingData_whenAsSensitive_thenOmitsSensitiveData() throws {
|
||||
let sut = Z(Data(hex: "12345678abcdef"))
|
||||
XCTAssertEqual(sut.debugDescription(withSensitiveData: true), "[7 bytes, 12345678abcdef]")
|
||||
XCTAssertEqual(sut.debugDescription(withSensitiveData: false), "[7 bytes]")
|
||||
}
|
||||
}
|
@ -24,7 +24,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import WireGuardKit
|
||||
internal import WireGuardKit
|
||||
|
||||
extension TunnelConfiguration.ParseError: LocalizedError {
|
||||
public var errorDescription: String? {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import WireGuardKit
|
||||
internal import WireGuardKit
|
||||
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright © 2018-2021 WireGuard LLC. All Rights Reserved.
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
import Foundation
|
||||
import PassepartoutKit
|
||||
import WireGuardKit
|
||||
internal import WireGuardKit
|
||||
|
||||
extension WireGuard.Configuration {
|
||||
init(wgQuickConfig: String) throws {
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
import Foundation
|
||||
import PassepartoutKit
|
||||
import WireGuardKit
|
||||
internal import WireGuardKit
|
||||
|
||||
extension PassepartoutKit.Endpoint {
|
||||
init?(wg: WireGuardKit.Endpoint) {
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
import Foundation
|
||||
import PassepartoutKit
|
||||
import WireGuardKit
|
||||
internal import WireGuardKit
|
||||
|
||||
extension WireGuard.LocalInterface {
|
||||
init(wg: InterfaceConfiguration) throws {
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
import Foundation
|
||||
import PassepartoutKit
|
||||
import WireGuardKit
|
||||
internal import WireGuardKit
|
||||
|
||||
// MARK: - Mapping
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
import Foundation
|
||||
import Network
|
||||
import PassepartoutKit
|
||||
import WireGuardKit
|
||||
internal import WireGuardKit
|
||||
|
||||
extension WireGuard.RemoteInterface {
|
||||
init(wg: PeerConfiguration) throws {
|
||||
|
@ -26,7 +26,7 @@
|
||||
import Foundation
|
||||
import Network
|
||||
import PassepartoutKit
|
||||
import WireGuardKit
|
||||
internal import WireGuardKit
|
||||
|
||||
extension Subnet {
|
||||
init?(wg: IPAddressRange) {
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
import Foundation
|
||||
import PassepartoutKit
|
||||
import WireGuardKit
|
||||
internal import WireGuardKit
|
||||
|
||||
public final class StandardWireGuardKeyGenerator: WireGuardKeyGenerator {
|
||||
public init() {
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
import Foundation
|
||||
import PassepartoutKit
|
||||
import WireGuardKit
|
||||
internal import WireGuardKit
|
||||
|
||||
/// Parses WireGuard configurations in `wg-quick` format.
|
||||
public final class StandardWireGuardParser {
|
||||
|
@ -33,8 +33,8 @@ import Foundation
|
||||
import NetworkExtension
|
||||
import PassepartoutKit
|
||||
import os
|
||||
import WireGuardKit
|
||||
import WireGuardKitGo
|
||||
internal import WireGuardKit
|
||||
internal import WireGuardKitGo
|
||||
|
||||
public final class WireGuardConnection: Connection {
|
||||
private let statusSubject: CurrentValueSubject<ConnectionStatus, Error>
|
||||
@ -50,7 +50,7 @@ public final class WireGuardConnection: Connection {
|
||||
private var dataCountTimer: AnyCancellable?
|
||||
|
||||
private lazy var adapter: WireGuardAdapter = {
|
||||
WireGuardAdapter(with: self, backend: WireGuardBackendGo()) { logLevel, message in
|
||||
WireGuardAdapter(with: AdapterDelegate(connection: self), backend: WireGuardBackendGo()) { logLevel, message in
|
||||
pp_log(.wireguard, osLogLevel: logLevel.osLogLevel, message)
|
||||
}
|
||||
}()
|
||||
@ -156,34 +156,47 @@ public final class WireGuardConnection: Connection {
|
||||
}
|
||||
}
|
||||
|
||||
extension WireGuardConnection: WireGuardAdapterDelegate {
|
||||
public func adapterShouldReassert(_ adapter: WireGuardAdapter, reasserting: Bool) {
|
||||
if reasserting {
|
||||
statusSubject.send(.connecting)
|
||||
}
|
||||
}
|
||||
// MARK: - WireGuardAdapterDelegate
|
||||
|
||||
public func adapterShouldSetNetworkSettings(_ adapter: WireGuardAdapter, settings: NEPacketTunnelNetworkSettings, completionHandler: ((Error?) -> Void)?) {
|
||||
let module = NESettingsModule(fullSettings: settings)
|
||||
let addressObject = Address(rawValue: settings.tunnelRemoteAddress)
|
||||
if addressObject == nil {
|
||||
pp_log(.wireguard, .error, "Unable to parse remote tunnel address")
|
||||
private extension WireGuardConnection {
|
||||
final class AdapterDelegate: WireGuardAdapterDelegate {
|
||||
private weak var connection: WireGuardConnection?
|
||||
|
||||
init(connection: WireGuardConnection) {
|
||||
self.connection = connection
|
||||
}
|
||||
|
||||
Task {
|
||||
do {
|
||||
try await controller.setTunnelSettings(with: TunnelRemoteInfo(
|
||||
originalModuleId: moduleId,
|
||||
address: addressObject,
|
||||
modules: [module]
|
||||
))
|
||||
completionHandler?(nil)
|
||||
pp_log(.wireguard, .info, "Tunnel interface is now UP")
|
||||
statusSubject.send(.connected)
|
||||
} catch {
|
||||
completionHandler?(error)
|
||||
pp_log(.wireguard, .error, "Unable to configure tunnel settings: \(error)")
|
||||
statusSubject.send(.disconnected)
|
||||
func adapterShouldReassert(_ adapter: WireGuardAdapter, reasserting: Bool) {
|
||||
if reasserting {
|
||||
connection?.statusSubject.send(.connecting)
|
||||
}
|
||||
}
|
||||
|
||||
func adapterShouldSetNetworkSettings(_ adapter: WireGuardAdapter, settings: NEPacketTunnelNetworkSettings, completionHandler: ((Error?) -> Void)?) {
|
||||
guard let connection else {
|
||||
return
|
||||
}
|
||||
let module = NESettingsModule(fullSettings: settings)
|
||||
let addressObject = Address(rawValue: settings.tunnelRemoteAddress)
|
||||
if addressObject == nil {
|
||||
pp_log(.wireguard, .error, "Unable to parse remote tunnel address")
|
||||
}
|
||||
|
||||
Task {
|
||||
do {
|
||||
try await connection.controller.setTunnelSettings(with: TunnelRemoteInfo(
|
||||
originalModuleId: connection.moduleId,
|
||||
address: addressObject,
|
||||
modules: [module]
|
||||
))
|
||||
completionHandler?(nil)
|
||||
pp_log(.wireguard, .info, "Tunnel interface is now UP")
|
||||
connection.statusSubject.send(.connected)
|
||||
} catch {
|
||||
completionHandler?(error)
|
||||
pp_log(.wireguard, .error, "Unable to configure tunnel settings: \(error)")
|
||||
connection.statusSubject.send(.disconnected)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
import PassepartoutKit
|
||||
@testable import PassepartoutWireGuardGo
|
||||
import WireGuardKit
|
||||
internal import WireGuardKit
|
||||
import XCTest
|
||||
|
||||
final class ParseErrorTests: XCTestCase {
|
||||
|
@ -12,13 +12,6 @@
|
||||
"testTimeoutsEnabled" : true
|
||||
},
|
||||
"testTargets" : [
|
||||
{
|
||||
"target" : {
|
||||
"containerPath" : "container:Packages\/PassepartoutOpenVPNOpenSSL",
|
||||
"identifier" : "PassepartoutCryptoOpenSSLTests",
|
||||
"name" : "PassepartoutCryptoOpenSSLTests"
|
||||
}
|
||||
},
|
||||
{
|
||||
"target" : {
|
||||
"containerPath" : "container:Packages\/PassepartoutKit",
|
||||
@ -36,9 +29,9 @@
|
||||
},
|
||||
{
|
||||
"target" : {
|
||||
"containerPath" : "container:Packages\/PassepartoutWireGuardGo",
|
||||
"identifier" : "PassepartoutWireGuardGoTests",
|
||||
"name" : "PassepartoutWireGuardGoTests"
|
||||
"containerPath" : "container:Packages\/PassepartoutOpenVPNOpenSSL",
|
||||
"identifier" : "PassepartoutOpenVPNOpenSSLTests",
|
||||
"name" : "PassepartoutOpenVPNOpenSSLTests"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -51,36 +44,8 @@
|
||||
{
|
||||
"target" : {
|
||||
"containerPath" : "container:Packages\/PassepartoutKit",
|
||||
"identifier" : "PassepartoutAPITests",
|
||||
"name" : "PassepartoutAPITests"
|
||||
}
|
||||
},
|
||||
{
|
||||
"target" : {
|
||||
"containerPath" : "container:Packages\/App",
|
||||
"identifier" : "CommonLibraryTests",
|
||||
"name" : "CommonLibraryTests"
|
||||
}
|
||||
},
|
||||
{
|
||||
"target" : {
|
||||
"containerPath" : "container:Packages\/App",
|
||||
"identifier" : "LegacyV2Tests",
|
||||
"name" : "LegacyV2Tests"
|
||||
}
|
||||
},
|
||||
{
|
||||
"target" : {
|
||||
"containerPath" : "container:Packages\/PassepartoutKit",
|
||||
"identifier" : "PassepartoutWireGuardTests",
|
||||
"name" : "PassepartoutWireGuardTests"
|
||||
}
|
||||
},
|
||||
{
|
||||
"target" : {
|
||||
"containerPath" : "container:Packages\/PassepartoutKit",
|
||||
"identifier" : "PassepartoutCoreTests",
|
||||
"name" : "PassepartoutCoreTests"
|
||||
"identifier" : "PassepartoutNETests",
|
||||
"name" : "PassepartoutNETests"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -90,11 +55,25 @@
|
||||
"name" : "AppUIMainTests"
|
||||
}
|
||||
},
|
||||
{
|
||||
"target" : {
|
||||
"containerPath" : "container:Packages\/App",
|
||||
"identifier" : "CommonLibraryTests",
|
||||
"name" : "CommonLibraryTests"
|
||||
}
|
||||
},
|
||||
{
|
||||
"target" : {
|
||||
"containerPath" : "container:Packages\/PassepartoutKit",
|
||||
"identifier" : "PassepartoutNETests",
|
||||
"name" : "PassepartoutNETests"
|
||||
"identifier" : "PassepartoutCoreTests",
|
||||
"name" : "PassepartoutCoreTests"
|
||||
}
|
||||
},
|
||||
{
|
||||
"target" : {
|
||||
"containerPath" : "container:Packages\/PassepartoutKit",
|
||||
"identifier" : "PassepartoutAPITests",
|
||||
"name" : "PassepartoutAPITests"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -104,11 +83,32 @@
|
||||
"name" : "UILibraryTests"
|
||||
}
|
||||
},
|
||||
{
|
||||
"target" : {
|
||||
"containerPath" : "container:Packages\/App",
|
||||
"identifier" : "LegacyV2Tests",
|
||||
"name" : "LegacyV2Tests"
|
||||
}
|
||||
},
|
||||
{
|
||||
"target" : {
|
||||
"containerPath" : "container:Packages\/PassepartoutWireGuardGo",
|
||||
"identifier" : "PassepartoutWireGuardGoTests",
|
||||
"name" : "PassepartoutWireGuardGoTests"
|
||||
}
|
||||
},
|
||||
{
|
||||
"target" : {
|
||||
"containerPath" : "container:Packages\/PassepartoutKit",
|
||||
"identifier" : "PassepartoutWireGuardTests",
|
||||
"name" : "PassepartoutWireGuardTests"
|
||||
}
|
||||
},
|
||||
{
|
||||
"target" : {
|
||||
"containerPath" : "container:Packages\/PassepartoutOpenVPNOpenSSL",
|
||||
"identifier" : "PassepartoutOpenVPNOpenSSLTests",
|
||||
"name" : "PassepartoutOpenVPNOpenSSLTests"
|
||||
"identifier" : "CPassepartoutCryptoOpenSSLTests",
|
||||
"name" : "CPassepartoutCryptoOpenSSLTests"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
Loading…
Reference in New Issue
Block a user