diff --git a/TunnelKit.xcodeproj/project.pbxproj b/TunnelKit.xcodeproj/project.pbxproj index eb6dd19..687b0b8 100644 --- a/TunnelKit.xcodeproj/project.pbxproj +++ b/TunnelKit.xcodeproj/project.pbxproj @@ -11,8 +11,8 @@ 0E07596020EF6D1400F38FD8 /* CryptoCBC.m in Sources */ = {isa = PBXBuildFile; fileRef = 0E07595C20EF6D1400F38FD8 /* CryptoCBC.m */; }; 0E07596320EF733F00F38FD8 /* CryptoMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = 0E07596120EF733F00F38FD8 /* CryptoMacros.h */; }; 0E07596420EF733F00F38FD8 /* CryptoMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = 0E07596120EF733F00F38FD8 /* CryptoMacros.h */; }; - 0E07596B20EF79AB00F38FD8 /* Encryption.h in Headers */ = {isa = PBXBuildFile; fileRef = 0E07596A20EF79AB00F38FD8 /* Encryption.h */; }; - 0E07596C20EF79AB00F38FD8 /* Encryption.h in Headers */ = {isa = PBXBuildFile; fileRef = 0E07596A20EF79AB00F38FD8 /* Encryption.h */; }; + 0E07596B20EF79AB00F38FD8 /* Crypto.h in Headers */ = {isa = PBXBuildFile; fileRef = 0E07596A20EF79AB00F38FD8 /* Crypto.h */; }; + 0E07596C20EF79AB00F38FD8 /* Crypto.h in Headers */ = {isa = PBXBuildFile; fileRef = 0E07596A20EF79AB00F38FD8 /* Crypto.h */; }; 0E07596E20EF79B400F38FD8 /* CryptoCBC.h in Headers */ = {isa = PBXBuildFile; fileRef = 0E07596D20EF79B400F38FD8 /* CryptoCBC.h */; }; 0E07596F20EF79B400F38FD8 /* CryptoCBC.h in Headers */ = {isa = PBXBuildFile; fileRef = 0E07596D20EF79B400F38FD8 /* CryptoCBC.h */; }; 0E07597E20F0060E00F38FD8 /* CryptoAEAD.h in Headers */ = {isa = PBXBuildFile; fileRef = 0E07597C20F0060E00F38FD8 /* CryptoAEAD.h */; }; @@ -185,7 +185,7 @@ /* Begin PBXFileReference section */ 0E07595C20EF6D1400F38FD8 /* CryptoCBC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CryptoCBC.m; sourceTree = ""; }; 0E07596120EF733F00F38FD8 /* CryptoMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoMacros.h; sourceTree = ""; }; - 0E07596A20EF79AB00F38FD8 /* Encryption.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Encryption.h; sourceTree = ""; }; + 0E07596A20EF79AB00F38FD8 /* Crypto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Crypto.h; sourceTree = ""; }; 0E07596D20EF79B400F38FD8 /* CryptoCBC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoCBC.h; sourceTree = ""; }; 0E07597C20F0060E00F38FD8 /* CryptoAEAD.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoAEAD.h; sourceTree = ""; }; 0E07597D20F0060E00F38FD8 /* CryptoAEAD.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CryptoAEAD.m; sourceTree = ""; }; @@ -236,7 +236,7 @@ 0ED9C8632138139000621BA3 /* SessionProxy+CompressionFraming.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SessionProxy+CompressionFraming.swift"; sourceTree = ""; }; 0EE7A79420F61EDC00B42E6A /* PacketMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PacketMacros.h; sourceTree = ""; }; 0EE7A79720F6296F00B42E6A /* PacketMacros.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PacketMacros.m; sourceTree = ""; }; - 0EE7A79D20F6488400B42E6A /* DataPathEncryption.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DataPathEncryption.h; sourceTree = ""; }; + 0EE7A79D20F6488400B42E6A /* DataPathCrypto.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DataPathCrypto.h; sourceTree = ""; }; 0EE7A7A020F664AB00B42E6A /* DataPathEncryptionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataPathEncryptionTests.swift; sourceTree = ""; }; 0EEC49DB20B5E732008FEB91 /* Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = ""; }; 0EFEB42A2006D3C800F81029 /* SessionProxy+EncryptionBridge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SessionProxy+EncryptionBridge.swift"; sourceTree = ""; }; @@ -440,6 +440,7 @@ 0E12B2A721456C0200B4BAE9 /* ControlChannel.swift */, 0E12B2AA2145E01700B4BAE9 /* ControlChannelSerializer.swift */, 0EFEB44A2006D3C800F81029 /* CoreConfiguration.swift */, + 0E07596A20EF79AB00F38FD8 /* Crypto.h */, 0E07597C20F0060E00F38FD8 /* CryptoAEAD.h */, 0E07597D20F0060E00F38FD8 /* CryptoAEAD.m */, 0EFEB4402006D3C800F81029 /* CryptoBox.h */, @@ -450,8 +451,7 @@ 0EFEB4432006D3C800F81029 /* Data+Manipulation.swift */, 0EFEB4352006D3C800F81029 /* DataPath.h */, 0EFEB44C2006D3C800F81029 /* DataPath.m */, - 0EE7A79D20F6488400B42E6A /* DataPathEncryption.h */, - 0E07596A20EF79AB00F38FD8 /* Encryption.h */, + 0EE7A79D20F6488400B42E6A /* DataPathCrypto.h */, 0EFEB4362006D3C800F81029 /* Errors.h */, 0EFEB44B2006D3C800F81029 /* Errors.m */, 0EFEB4452006D3C800F81029 /* IOInterface.swift */, @@ -539,7 +539,7 @@ 0E07596E20EF79B400F38FD8 /* CryptoCBC.h in Headers */, 0E07596320EF733F00F38FD8 /* CryptoMacros.h in Headers */, 0EFEB46E2006D3C800F81029 /* TLSBox.h in Headers */, - 0E07596B20EF79AB00F38FD8 /* Encryption.h in Headers */, + 0E07596B20EF79AB00F38FD8 /* Crypto.h in Headers */, 0EFEB46B2006D3C800F81029 /* CryptoBox.h in Headers */, 0EFEB4592006D3C800F81029 /* Allocation.h in Headers */, 0EFEB4582006D3C800F81029 /* MSS.h in Headers */, @@ -561,7 +561,7 @@ 0E07596F20EF79B400F38FD8 /* CryptoCBC.h in Headers */, 0E07596420EF733F00F38FD8 /* CryptoMacros.h in Headers */, 0EEC49EA20B5F7F6008FEB91 /* ZeroingData.h in Headers */, - 0E07596C20EF79AB00F38FD8 /* Encryption.h in Headers */, + 0E07596C20EF79AB00F38FD8 /* Crypto.h in Headers */, 0EEC49E120B5F7EA008FEB91 /* Allocation.h in Headers */, 0EEC49E320B5F7F6008FEB91 /* DataPath.h in Headers */, 0EF5CF282141E183004FF1BD /* CompressionFramingNative.h in Headers */, diff --git a/TunnelKit/Sources/Core/ControlChannelSerializer.swift b/TunnelKit/Sources/Core/ControlChannelSerializer.swift index 4f9a39e..de73743 100644 --- a/TunnelKit/Sources/Core/ControlChannelSerializer.swift +++ b/TunnelKit/Sources/Core/ControlChannelSerializer.swift @@ -50,15 +50,15 @@ extension ControlChannel { var offset = start let end = end ?? packet.count - guard end >= offset + PacketHeaderLength else { - throw ControlChannelError("Missing header") + guard end >= offset + PacketOpcodeLength else { + throw ControlChannelError("Missing opcode") } let codeValue = packet[offset] >> 3 guard let code = PacketCode(rawValue: codeValue) else { throw ControlChannelError("Unknown code: \(codeValue))") } let key = packet[offset] & 0b111 - offset += PacketHeaderLength + offset += PacketOpcodeLength log.debug("Control: Try read packet with code \(code) and key \(key)") diff --git a/TunnelKit/Sources/Core/ControlPacket.h b/TunnelKit/Sources/Core/ControlPacket.h index eefda9f..7e19f81 100644 --- a/TunnelKit/Sources/Core/ControlPacket.h +++ b/TunnelKit/Sources/Core/ControlPacket.h @@ -52,7 +52,8 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, strong, readonly) NSData *_Nullable payload; @property (nonatomic, strong) NSDate *_Nullable sentDate; -- (NSInteger)serializeTo:(nullable uint8_t *)to; +- (NSInteger)capacity; +- (NSInteger)serializeTo:(uint8_t *)to; - (NSData *)serialized; @end diff --git a/TunnelKit/Sources/Core/ControlPacket.m b/TunnelKit/Sources/Core/ControlPacket.m index cb1a353..bcacc0f 100644 --- a/TunnelKit/Sources/Core/ControlPacket.m +++ b/TunnelKit/Sources/Core/ControlPacket.m @@ -80,7 +80,7 @@ const BOOL isAck = self.isAck; const NSUInteger ackLength = self.ackIds.count; NSCAssert(!isAck || ackLength > 0, @"Ack packet must provide positive ackLength"); - NSInteger n = PacketHeaderLength + PacketSessionIdLength; + NSInteger n = PacketOpcodeLength + PacketSessionIdLength; n += PacketAckLengthLength; if (ackLength > 0) { n += ackLength * PacketIdLength + PacketSessionIdLength; @@ -95,9 +95,6 @@ // Ruby: send_ctrl - (NSInteger)serializeTo:(uint8_t *)to { - if (!to) { - return [self capacity]; - } uint8_t *ptr = to; ptr += PacketHeaderSet(ptr, self.code, self.key, self.sessionId.bytes); if (self.ackIds.count > 0) { @@ -124,7 +121,7 @@ ptr += self.payload.length; } } - return (int)(ptr - to); + return ptr - to; } - (NSData *)serialized diff --git a/TunnelKit/Sources/Core/Encryption.h b/TunnelKit/Sources/Core/Crypto.h similarity index 85% rename from TunnelKit/Sources/Core/Encryption.h rename to TunnelKit/Sources/Core/Crypto.h index 333544c..8ece563 100644 --- a/TunnelKit/Sources/Core/Encryption.h +++ b/TunnelKit/Sources/Core/Crypto.h @@ -1,5 +1,5 @@ // -// Encryption.h +// Crypto.h // TunnelKit // // Created by Davide De Rosa on 3/3/17. @@ -48,10 +48,8 @@ NS_ASSUME_NONNULL_BEGIN - (void)configureEncryptionWithCipherKey:(nullable ZeroingData *)cipherKey hmacKey:(nullable ZeroingData *)hmacKey; - (int)digestLength; -- (int)overheadLength; -- (int)extraLength; -- (nullable NSData *)encryptData:(NSData *)data offset:(NSInteger)offset extra:(nullable const uint8_t *)extra error:(NSError **)error; +- (NSInteger)encryptionCapacityWithLength:(NSInteger)length; - (BOOL)encryptBytes:(const uint8_t *)bytes length:(NSInteger)length dest:(uint8_t *)dest destLength:(NSInteger *)destLength extra:(nullable const uint8_t *)extra error:(NSError **)error; - (id)dataPathEncrypter; @@ -63,13 +61,10 @@ NS_ASSUME_NONNULL_BEGIN - (void)configureDecryptionWithCipherKey:(nullable ZeroingData *)cipherKey hmacKey:(nullable ZeroingData *)hmacKey; - (int)digestLength; -- (int)overheadLength; -- (int)extraLength; -- (nullable NSData *)decryptData:(NSData *)data offset:(NSInteger)offset extra:(nullable const uint8_t *)extra error:(NSError **)error; +- (NSInteger)encryptionCapacityWithLength:(NSInteger)length; - (BOOL)decryptBytes:(const uint8_t *)bytes length:(NSInteger)length dest:(uint8_t *)dest destLength:(NSInteger *)destLength extra:(nullable const uint8_t *)extra error:(NSError **)error; -- (BOOL)verifyData:(NSData *)data offset:(NSInteger)offset extra:(nullable const uint8_t *)extra error:(NSError **)error; -- (BOOL)verifyBytes:(const uint8_t *)bytes length:(NSInteger)length extra:(const uint8_t *)extra error:(NSError **)error; +- (BOOL)verifyBytes:(const uint8_t *)bytes length:(NSInteger)length extra:(nullable const uint8_t *)extra error:(NSError **)error; - (id)dataPathDecrypter; diff --git a/TunnelKit/Sources/Core/CryptoAEAD.h b/TunnelKit/Sources/Core/CryptoAEAD.h index 49809fe..6c73bc6 100644 --- a/TunnelKit/Sources/Core/CryptoAEAD.h +++ b/TunnelKit/Sources/Core/CryptoAEAD.h @@ -36,8 +36,8 @@ #import -#import "Encryption.h" -#import "DataPathEncryption.h" +#import "Crypto.h" +#import "DataPathCrypto.h" NS_ASSUME_NONNULL_BEGIN diff --git a/TunnelKit/Sources/Core/CryptoAEAD.m b/TunnelKit/Sources/Core/CryptoAEAD.m index cff34d2..85185a8 100644 --- a/TunnelKit/Sources/Core/CryptoAEAD.m +++ b/TunnelKit/Sources/Core/CryptoAEAD.m @@ -50,7 +50,6 @@ const NSInteger CryptoAEADTagLength = 16; @property (nonatomic, unsafe_unretained) const EVP_CIPHER *cipher; @property (nonatomic, assign) int cipherKeyLength; @property (nonatomic, assign) int cipherIVLength; // 12 (AD packetId + HMAC key) -@property (nonatomic, assign) int overheadLength; @property (nonatomic, assign) int extraPacketIdOffset; @property (nonatomic, unsafe_unretained) EVP_CIPHER_CTX *cipherCtxEnc; @@ -73,7 +72,6 @@ const NSInteger CryptoAEADTagLength = 16; self.cipherKeyLength = EVP_CIPHER_key_length(self.cipher); self.cipherIVLength = EVP_CIPHER_iv_length(self.cipher); - self.overheadLength = CryptoAEADTagLength; self.extraLength = PacketIdLength; self.extraPacketIdOffset = 0; @@ -102,6 +100,11 @@ const NSInteger CryptoAEADTagLength = 16; return 0; } +- (NSInteger)encryptionCapacityWithLength:(NSInteger)length +{ + return safe_crypto_capacity(length, CryptoAEADTagLength); +} + #pragma mark Encrypter - (void)configureEncryptionWithCipherKey:(ZeroingData *)cipherKey hmacKey:(ZeroingData *)hmacKey @@ -115,24 +118,6 @@ const NSInteger CryptoAEADTagLength = 16; [self prepareIV:self.cipherIVEnc withHMACKey:hmacKey]; } -- (NSData *)encryptData:(NSData *)data offset:(NSInteger)offset extra:(const uint8_t *)extra error:(NSError *__autoreleasing *)error -{ - NSParameterAssert(data); - NSParameterAssert(extra); - - const uint8_t *bytes = data.bytes + offset; - const int length = (int)(data.length - offset); - const int maxOutputSize = (int)safe_crypto_capacity(data.length, self.overheadLength); - - NSMutableData *dest = [[NSMutableData alloc] initWithLength:maxOutputSize]; - NSInteger encryptedLength = INT_MAX; - if (![self encryptBytes:bytes length:length dest:dest.mutableBytes destLength:&encryptedLength extra:extra error:error]) { - return nil; - } - dest.length = encryptedLength; - return dest; -} - - (BOOL)encryptBytes:(const uint8_t *)bytes length:(NSInteger)length dest:(uint8_t *)dest destLength:(NSInteger *)destLength extra:(const uint8_t *)extra error:(NSError *__autoreleasing *)error { NSParameterAssert(extra); @@ -179,24 +164,6 @@ const NSInteger CryptoAEADTagLength = 16; [self prepareIV:self.cipherIVDec withHMACKey:hmacKey]; } -- (NSData *)decryptData:(NSData *)data offset:(NSInteger)offset extra:(const uint8_t *)extra error:(NSError *__autoreleasing *)error -{ - NSParameterAssert(data); - NSParameterAssert(extra); - - const uint8_t *bytes = data.bytes + offset; - const int length = (int)(data.length - offset); - const int maxOutputSize = (int)safe_crypto_capacity(data.length, self.overheadLength); - - NSMutableData *dest = [[NSMutableData alloc] initWithLength:maxOutputSize]; - NSInteger decryptedLength; - if (![self decryptBytes:bytes length:length dest:dest.mutableBytes destLength:&decryptedLength extra:extra error:error]) { - return nil; - } - dest.length = decryptedLength; - return dest; -} - - (BOOL)decryptBytes:(const uint8_t *)bytes length:(NSInteger)length dest:(uint8_t *)dest destLength:(NSInteger *)destLength extra:(const uint8_t *)extra error:(NSError *__autoreleasing *)error { NSParameterAssert(extra); @@ -225,15 +192,9 @@ const NSInteger CryptoAEADTagLength = 16; TUNNEL_CRYPTO_RETURN_STATUS(code) } -- (BOOL)verifyData:(NSData *)data offset:(NSInteger)offset extra:(const uint8_t *)extra error:(NSError *__autoreleasing *)error -{ - NSAssert(NO, @"Verification not supported"); - return NO; -} - - (BOOL)verifyBytes:(const uint8_t *)bytes length:(NSInteger)length extra:(const uint8_t *)extra error:(NSError *__autoreleasing *)error { - NSAssert(NO, @"Verification not supported"); + [NSException raise:NSInvalidArgumentException format:@"Verification not supported"]; return NO; } @@ -276,17 +237,12 @@ const NSInteger CryptoAEADTagLength = 16; #pragma mark DataPathChannel -- (int)overheadLength -{ - return self.crypto.overheadLength; -} - - (void)setPeerId:(uint32_t)peerId { peerId &= 0xffffff; if (peerId == PacketPeerIdDisabled) { - self.headerLength = 1; + self.headerLength = PacketOpcodeLength; self.crypto.extraLength = PacketIdLength; self.crypto.extraPacketIdOffset = 0; self.setDataHeader = ^(uint8_t *to, uint8_t key) { @@ -295,7 +251,7 @@ const NSInteger CryptoAEADTagLength = 16; self.checkPeerId = NULL; } else { - self.headerLength = 4; + self.headerLength = PacketOpcodeLength + PacketPeerIdLength; self.crypto.extraLength = self.headerLength + PacketIdLength; self.crypto.extraPacketIdOffset = self.headerLength; self.setDataHeader = ^(uint8_t *to, uint8_t key) { @@ -307,6 +263,11 @@ const NSInteger CryptoAEADTagLength = 16; } } +- (NSInteger)encryptionCapacityWithLength:(NSInteger)length +{ + return [self.crypto encryptionCapacityWithLength:length]; +} + #pragma mark DataPathEncrypter - (void)assembleDataPacketWithBlock:(DataPathAssembleBlock)block packetId:(uint32_t)packetId payload:(NSData *)payload into:(uint8_t *)packetBytes length:(NSInteger *)packetLength @@ -324,7 +285,7 @@ const NSInteger CryptoAEADTagLength = 16; - (NSData *)encryptedDataPacketWithKey:(uint8_t)key packetId:(uint32_t)packetId packetBytes:(const uint8_t *)packetBytes packetLength:(NSInteger)packetLength error:(NSError *__autoreleasing *)error { - const int capacity = self.headerLength + PacketIdLength + (int)safe_crypto_capacity(packetLength, self.crypto.overheadLength); + const int capacity = self.headerLength + PacketIdLength + (int)[self.crypto encryptionCapacityWithLength:packetLength]; NSMutableData *encryptedPacket = [[NSMutableData alloc] initWithLength:capacity]; uint8_t *ptr = encryptedPacket.mutableBytes; NSInteger encryptedPacketLength = INT_MAX; diff --git a/TunnelKit/Sources/Core/CryptoCBC.h b/TunnelKit/Sources/Core/CryptoCBC.h index 9ef8c29..d8cb6e8 100644 --- a/TunnelKit/Sources/Core/CryptoCBC.h +++ b/TunnelKit/Sources/Core/CryptoCBC.h @@ -36,8 +36,8 @@ #import -#import "Encryption.h" -#import "DataPathEncryption.h" +#import "Crypto.h" +#import "DataPathCrypto.h" NS_ASSUME_NONNULL_BEGIN diff --git a/TunnelKit/Sources/Core/CryptoCBC.m b/TunnelKit/Sources/Core/CryptoCBC.m index b7227a4..5b69e10 100644 --- a/TunnelKit/Sources/Core/CryptoCBC.m +++ b/TunnelKit/Sources/Core/CryptoCBC.m @@ -54,7 +54,6 @@ const NSInteger CryptoCBCMaxHMACLength = 100; @property (nonatomic, assign) int cipherIVLength; @property (nonatomic, assign) int hmacKeyLength; @property (nonatomic, assign) int digestLength; -@property (nonatomic, assign) int overheadLength; @property (nonatomic, unsafe_unretained) EVP_CIPHER_CTX *cipherCtxEnc; @property (nonatomic, unsafe_unretained) EVP_CIPHER_CTX *cipherCtxDec; @@ -87,7 +86,6 @@ const NSInteger CryptoCBCMaxHMACLength = 100; // as seen in OpenVPN's crypto_openssl.c:md_kt_size() self.hmacKeyLength = EVP_MD_size(self.digest); self.digestLength = EVP_MD_size(self.digest); - self.overheadLength = self.cipherIVLength + self.digestLength; if (cipherName) { self.cipherCtxEnc = EVP_CIPHER_CTX_new(); @@ -120,6 +118,11 @@ const NSInteger CryptoCBCMaxHMACLength = 100; return 0; } +- (NSInteger)encryptionCapacityWithLength:(NSInteger)length +{ + return safe_crypto_capacity(length, self.digestLength + self.cipherIVLength); +} + #pragma mark Encrypter - (void)configureEncryptionWithCipherKey:(ZeroingData *)cipherKey hmacKey:(ZeroingData *)hmacKey @@ -138,23 +141,6 @@ const NSInteger CryptoCBCMaxHMACLength = 100; HMAC_Init_ex(self.hmacCtxEnc, hmacKey.bytes, self.hmacKeyLength, self.digest, NULL); } -- (NSData *)encryptData:(NSData *)data offset:(NSInteger)offset extra:(const uint8_t *)extra error:(NSError *__autoreleasing *)error -{ - NSParameterAssert(data); - - const uint8_t *bytes = data.bytes + offset; - const int length = (int)(data.length - offset); - const int maxOutputSize = (int)safe_crypto_capacity(data.length, self.overheadLength); - - NSMutableData *dest = [[NSMutableData alloc] initWithLength:maxOutputSize]; - NSInteger encryptedLength = INT_MAX; - if (![self encryptBytes:bytes length:length dest:dest.mutableBytes destLength:&encryptedLength extra:extra error:error]) { - return nil; - } - dest.length = encryptedLength; - return dest; -} - - (BOOL)encryptBytes:(const uint8_t *)bytes length:(NSInteger)length dest:(uint8_t *)dest destLength:(NSInteger *)destLength extra:(const uint8_t *)extra error:(NSError *__autoreleasing *)error { uint8_t *outIV = dest + self.digestLength; @@ -214,24 +200,6 @@ const NSInteger CryptoCBCMaxHMACLength = 100; HMAC_Init_ex(self.hmacCtxDec, hmacKey.bytes, self.hmacKeyLength, self.digest, NULL); } -- (NSData *)decryptData:(NSData *)data offset:(NSInteger)offset extra:(const uint8_t *)extra error:(NSError *__autoreleasing *)error -{ - NSAssert(self.cipher, @"No cipher provided"); - NSParameterAssert(data); - - const uint8_t *bytes = data.bytes + offset; - const int length = (int)(data.length - offset); - const int maxOutputSize = (int)safe_crypto_capacity(data.length, self.overheadLength); - - NSMutableData *dest = [[NSMutableData alloc] initWithLength:maxOutputSize]; - NSInteger decryptedLength; - if (![self decryptBytes:bytes length:length dest:dest.mutableBytes destLength:&decryptedLength extra:extra error:error]) { - return nil; - } - dest.length = decryptedLength; - return dest; -} - - (BOOL)decryptBytes:(const uint8_t *)bytes length:(NSInteger)length dest:(uint8_t *)dest destLength:(NSInteger *)destLength extra:(const uint8_t *)extra error:(NSError *__autoreleasing *)error { NSAssert(self.cipher, @"No cipher provided"); @@ -261,11 +229,6 @@ const NSInteger CryptoCBCMaxHMACLength = 100; TUNNEL_CRYPTO_RETURN_STATUS(code) } -- (BOOL)verifyData:(NSData *)data offset:(NSInteger)offset extra:(const uint8_t *)extra error:(NSError *__autoreleasing *)error -{ - return [self verifyBytes:data.bytes length:data.length extra:extra error:error]; -} - - (BOOL)verifyBytes:(const uint8_t *)bytes length:(NSInteger)length extra:(const uint8_t *)extra error:(NSError *__autoreleasing *)error { int l1 = 0; @@ -316,24 +279,19 @@ const NSInteger CryptoCBCMaxHMACLength = 100; #pragma mark DataPathChannel -- (int)overheadLength -{ - return self.crypto.overheadLength; -} - - (void)setPeerId:(uint32_t)peerId { peerId &= 0xffffff; if (peerId == PacketPeerIdDisabled) { - self.headerLength = 1; + self.headerLength = PacketOpcodeLength; self.setDataHeader = ^(uint8_t *to, uint8_t key) { PacketHeaderSet(to, PacketCodeDataV1, key, nil); }; self.checkPeerId = NULL; } else { - self.headerLength = 4; + self.headerLength = PacketOpcodeLength + PacketPeerIdLength; self.setDataHeader = ^(uint8_t *to, uint8_t key) { PacketHeaderSetDataV2(to, key, peerId); }; @@ -343,6 +301,11 @@ const NSInteger CryptoCBCMaxHMACLength = 100; } } +- (NSInteger)encryptionCapacityWithLength:(NSInteger)length +{ + return [self.crypto encryptionCapacityWithLength:length]; +} + #pragma mark DataPathEncrypter - (void)assembleDataPacketWithBlock:(DataPathAssembleBlock)block packetId:(uint32_t)packetId payload:(NSData *)payload into:(uint8_t *)packetBytes length:(NSInteger *)packetLength @@ -363,7 +326,7 @@ const NSInteger CryptoCBCMaxHMACLength = 100; - (NSData *)encryptedDataPacketWithKey:(uint8_t)key packetId:(uint32_t)packetId packetBytes:(const uint8_t *)packetBytes packetLength:(NSInteger)packetLength error:(NSError *__autoreleasing *)error { - const int capacity = self.headerLength + (int)safe_crypto_capacity(packetLength, self.crypto.overheadLength); + const int capacity = self.headerLength + (int)[self.crypto encryptionCapacityWithLength:packetLength]; NSMutableData *encryptedPacket = [[NSMutableData alloc] initWithLength:capacity]; uint8_t *ptr = encryptedPacket.mutableBytes; NSInteger encryptedPacketLength = INT_MAX; diff --git a/TunnelKit/Sources/Core/DataPath.m b/TunnelKit/Sources/Core/DataPath.m index 233918b..f297fd4 100644 --- a/TunnelKit/Sources/Core/DataPath.m +++ b/TunnelKit/Sources/Core/DataPath.m @@ -37,7 +37,7 @@ #import #import "DataPath.h" -#import "DataPathEncryption.h" +#import "DataPathCrypto.h" #import "MSS.h" #import "ReplayProtector.h" #import "Allocation.h" @@ -120,7 +120,7 @@ - (void)adjustEncBufferToPacketSize:(int)size { - const int neededCapacity = DataPathByteAlignment + (int)safe_crypto_capacity(size, self.encrypter.overheadLength); + const int neededCapacity = DataPathByteAlignment + (int)[self.encrypter encryptionCapacityWithLength:size]; if (self.encBufferCapacity >= neededCapacity) { return; } @@ -132,7 +132,7 @@ - (void)adjustDecBufferToPacketSize:(int)size { - const int neededCapacity = DataPathByteAlignment + (int)safe_crypto_capacity(size, self.decrypter.overheadLength); + const int neededCapacity = DataPathByteAlignment + (int)[self.decrypter encryptionCapacityWithLength:size]; if (self.decBufferCapacity >= neededCapacity) { return; } diff --git a/TunnelKit/Sources/Core/DataPathEncryption.h b/TunnelKit/Sources/Core/DataPathCrypto.h similarity index 97% rename from TunnelKit/Sources/Core/DataPathEncryption.h rename to TunnelKit/Sources/Core/DataPathCrypto.h index e84d1f8..bb9b591 100644 --- a/TunnelKit/Sources/Core/DataPathEncryption.h +++ b/TunnelKit/Sources/Core/DataPathCrypto.h @@ -1,5 +1,5 @@ // -// DataPathEncryption.h +// DataPathCrypto.h // TunnelKit // // Created by Davide De Rosa on 7/11/18. @@ -43,8 +43,8 @@ typedef void (^DataPathParseBlock)(uint8_t *payload, NSInteger *payloadOffset, N @protocol DataPathChannel -- (int)overheadLength; - (void)setPeerId:(uint32_t)peerId; +- (NSInteger)encryptionCapacityWithLength:(NSInteger)length; @end diff --git a/TunnelKit/Sources/Core/PacketMacros.h b/TunnelKit/Sources/Core/PacketMacros.h index 3c740d9..019a170 100644 --- a/TunnelKit/Sources/Core/PacketMacros.h +++ b/TunnelKit/Sources/Core/PacketMacros.h @@ -39,7 +39,7 @@ NS_ASSUME_NONNULL_BEGIN -#define PacketHeaderLength ((NSInteger)1) +#define PacketOpcodeLength ((NSInteger)1) #define PacketIdLength ((NSInteger)4) #define PacketSessionIdLength ((NSInteger)8) #define PacketAckLengthLength ((NSInteger)1) @@ -66,7 +66,7 @@ extern const uint8_t DataPacketPingData[16]; static inline int PacketHeaderSet(uint8_t *to, PacketCode code, uint8_t key, const uint8_t *_Nullable sessionId) { *(uint8_t *)to = (code << 3) | (key & 0b111); - int offset = PacketHeaderLength; + int offset = PacketOpcodeLength; if (sessionId) { memcpy(to + offset, sessionId, PacketSessionIdLength); offset += PacketSessionIdLength; @@ -77,7 +77,7 @@ static inline int PacketHeaderSet(uint8_t *to, PacketCode code, uint8_t key, con static inline int PacketHeaderSetDataV2(uint8_t *to, uint8_t key, uint32_t peerId) { *(uint32_t *)to = ((PacketCodeDataV2 << 3) | (key & 0b111)) | htonl(peerId & 0xffffff); - return PacketHeaderLength + PacketPeerIdLength; + return PacketOpcodeLength + PacketPeerIdLength; } static inline int PacketHeaderGetDataV2PeerId(const uint8_t *from) diff --git a/TunnelKit/Sources/Core/ZeroingData.h b/TunnelKit/Sources/Core/ZeroingData.h index 3e2fe3d..8298c5a 100644 --- a/TunnelKit/Sources/Core/ZeroingData.h +++ b/TunnelKit/Sources/Core/ZeroingData.h @@ -66,6 +66,7 @@ NS_ASSUME_NONNULL_BEGIN - (nullable NSString *)nullTerminatedStringFromOffset:(NSInteger)from; - (BOOL)isEqualToData:(NSData *)data; +- (NSData *)toData; // XXX: unsafe - (NSString *)toHex; @end diff --git a/TunnelKit/Sources/Core/ZeroingData.m b/TunnelKit/Sources/Core/ZeroingData.m index 2cab776..672418a 100644 --- a/TunnelKit/Sources/Core/ZeroingData.m +++ b/TunnelKit/Sources/Core/ZeroingData.m @@ -276,6 +276,11 @@ return !memcmp(_bytes, data.bytes, _count); } +- (NSData *)toData +{ + return [NSData dataWithBytes:_bytes length:_count]; +} + - (NSString *)toHex { const NSUInteger capacity = _count * 2; diff --git a/TunnelKit/Sources/Core/module.modulemap b/TunnelKit/Sources/Core/module.modulemap index 0eb8bf0..626b52a 100644 --- a/TunnelKit/Sources/Core/module.modulemap +++ b/TunnelKit/Sources/Core/module.modulemap @@ -38,14 +38,14 @@ module __TunnelKitNative { header "Errors.h" header "ZeroingData.h" header "TLSBox.h" + header "Crypto.h" header "CryptoBox.h" - header "Encryption.h" header "MSS.h" header "PacketMacros.h" header "ControlPacket.h" header "ReplayProtector.h" header "CompressionFramingNative.h" header "DataPath.h" - header "DataPathEncryption.h" + header "DataPathCrypto.h" export * } diff --git a/TunnelKitTests/DataManipulationTests.swift b/TunnelKitTests/DataManipulationTests.swift index 56df9a0..05f29c7 100644 --- a/TunnelKitTests/DataManipulationTests.swift +++ b/TunnelKitTests/DataManipulationTests.swift @@ -69,8 +69,8 @@ class DataManipulationTests: XCTestCase { let z2 = z1.withOffset(2, count: 3) // 5678ab let z3 = z2.appending(Z(Data(hex: "aaddcc"))) // 5678abaaddcc - XCTAssertEqual(z1.data, Data(hex: "12345678abcdef")) - XCTAssertEqual(z2.data, Data(hex: "5678ab")) - XCTAssertEqual(z3.data, Data(hex: "5678abaaddcc")) + XCTAssertEqual(z1.toData(), Data(hex: "12345678abcdef")) + XCTAssertEqual(z2.toData(), Data(hex: "5678ab")) + XCTAssertEqual(z3.toData(), Data(hex: "5678abaaddcc")) } } diff --git a/TunnelKitTests/EncryptionPerformanceTests.swift b/TunnelKitTests/EncryptionPerformanceTests.swift index 90f8e46..645c781 100644 --- a/TunnelKitTests/EncryptionPerformanceTests.swift +++ b/TunnelKitTests/EncryptionPerformanceTests.swift @@ -72,7 +72,7 @@ class EncryptionPerformanceTests: XCTestCase { let suite = TestUtils.generateDataSuite(1000, 100000) measure { for data in suite { - let _ = try! self.cbcEncrypter.encryptData(data, offset: 0, extra: nil) + let _ = try! self.cbcEncrypter.encryptData(data, extra: nil) } } } @@ -83,7 +83,7 @@ class EncryptionPerformanceTests: XCTestCase { let extra: [UInt8] = [0x11, 0x22, 0x33, 0x44] measure { for data in suite { - let _ = try! self.gcmEncrypter.encryptData(data, offset: 0, extra: extra) + let _ = try! self.gcmEncrypter.encryptData(data, extra: extra) } } } diff --git a/TunnelKitTests/EncryptionTests.swift b/TunnelKitTests/EncryptionTests.swift index aa1899d..a7b598e 100644 --- a/TunnelKitTests/EncryptionTests.swift +++ b/TunnelKitTests/EncryptionTests.swift @@ -40,13 +40,19 @@ import XCTest @testable import __TunnelKitNative class EncryptionTests: XCTestCase { - private var cipherKey: ZeroingData! + private var cipherEncKey: ZeroingData! - private var hmacKey: ZeroingData! + private var cipherDecKey: ZeroingData! + + private var hmacEncKey: ZeroingData! + + private var hmacDecKey: ZeroingData! override func setUp() { - cipherKey = try! SecureRandom.safeData(length: 32) - hmacKey = try! SecureRandom.safeData(length: 32) + cipherEncKey = try! SecureRandom.safeData(length: 32) + cipherDecKey = try! SecureRandom.safeData(length: 32) + hmacEncKey = try! SecureRandom.safeData(length: 32) + hmacDecKey = try! SecureRandom.safeData(length: 32) } override func tearDown() { @@ -54,67 +60,38 @@ class EncryptionTests: XCTestCase { } func testCBC() { - let cbc = CryptoBox(cipherAlgorithm: "aes-128-cbc", digestAlgorithm: "sha256") - try! cbc.configure(withCipherEncKey: cipherKey, cipherDecKey: cipherKey, hmacEncKey: hmacKey, hmacDecKey: hmacKey) - let enc = cbc.encrypter() - let dec = cbc.decrypter() - + let (client, server) = clientServer("aes-128-cbc", "sha256") + let plain = Data(hex: "00112233445566778899") - let encrypted = try! enc.encryptData(plain, offset: 0, extra: nil) - let decrypted = try! dec.decryptData(encrypted, offset: 0, extra: nil) + let encrypted = try! client.encrypter().encryptData(plain, extra: nil) + let decrypted = try! server.decrypter().decryptData(encrypted, extra: nil) XCTAssertEqual(plain, decrypted) } func testHMAC() { - let cbc = CryptoBox(cipherAlgorithm: nil, digestAlgorithm: "sha256") - try! cbc.configure(withCipherEncKey: nil, cipherDecKey: nil, hmacEncKey: hmacKey, hmacDecKey: hmacKey) - let enc = cbc.encrypter() - let dec = cbc.decrypter() - + let (client, server) = clientServer(nil, "sha256") + let plain = Data(hex: "00112233445566778899") - let encrypted = try! enc.encryptData(plain, offset: 0, extra: nil) - do { - try dec.verifyData(encrypted, offset: 0, extra: nil) - XCTAssert(true) - } catch { - XCTAssert(false) - } + let encrypted = try! client.encrypter().encryptData(plain, extra: nil) + XCTAssertNoThrow(try server.decrypter().verifyData(encrypted, extra: nil)) } func testGCM() { - let gcm = CryptoBox(cipherAlgorithm: "aes-256-gcm", digestAlgorithm: nil) - try! gcm.configure(withCipherEncKey: cipherKey, cipherDecKey: cipherKey, hmacEncKey: hmacKey, hmacDecKey: hmacKey) - let enc = gcm.encrypter() - let dec = gcm.decrypter() + let (client, server) = clientServer("aes-256-gcm", nil) // let packetId: UInt32 = 0x56341200 let extra: [UInt8] = [0x00, 0x12, 0x34, 0x56] let plain = Data(hex: "00112233445566778899") - let encrypted = try! enc.encryptData(plain, offset: 0, extra: extra) - let decrypted = try! dec.decryptData(encrypted, offset: 0, extra: extra) + let encrypted = try! client.encrypter().encryptData(plain, extra: extra) + let decrypted = try! server.decrypter().decryptData(encrypted, extra: extra) XCTAssertEqual(plain, decrypted) } -// func testCryptoOperation() { -// let data = Data(hex: "aabbccddeeff") -// -// print("Original : \(data.toHex())") -// var enc: Data -// var dec: Data -// -// enc = Data() -// enc.append(try! encrypter.encryptData(data, offset: 0, packetId: 0)) -// print("Encrypted: \(enc.toHex())") -// dec = try! decrypter.decryptData(enc, offset: 0, packetId: 0) -// print("Decrypted: \(dec.toHex())") -// XCTAssert(dec == data) -// -// let prefix = "abcdef" -// enc = Data(hex: prefix) -// enc.append(try! encrypter.encryptData(data, offset: 0, packetId: 0)) -// print("Encrypted: \(enc.toHex())") -// dec = try! decrypter.decryptData(enc, offset: (prefix.count / 2), packetId: 0) -// print("Decrypted: \(dec.toHex())") -// XCTAssert(dec == data) -// } + private func clientServer(_ c: String?, _ d: String?) -> (CryptoBox, CryptoBox) { + let client = CryptoBox(cipherAlgorithm: c, digestAlgorithm: d) + let server = CryptoBox(cipherAlgorithm: c, digestAlgorithm: d) + XCTAssertNoThrow(try client.configure(withCipherEncKey: cipherEncKey, cipherDecKey: cipherDecKey, hmacEncKey: hmacEncKey, hmacDecKey: hmacDecKey)) + XCTAssertNoThrow(try server.configure(withCipherEncKey: cipherDecKey, cipherDecKey: cipherEncKey, hmacEncKey: hmacDecKey, hmacDecKey: hmacEncKey)) + return (client, server) + } } diff --git a/TunnelKitTests/TestUtils.swift b/TunnelKitTests/TestUtils.swift index a481fe5..8e516a5 100644 --- a/TunnelKitTests/TestUtils.swift +++ b/TunnelKitTests/TestUtils.swift @@ -56,8 +56,35 @@ class TestUtils { } } -extension ZeroingData { - var data: Data { - return Data(bytes: bytes, count: count) +extension Encrypter { + func encryptData(_ data: Data, extra: [UInt8]?) throws -> Data { + let srcLength = data.count + var dest: [UInt8] = Array(repeating: 0, count: srcLength + 256) + var destLength = 0 + try data.withUnsafeBytes { + try encryptBytes($0, length: srcLength, dest: &dest, destLength: &destLength, extra: extra) + } + dest.removeSubrange(destLength.. Data { + let srcLength = data.count + var dest: [UInt8] = Array(repeating: 0, count: srcLength + 256) + var destLength = 0 + try data.withUnsafeBytes { + try decryptBytes($0, length: srcLength, dest: &dest, destLength: &destLength, extra: extra) + } + dest.removeSubrange(destLength..