Merge pull request #6 from keeshux/block-based-payload-assembly
Block based payload assembly
This commit is contained in:
commit
2f7d41a921
@ -51,9 +51,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
|
|
||||||
@interface DataPathCryptoAEAD : NSObject <DataPathEncrypter, DataPathDecrypter>
|
@interface DataPathCryptoAEAD : NSObject <DataPathEncrypter, DataPathDecrypter>
|
||||||
|
|
||||||
@property (nonatomic, assign) uint32_t peerId;
|
|
||||||
@property (nonatomic, assign) CompressionFraming compressionFraming;
|
|
||||||
|
|
||||||
- (instancetype)initWithCrypto:(nonnull CryptoAEAD *)crypto;
|
- (instancetype)initWithCrypto:(nonnull CryptoAEAD *)crypto;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -264,15 +264,16 @@ const NSInteger CryptoAEADTagLength = 16;
|
|||||||
|
|
||||||
- (void)setPeerId:(uint32_t)peerId
|
- (void)setPeerId:(uint32_t)peerId
|
||||||
{
|
{
|
||||||
_peerId = peerId & 0xffffff;
|
peerId &= 0xffffff;
|
||||||
|
|
||||||
if (_peerId == PacketPeerIdDisabled) {
|
if (peerId == PacketPeerIdDisabled) {
|
||||||
self.headerLength = 1;
|
self.headerLength = 1;
|
||||||
self.crypto.extraLength = PacketIdLength;
|
self.crypto.extraLength = PacketIdLength;
|
||||||
self.crypto.extraPacketIdOffset = 0;
|
self.crypto.extraPacketIdOffset = 0;
|
||||||
self.setDataHeader = ^(uint8_t *to, uint8_t key) {
|
self.setDataHeader = ^(uint8_t *to, uint8_t key) {
|
||||||
PacketHeaderSet(to, PacketCodeDataV1, key);
|
PacketHeaderSet(to, PacketCodeDataV1, key);
|
||||||
};
|
};
|
||||||
|
self.checkPeerId = NULL;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
self.headerLength = 4;
|
self.headerLength = 4;
|
||||||
@ -282,87 +283,72 @@ const NSInteger CryptoAEADTagLength = 16;
|
|||||||
PacketHeaderSetDataV2(to, key, peerId);
|
PacketHeaderSetDataV2(to, key, peerId);
|
||||||
};
|
};
|
||||||
self.checkPeerId = ^BOOL(const uint8_t *ptr) {
|
self.checkPeerId = ^BOOL(const uint8_t *ptr) {
|
||||||
return (PacketHeaderGetDataV2PeerId(ptr) == self.peerId);
|
return (PacketHeaderGetDataV2PeerId(ptr) == peerId);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark DataPathEncrypter
|
#pragma mark DataPathEncrypter
|
||||||
|
|
||||||
- (void)assembleDataPacketWithPacketId:(uint32_t)packetId payload:(NSData *)payload into:(uint8_t *)dest length:(NSInteger *)length
|
- (void)assembleDataPacketWithBlock:(DataPathAssembleBlock)block packetId:(uint32_t)packetId payload:(NSData *)payload into:(uint8_t *)packetBytes length:(NSInteger *)packetLength
|
||||||
{
|
{
|
||||||
uint8_t *ptr = dest;
|
*packetLength = payload.length;
|
||||||
*length = (int)(ptr - dest + payload.length);
|
if (!block) {
|
||||||
|
memcpy(packetBytes, payload.bytes, payload.length);
|
||||||
switch (self.compressionFraming) {
|
return;
|
||||||
case CompressionFramingDisabled:
|
|
||||||
memcpy(ptr, payload.bytes, payload.length);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CompressionFramingCompress:
|
|
||||||
memcpy(ptr, payload.bytes, payload.length);
|
|
||||||
ptr[payload.length] = *ptr;
|
|
||||||
*ptr = CompressionFramingNoCompressSwap;
|
|
||||||
*length += sizeof(uint8_t);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CompressionFramingCompLZO:
|
|
||||||
memcpy(ptr + sizeof(uint8_t), payload.bytes, payload.length);
|
|
||||||
*ptr = CompressionFramingNoCompress;
|
|
||||||
*length += sizeof(uint8_t);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSData *)encryptedDataPacketWithKey:(uint8_t)key packetId:(uint32_t)packetId payload:(const uint8_t *)payload payloadLength:(NSInteger)payloadLength error:(NSError *__autoreleasing *)error
|
NSInteger packetLengthOffset;
|
||||||
|
block(packetBytes, &packetLengthOffset, payload);
|
||||||
|
*packetLength += packetLengthOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (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(payloadLength, self.crypto.overheadLength);
|
const int capacity = self.headerLength + PacketIdLength + (int)safe_crypto_capacity(packetLength, self.crypto.overheadLength);
|
||||||
NSMutableData *encryptedPacket = [[NSMutableData alloc] initWithLength:capacity];
|
NSMutableData *encryptedPacket = [[NSMutableData alloc] initWithLength:capacity];
|
||||||
uint8_t *ptr = encryptedPacket.mutableBytes;
|
uint8_t *ptr = encryptedPacket.mutableBytes;
|
||||||
NSInteger encryptedPayloadLength = INT_MAX;
|
NSInteger encryptedPacketLength = INT_MAX;
|
||||||
|
|
||||||
self.setDataHeader(ptr, key);
|
self.setDataHeader(ptr, key);
|
||||||
*(uint32_t *)(ptr + self.headerLength) = htonl(packetId);
|
*(uint32_t *)(ptr + self.headerLength) = htonl(packetId);
|
||||||
|
|
||||||
const uint8_t *extra = ptr; // AD = header + peer id + packet id
|
const uint8_t *extra = ptr; // AD = header + peer id + packet id
|
||||||
if (self.peerId == PacketPeerIdDisabled) {
|
if (!self.checkPeerId) {
|
||||||
extra += self.headerLength; // AD = packet id only
|
extra += self.headerLength; // AD = packet id only
|
||||||
}
|
}
|
||||||
|
|
||||||
const BOOL success = [self.crypto encryptBytes:payload
|
const BOOL success = [self.crypto encryptBytes:packetBytes
|
||||||
length:payloadLength
|
length:packetLength
|
||||||
dest:(ptr + self.headerLength + PacketIdLength) // skip header and packet id
|
dest:(ptr + self.headerLength + PacketIdLength) // skip header and packet id
|
||||||
destLength:&encryptedPayloadLength
|
destLength:&encryptedPacketLength
|
||||||
extra:extra
|
extra:extra
|
||||||
error:error];
|
error:error];
|
||||||
|
|
||||||
NSAssert(encryptedPayloadLength <= capacity, @"Did not allocate enough bytes for payload");
|
NSAssert(encryptedPacketLength <= capacity, @"Did not allocate enough bytes for payload");
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
encryptedPacket.length = self.headerLength + PacketIdLength + encryptedPayloadLength;
|
encryptedPacket.length = self.headerLength + PacketIdLength + encryptedPacketLength;
|
||||||
return encryptedPacket;
|
return encryptedPacket;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark DataPathDecrypter
|
#pragma mark DataPathDecrypter
|
||||||
|
|
||||||
- (BOOL)decryptDataPacket:(NSData *)packet into:(uint8_t *)dest length:(NSInteger *)length packetId:(uint32_t *)packetId error:(NSError *__autoreleasing *)error
|
- (BOOL)decryptDataPacket:(NSData *)packet into:(uint8_t *)packetBytes length:(NSInteger *)packetLength packetId:(uint32_t *)packetId error:(NSError *__autoreleasing *)error
|
||||||
{
|
{
|
||||||
const uint8_t *extra = packet.bytes; // AD = header + peer id + packet id
|
const uint8_t *extra = packet.bytes; // AD = header + peer id + packet id
|
||||||
if (self.peerId == PacketPeerIdDisabled) {
|
if (!self.checkPeerId) {
|
||||||
extra += self.headerLength; // AD = packet id only
|
extra += self.headerLength; // AD = packet id only
|
||||||
}
|
}
|
||||||
|
|
||||||
// skip header + packet id
|
// skip header + packet id
|
||||||
const BOOL success = [self.crypto decryptBytes:(packet.bytes + self.headerLength + PacketIdLength)
|
const BOOL success = [self.crypto decryptBytes:(packet.bytes + self.headerLength + PacketIdLength)
|
||||||
length:(int)(packet.length - (self.headerLength + PacketIdLength))
|
length:(int)(packet.length - (self.headerLength + PacketIdLength))
|
||||||
dest:dest
|
dest:packetBytes
|
||||||
destLength:length
|
destLength:packetLength
|
||||||
extra:extra
|
extra:extra
|
||||||
error:error];
|
error:error];
|
||||||
if (!success) {
|
if (!success) {
|
||||||
@ -378,27 +364,19 @@ const NSInteger CryptoAEADTagLength = 16;
|
|||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (const uint8_t *)parsePayloadWithDataPacket:(uint8_t *)packet packetLength:(NSInteger)packetLength length:(NSInteger *)length
|
- (const uint8_t *)parsePayloadWithBlock:(DataPathParseBlock)block length:(NSInteger *)length packetBytes:(uint8_t *)packetBytes packetLength:(NSInteger)packetLength
|
||||||
{
|
{
|
||||||
uint8_t *ptr = packet;
|
uint8_t *payload = packetBytes;
|
||||||
*length = packetLength - (int)(ptr - packet);
|
*length = packetLength - (int)(payload - packetBytes);
|
||||||
if (self.compressionFraming != CompressionFramingDisabled) {
|
if (!block) {
|
||||||
switch (*ptr) {
|
return payload;
|
||||||
case CompressionFramingNoCompress:
|
|
||||||
ptr += sizeof(uint8_t);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CompressionFramingNoCompressSwap:
|
|
||||||
*ptr = packet[packetLength - 1];
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
NSAssert(NO, @"Compression not supported (found %X)", *ptr);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
*length -= sizeof(uint8_t);
|
|
||||||
}
|
NSInteger payloadOffset;
|
||||||
return ptr;
|
NSInteger payloadHeaderLength;
|
||||||
|
block(payload, &payloadOffset, &payloadHeaderLength, packetBytes, packetLength);
|
||||||
|
*length -= payloadHeaderLength;
|
||||||
|
return payload + payloadOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -50,9 +50,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
|
|
||||||
@interface DataPathCryptoCBC : NSObject <DataPathEncrypter, DataPathDecrypter>
|
@interface DataPathCryptoCBC : NSObject <DataPathEncrypter, DataPathDecrypter>
|
||||||
|
|
||||||
@property (nonatomic, assign) uint32_t peerId;
|
|
||||||
@property (nonatomic, assign) CompressionFraming compressionFraming;
|
|
||||||
|
|
||||||
- (instancetype)initWithCrypto:(nonnull CryptoCBC *)crypto;
|
- (instancetype)initWithCrypto:(nonnull CryptoCBC *)crypto;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -266,13 +266,14 @@ const NSInteger CryptoCBCMaxHMACLength = 100;
|
|||||||
|
|
||||||
- (void)setPeerId:(uint32_t)peerId
|
- (void)setPeerId:(uint32_t)peerId
|
||||||
{
|
{
|
||||||
_peerId = peerId & 0xffffff;
|
peerId &= 0xffffff;
|
||||||
|
|
||||||
if (_peerId == PacketPeerIdDisabled) {
|
if (peerId == PacketPeerIdDisabled) {
|
||||||
self.headerLength = 1;
|
self.headerLength = 1;
|
||||||
self.setDataHeader = ^(uint8_t *to, uint8_t key) {
|
self.setDataHeader = ^(uint8_t *to, uint8_t key) {
|
||||||
PacketHeaderSet(to, PacketCodeDataV1, key);
|
PacketHeaderSet(to, PacketCodeDataV1, key);
|
||||||
};
|
};
|
||||||
|
self.checkPeerId = NULL;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
self.headerLength = 4;
|
self.headerLength = 4;
|
||||||
@ -280,76 +281,62 @@ const NSInteger CryptoCBCMaxHMACLength = 100;
|
|||||||
PacketHeaderSetDataV2(to, key, peerId);
|
PacketHeaderSetDataV2(to, key, peerId);
|
||||||
};
|
};
|
||||||
self.checkPeerId = ^BOOL(const uint8_t *ptr) {
|
self.checkPeerId = ^BOOL(const uint8_t *ptr) {
|
||||||
return (PacketHeaderGetDataV2PeerId(ptr) == self.peerId);
|
return (PacketHeaderGetDataV2PeerId(ptr) == peerId);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark DataPathEncrypter
|
#pragma mark DataPathEncrypter
|
||||||
|
|
||||||
- (void)assembleDataPacketWithPacketId:(uint32_t)packetId payload:(NSData *)payload into:(uint8_t *)dest length:(NSInteger *)length
|
- (void)assembleDataPacketWithBlock:(DataPathAssembleBlock)block packetId:(uint32_t)packetId payload:(NSData *)payload into:(uint8_t *)packetBytes length:(NSInteger *)packetLength
|
||||||
{
|
{
|
||||||
uint8_t *ptr = dest;
|
uint8_t *ptr = packetBytes;
|
||||||
*(uint32_t *)ptr = htonl(packetId);
|
*(uint32_t *)ptr = htonl(packetId);
|
||||||
ptr += sizeof(uint32_t);
|
ptr += sizeof(uint32_t);
|
||||||
*length = (int)(ptr - dest + payload.length);
|
*packetLength = (int)(ptr - packetBytes + payload.length);
|
||||||
|
if (!block) {
|
||||||
switch (self.compressionFraming) {
|
|
||||||
case CompressionFramingDisabled:
|
|
||||||
memcpy(ptr, payload.bytes, payload.length);
|
memcpy(ptr, payload.bytes, payload.length);
|
||||||
break;
|
return;
|
||||||
|
|
||||||
case CompressionFramingCompress:
|
|
||||||
memcpy(ptr, payload.bytes, payload.length);
|
|
||||||
ptr[payload.length] = *ptr;
|
|
||||||
*ptr = CompressionFramingNoCompressSwap;
|
|
||||||
*length += sizeof(uint8_t);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CompressionFramingCompLZO:
|
|
||||||
memcpy(ptr + sizeof(uint8_t), payload.bytes, payload.length);
|
|
||||||
*ptr = CompressionFramingNoCompress;
|
|
||||||
*length += sizeof(uint8_t);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSData *)encryptedDataPacketWithKey:(uint8_t)key packetId:(uint32_t)packetId payload:(const uint8_t *)payload payloadLength:(NSInteger)payloadLength error:(NSError *__autoreleasing *)error
|
NSInteger packetLengthOffset;
|
||||||
|
block(ptr, &packetLengthOffset, payload);
|
||||||
|
*packetLength += packetLengthOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (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(payloadLength, self.crypto.overheadLength);
|
const int capacity = self.headerLength + (int)safe_crypto_capacity(packetLength, self.crypto.overheadLength);
|
||||||
NSMutableData *encryptedPacket = [[NSMutableData alloc] initWithLength:capacity];
|
NSMutableData *encryptedPacket = [[NSMutableData alloc] initWithLength:capacity];
|
||||||
uint8_t *ptr = encryptedPacket.mutableBytes;
|
uint8_t *ptr = encryptedPacket.mutableBytes;
|
||||||
NSInteger encryptedPayloadLength = INT_MAX;
|
NSInteger encryptedPacketLength = INT_MAX;
|
||||||
const BOOL success = [self.crypto encryptBytes:payload
|
const BOOL success = [self.crypto encryptBytes:packetBytes
|
||||||
length:payloadLength
|
length:packetLength
|
||||||
dest:(ptr + self.headerLength) // skip header byte
|
dest:(ptr + self.headerLength) // skip header byte
|
||||||
destLength:&encryptedPayloadLength
|
destLength:&encryptedPacketLength
|
||||||
extra:NULL
|
extra:NULL
|
||||||
error:error];
|
error:error];
|
||||||
|
|
||||||
NSAssert(encryptedPayloadLength <= capacity, @"Did not allocate enough bytes for payload");
|
NSAssert(encryptedPacketLength <= capacity, @"Did not allocate enough bytes for payload");
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.setDataHeader(ptr, key);
|
self.setDataHeader(ptr, key);
|
||||||
encryptedPacket.length = self.headerLength + encryptedPayloadLength;
|
encryptedPacket.length = self.headerLength + encryptedPacketLength;
|
||||||
return encryptedPacket;
|
return encryptedPacket;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark DataPathDecrypter
|
#pragma mark DataPathDecrypter
|
||||||
|
|
||||||
- (BOOL)decryptDataPacket:(NSData *)packet into:(uint8_t *)dest length:(NSInteger *)length packetId:(nonnull uint32_t *)packetId error:(NSError *__autoreleasing *)error
|
- (BOOL)decryptDataPacket:(NSData *)packet into:(uint8_t *)packetBytes length:(NSInteger *)packetLength packetId:(uint32_t *)packetId error:(NSError *__autoreleasing *)error
|
||||||
{
|
{
|
||||||
// skip header = (code, key)
|
// skip header = (code, key)
|
||||||
const BOOL success = [self.crypto decryptBytes:(packet.bytes + self.headerLength)
|
const BOOL success = [self.crypto decryptBytes:(packet.bytes + self.headerLength)
|
||||||
length:(int)(packet.length - self.headerLength)
|
length:(int)(packet.length - self.headerLength)
|
||||||
dest:dest
|
dest:packetBytes
|
||||||
destLength:length
|
destLength:packetLength
|
||||||
extra:NULL
|
extra:NULL
|
||||||
error:error];
|
error:error];
|
||||||
if (!success) {
|
if (!success) {
|
||||||
@ -361,32 +348,24 @@ const NSInteger CryptoCBCMaxHMACLength = 100;
|
|||||||
}
|
}
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
*packetId = ntohl(*(uint32_t *)dest);
|
*packetId = ntohl(*(uint32_t *)packetBytes);
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (const uint8_t *)parsePayloadWithDataPacket:(uint8_t *)packet packetLength:(NSInteger)packetLength length:(NSInteger *)length
|
- (const uint8_t *)parsePayloadWithBlock:(DataPathParseBlock)block length:(NSInteger *)length packetBytes:(uint8_t *)packetBytes packetLength:(NSInteger)packetLength
|
||||||
{
|
{
|
||||||
uint8_t *ptr = packet;
|
uint8_t *payload = packetBytes;
|
||||||
ptr += sizeof(uint32_t); // packet id
|
payload += sizeof(uint32_t); // packet id
|
||||||
*length = packetLength - (int)(ptr - packet);
|
*length = packetLength - (int)(payload - packetBytes);
|
||||||
if (self.compressionFraming != CompressionFramingDisabled) {
|
if (!block) {
|
||||||
switch (*ptr) {
|
return payload;
|
||||||
case CompressionFramingNoCompress:
|
|
||||||
ptr += sizeof(uint8_t);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CompressionFramingNoCompressSwap:
|
|
||||||
*ptr = packet[packetLength - 1];
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
NSAssert(NO, @"Compression not supported (found %X)", *ptr);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
*length -= sizeof(uint8_t);
|
|
||||||
}
|
NSInteger payloadOffset;
|
||||||
return ptr;
|
NSInteger payloadHeaderLength;
|
||||||
|
block(payload, &payloadOffset, &payloadHeaderLength, packetBytes, packetLength);
|
||||||
|
*length -= payloadHeaderLength;
|
||||||
|
return payload + payloadOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -64,6 +64,9 @@
|
|||||||
@property (nonatomic, assign) int decBufferCapacity;
|
@property (nonatomic, assign) int decBufferCapacity;
|
||||||
@property (nonatomic, strong) ReplayProtector *inReplay;
|
@property (nonatomic, strong) ReplayProtector *inReplay;
|
||||||
|
|
||||||
|
@property (nonatomic, copy) DataPathAssembleBlock assemblePayloadBlock;
|
||||||
|
@property (nonatomic, copy) DataPathParseBlock parsePayloadBlock;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation DataPath
|
@implementation DataPath
|
||||||
@ -105,6 +108,8 @@
|
|||||||
if (usesReplayProtection) {
|
if (usesReplayProtection) {
|
||||||
self.inReplay = [[ReplayProtector alloc] init];
|
self.inReplay = [[ReplayProtector alloc] init];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.compressionFraming = CompressionFramingDisabled;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@ -156,24 +161,60 @@
|
|||||||
NSAssert(self.encrypter, @"Setting peer-id to nil encrypter");
|
NSAssert(self.encrypter, @"Setting peer-id to nil encrypter");
|
||||||
NSAssert(self.decrypter, @"Setting peer-id to nil decrypter");
|
NSAssert(self.decrypter, @"Setting peer-id to nil decrypter");
|
||||||
|
|
||||||
self.encrypter.peerId = peerId;
|
[self.encrypter setPeerId:peerId];
|
||||||
self.decrypter.peerId = peerId;
|
[self.decrypter setPeerId:peerId];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setCompressionFraming:(CompressionFraming)compressionFraming
|
- (void)setCompressionFraming:(CompressionFraming)compressionFraming
|
||||||
{
|
{
|
||||||
NSAssert(self.encrypter, @"Setting compressionFraming to nil encrypter");
|
switch (compressionFraming) {
|
||||||
NSAssert(self.decrypter, @"Setting compressionFraming to nil decrypter");
|
case CompressionFramingDisabled: {
|
||||||
|
self.assemblePayloadBlock = ^(uint8_t * _Nonnull packetDest, NSInteger * _Nonnull packetLengthOffset, NSData * _Nonnull payload) {
|
||||||
self.encrypter.compressionFraming = compressionFraming;
|
memcpy(packetDest, payload.bytes, payload.length);
|
||||||
self.decrypter.compressionFraming = compressionFraming;
|
*packetLengthOffset = 0;
|
||||||
|
};
|
||||||
|
self.parsePayloadBlock = ^(uint8_t * _Nonnull payload, NSInteger *payloadOffset, NSInteger * _Nonnull headerLength, const uint8_t * _Nonnull packet, NSInteger packetLength) {
|
||||||
|
*payloadOffset = 0;
|
||||||
|
*headerLength = 0;
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CompressionFramingCompress: {
|
||||||
|
self.assemblePayloadBlock = ^(uint8_t * _Nonnull packetDest, NSInteger * _Nonnull packetLengthOffset, NSData * _Nonnull payload) {
|
||||||
|
memcpy(packetDest, payload.bytes, payload.length);
|
||||||
|
packetDest[payload.length] = packetDest[0];
|
||||||
|
packetDest[0] = CompressionFramingNoCompressSwap;
|
||||||
|
*packetLengthOffset = 1;
|
||||||
|
};
|
||||||
|
self.parsePayloadBlock = ^(uint8_t * _Nonnull payload, NSInteger *payloadOffset, NSInteger * _Nonnull headerLength, const uint8_t * _Nonnull packet, NSInteger packetLength) {
|
||||||
|
NSCAssert(payload[0] == CompressionFramingNoCompressSwap, @"Expected NO_COMPRESS_SWAP (found %X != %X)", payload[0], CompressionFramingNoCompressSwap);
|
||||||
|
payload[0] = packet[packetLength - 1];
|
||||||
|
*payloadOffset = 0;
|
||||||
|
*headerLength = 1;
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CompressionFramingCompLZO: {
|
||||||
|
self.assemblePayloadBlock = ^(uint8_t * _Nonnull packetDest, NSInteger * _Nonnull packetLengthOffset, NSData * _Nonnull payload) {
|
||||||
|
memcpy(packetDest + 1, payload.bytes, payload.length);
|
||||||
|
packetDest[0] = CompressionFramingNoCompress;
|
||||||
|
*packetLengthOffset = 1;
|
||||||
|
};
|
||||||
|
self.parsePayloadBlock = ^(uint8_t * _Nonnull payload, NSInteger *payloadOffset, NSInteger * _Nonnull headerLength, const uint8_t * _Nonnull packet, NSInteger packetLength) {
|
||||||
|
NSCAssert(payload[0] == CompressionFramingNoCompress, @"Expected NO_COMPRESS (found %X != %X)", payload[0], CompressionFramingNoCompress);
|
||||||
|
*payloadOffset = 1;
|
||||||
|
*headerLength = 1;
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark DataPath
|
#pragma mark DataPath
|
||||||
|
|
||||||
- (NSArray<NSData *> *)encryptPackets:(NSArray<NSData *> *)packets key:(uint8_t)key error:(NSError *__autoreleasing *)error
|
- (NSArray<NSData *> *)encryptPackets:(NSArray<NSData *> *)packets key:(uint8_t)key error:(NSError *__autoreleasing *)error
|
||||||
{
|
{
|
||||||
NSAssert(self.encrypter.peerId == self.decrypter.peerId, @"Peer-id mismatch in DataPath encrypter/decrypter");
|
// NSAssert(self.encrypter.peerId == self.decrypter.peerId, @"Peer-id mismatch in DataPath encrypter/decrypter");
|
||||||
|
|
||||||
if (self.outPacketId > self.maxPacketId) {
|
if (self.outPacketId > self.maxPacketId) {
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -184,53 +225,53 @@
|
|||||||
|
|
||||||
[self.outPackets removeAllObjects];
|
[self.outPackets removeAllObjects];
|
||||||
|
|
||||||
for (NSData *raw in packets) {
|
for (NSData *payload in packets) {
|
||||||
self.outPacketId += 1;
|
self.outPacketId += 1;
|
||||||
|
|
||||||
// may resize encBuffer to hold encrypted payload
|
// may resize encBuffer to hold encrypted payload
|
||||||
[self adjustEncBufferToPacketSize:(int)raw.length];
|
[self adjustEncBufferToPacketSize:(int)payload.length];
|
||||||
|
|
||||||
uint8_t *payload = self.encBufferAligned;
|
uint8_t *dataPacketBytes = self.encBufferAligned;
|
||||||
NSInteger payloadLength;
|
NSInteger dataPacketLength;
|
||||||
[self.encrypter assembleDataPacketWithPacketId:self.outPacketId
|
[self.encrypter assembleDataPacketWithBlock:self.assemblePayloadBlock
|
||||||
payload:raw
|
|
||||||
into:payload
|
|
||||||
length:&payloadLength];
|
|
||||||
MSSFix(payload, payloadLength);
|
|
||||||
|
|
||||||
NSData *encryptedPacket = [self.encrypter encryptedDataPacketWithKey:key
|
|
||||||
packetId:self.outPacketId
|
packetId:self.outPacketId
|
||||||
payload:payload
|
payload:payload
|
||||||
payloadLength:payloadLength
|
into:dataPacketBytes
|
||||||
|
length:&dataPacketLength];
|
||||||
|
MSSFix(dataPacketBytes, dataPacketLength);
|
||||||
|
|
||||||
|
NSData *encryptedDataPacket = [self.encrypter encryptedDataPacketWithKey:key
|
||||||
|
packetId:self.outPacketId
|
||||||
|
packetBytes:dataPacketBytes
|
||||||
|
packetLength:dataPacketLength
|
||||||
error:error];
|
error:error];
|
||||||
if (!encryptedPacket) {
|
if (!encryptedDataPacket) {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self.outPackets addObject:encryptedPacket];
|
[self.outPackets addObject:encryptedDataPacket];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.outPackets;
|
return self.outPackets;
|
||||||
}
|
}
|
||||||
|
|
||||||
//- (NSArray<NSData *> *)decryptPackets:(NSArray<NSData *> *)packets error:(NSError *__autoreleasing *)error
|
|
||||||
- (NSArray<NSData *> *)decryptPackets:(NSArray<NSData *> *)packets keepAlive:(bool *)keepAlive error:(NSError *__autoreleasing *)error
|
- (NSArray<NSData *> *)decryptPackets:(NSArray<NSData *> *)packets keepAlive:(bool *)keepAlive error:(NSError *__autoreleasing *)error
|
||||||
{
|
{
|
||||||
NSAssert(self.encrypter.peerId == self.decrypter.peerId, @"Peer-id mismatch in DataPath encrypter/decrypter");
|
// NSAssert(self.encrypter.peerId == self.decrypter.peerId, @"Peer-id mismatch in DataPath encrypter/decrypter");
|
||||||
|
|
||||||
[self.inPackets removeAllObjects];
|
[self.inPackets removeAllObjects];
|
||||||
|
|
||||||
for (NSData *encryptedPacket in packets) {
|
for (NSData *encryptedDataPacket in packets) {
|
||||||
|
|
||||||
// may resize decBuffer to encryptedPacket.length
|
// may resize decBuffer to encryptedPacket.length
|
||||||
[self adjustDecBufferToPacketSize:(int)encryptedPacket.length];
|
[self adjustDecBufferToPacketSize:(int)encryptedDataPacket.length];
|
||||||
|
|
||||||
uint8_t *packet = self.decBufferAligned;
|
uint8_t *dataPacketBytes = self.decBufferAligned;
|
||||||
NSInteger packetLength = INT_MAX;
|
NSInteger dataPacketLength = INT_MAX;
|
||||||
uint32_t packetId;
|
uint32_t packetId;
|
||||||
const BOOL success = [self.decrypter decryptDataPacket:encryptedPacket
|
const BOOL success = [self.decrypter decryptDataPacket:encryptedDataPacket
|
||||||
into:packet
|
into:dataPacketBytes
|
||||||
length:&packetLength
|
length:&dataPacketLength
|
||||||
packetId:&packetId
|
packetId:&packetId
|
||||||
error:error];
|
error:error];
|
||||||
if (!success) {
|
if (!success) {
|
||||||
@ -247,21 +288,22 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
NSInteger payloadLength;
|
NSInteger payloadLength;
|
||||||
const uint8_t *payload = [self.decrypter parsePayloadWithDataPacket:packet
|
const uint8_t *payloadBytes = [self.decrypter parsePayloadWithBlock:self.parsePayloadBlock
|
||||||
packetLength:packetLength
|
length:&payloadLength
|
||||||
length:&payloadLength];
|
packetBytes:dataPacketBytes
|
||||||
|
packetLength:dataPacketLength];
|
||||||
|
|
||||||
if ((payloadLength == sizeof(DataPacketPingData)) && !memcmp(payload, DataPacketPingData, payloadLength)) {
|
if ((payloadLength == sizeof(DataPacketPingData)) && !memcmp(payloadBytes, DataPacketPingData, payloadLength)) {
|
||||||
if (keepAlive) {
|
if (keepAlive) {
|
||||||
*keepAlive = true;
|
*keepAlive = true;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// MSSFix(payload, payloadLength);
|
// MSSFix(payloadBytes, payloadLength);
|
||||||
|
|
||||||
NSData *raw = [[NSData alloc] initWithBytes:payload length:payloadLength];
|
NSData *payload = [[NSData alloc] initWithBytes:payloadBytes length:payloadLength];
|
||||||
[self.inPackets addObject:raw];
|
[self.inPackets addObject:payload];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.inPackets;
|
return self.inPackets;
|
||||||
|
@ -36,26 +36,26 @@
|
|||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
typedef void (^DataPathAssembleBlock)(uint8_t *_Nonnull packetDest, NSInteger *_Nonnull packetLengthOffset, NSData *_Nonnull payload);
|
||||||
|
typedef void (^DataPathParseBlock)(uint8_t *_Nonnull payload, NSInteger *_Nonnull payloadOffset, NSInteger *_Nonnull headerLength, const uint8_t *_Nonnull packet, NSInteger packetLength);
|
||||||
|
|
||||||
@protocol DataPathChannel
|
@protocol DataPathChannel
|
||||||
|
|
||||||
- (int)overheadLength;
|
- (int)overheadLength;
|
||||||
- (uint32_t)peerId;
|
|
||||||
- (void)setPeerId:(uint32_t)peerId;
|
- (void)setPeerId:(uint32_t)peerId;
|
||||||
- (CompressionFraming)compressionFraming;
|
|
||||||
- (void)setCompressionFraming:(CompressionFraming)compressionFraming;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@protocol DataPathEncrypter <DataPathChannel>
|
@protocol DataPathEncrypter <DataPathChannel>
|
||||||
|
|
||||||
- (void)assembleDataPacketWithPacketId:(uint32_t)packetId payload:(NSData *)payload into:(nonnull uint8_t *)dest length:(nonnull NSInteger *)length;
|
- (void)assembleDataPacketWithBlock:(DataPathAssembleBlock)block packetId:(uint32_t)packetId payload:(NSData *)payload into:(nonnull uint8_t *)packetBytes length:(nonnull NSInteger *)packetLength;
|
||||||
- (NSData *)encryptedDataPacketWithKey:(uint8_t)key packetId:(uint32_t)packetId payload:(const uint8_t *)payload payloadLength:(NSInteger)payloadLength error:(NSError **)error;
|
- (NSData *)encryptedDataPacketWithKey:(uint8_t)key packetId:(uint32_t)packetId packetBytes:(const uint8_t *)packetBytes packetLength:(NSInteger)packetLength error:(NSError **)error;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@protocol DataPathDecrypter <DataPathChannel>
|
@protocol DataPathDecrypter <DataPathChannel>
|
||||||
|
|
||||||
- (BOOL)decryptDataPacket:(nonnull NSData *)packet into:(nonnull uint8_t *)dest length:(nonnull NSInteger *)length packetId:(nonnull uint32_t *)packetId error:(NSError **)error;
|
- (BOOL)decryptDataPacket:(nonnull NSData *)packet into:(nonnull uint8_t *)packetBytes length:(nonnull NSInteger *)packetLength packetId:(nonnull uint32_t *)packetId error:(NSError **)error;
|
||||||
- (nonnull const uint8_t *)parsePayloadWithDataPacket:(nonnull uint8_t *)packet packetLength:(NSInteger)packetLength length:(nonnull NSInteger *)length;
|
- (nonnull const uint8_t *)parsePayloadWithBlock:(DataPathParseBlock)block length:(nonnull NSInteger *)length packetBytes:(nonnull uint8_t *)packetBytes packetLength:(NSInteger)packetLength;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -40,13 +40,15 @@ import XCTest
|
|||||||
@testable import __TunnelKitNative
|
@testable import __TunnelKitNative
|
||||||
|
|
||||||
class DataPathEncryptionTests: XCTestCase {
|
class DataPathEncryptionTests: XCTestCase {
|
||||||
private var cipherKey: ZeroingData!
|
private let cipherKey = try! SecureRandom.safeData(length: 32)
|
||||||
|
|
||||||
private var hmacKey: ZeroingData!
|
private let hmacKey = try! SecureRandom.safeData(length: 32)
|
||||||
|
|
||||||
|
private var enc: DataPathEncrypter!
|
||||||
|
|
||||||
|
private var dec: DataPathDecrypter!
|
||||||
|
|
||||||
override func setUp() {
|
override func setUp() {
|
||||||
cipherKey = try! SecureRandom.safeData(length: 32)
|
|
||||||
hmacKey = try! SecureRandom.safeData(length: 32)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDown() {
|
override func tearDown() {
|
||||||
@ -54,53 +56,83 @@ class DataPathEncryptionTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testCBC() {
|
func testCBC() {
|
||||||
privateTestDataPath(cipher: "aes-128-cbc", digest: "sha256", peerId: nil)
|
prepareBox(cipher: "aes-128-cbc", digest: "sha256")
|
||||||
|
privateTestDataPathHigh(peerId: nil)
|
||||||
|
privateTestDataPathLow(peerId: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testFloatingCBC() {
|
func testFloatingCBC() {
|
||||||
privateTestDataPath(cipher: "aes-128-cbc", digest: "sha256", peerId: 0x64385837)
|
prepareBox(cipher: "aes-128-cbc", digest: "sha256")
|
||||||
|
privateTestDataPathHigh(peerId: 0x64385837)
|
||||||
|
privateTestDataPathLow(peerId: 0x64385837)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testGCM() {
|
func testGCM() {
|
||||||
privateTestDataPath(cipher: "aes-256-gcm", digest: nil, peerId: nil)
|
prepareBox(cipher: "aes-256-gcm", digest: nil)
|
||||||
|
privateTestDataPathHigh(peerId: nil)
|
||||||
|
privateTestDataPathLow(peerId: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testFloatingGCM() {
|
func testFloatingGCM() {
|
||||||
privateTestDataPath(cipher: "aes-256-gcm", digest: nil, peerId: 0x64385837)
|
prepareBox(cipher: "aes-256-gcm", digest: nil)
|
||||||
|
privateTestDataPathHigh(peerId: 0x64385837)
|
||||||
|
privateTestDataPathLow(peerId: 0x64385837)
|
||||||
}
|
}
|
||||||
|
|
||||||
func privateTestDataPath(cipher: String, digest: String?, peerId: UInt32?) {
|
func prepareBox(cipher: String, digest: String?) {
|
||||||
let box = CryptoBox(cipherAlgorithm: cipher, digestAlgorithm: digest)
|
let box = CryptoBox(cipherAlgorithm: cipher, digestAlgorithm: digest)
|
||||||
try! box.configure(withCipherEncKey: cipherKey, cipherDecKey: cipherKey, hmacEncKey: hmacKey, hmacDecKey: hmacKey)
|
try! box.configure(withCipherEncKey: cipherKey, cipherDecKey: cipherKey, hmacEncKey: hmacKey, hmacDecKey: hmacKey)
|
||||||
let enc = box.encrypter().dataPathEncrypter()
|
enc = box.encrypter().dataPathEncrypter()
|
||||||
let dec = box.decrypter().dataPathDecrypter()
|
dec = box.decrypter().dataPathDecrypter()
|
||||||
|
}
|
||||||
|
|
||||||
|
func privateTestDataPathHigh(peerId: UInt32?) {
|
||||||
|
let path = DataPath(encrypter: enc, decrypter: dec, maxPackets: 1000, usesReplayProtection: false)
|
||||||
|
path.setCompressionFraming(.disabled)
|
||||||
|
|
||||||
if let peerId = peerId {
|
if let peerId = peerId {
|
||||||
enc.setPeerId(peerId)
|
enc.setPeerId(peerId)
|
||||||
dec.setPeerId(peerId)
|
dec.setPeerId(peerId)
|
||||||
XCTAssertEqual(enc.peerId(), peerId & 0xffffff)
|
// XCTAssertEqual(enc.peerId(), peerId & 0xffffff)
|
||||||
XCTAssertEqual(dec.peerId(), peerId & 0xffffff)
|
// XCTAssertEqual(dec.peerId(), peerId & 0xffffff)
|
||||||
}
|
}
|
||||||
// enc.setLZOFraming(true)
|
|
||||||
// dec.setLZOFraming(true)
|
|
||||||
|
|
||||||
let payload = Data(hex: "00112233445566778899")
|
let expectedPayload = Data(hex: "00112233445566778899")
|
||||||
let packetId: UInt32 = 0x56341200
|
|
||||||
let key: UInt8 = 4
|
let key: UInt8 = 4
|
||||||
var encryptedPayload: [UInt8] = [UInt8](repeating: 0, count: 1000)
|
|
||||||
var encryptedPayloadLength: Int = 0
|
|
||||||
enc.assembleDataPacket(withPacketId: packetId, payload: payload, into: &encryptedPayload, length: &encryptedPayloadLength)
|
|
||||||
let encrypted = try! enc.encryptedDataPacket(withKey: key, packetId: packetId, payload: encryptedPayload, payloadLength: encryptedPayloadLength)
|
|
||||||
|
|
||||||
var decrypted: [UInt8] = [UInt8](repeating: 0, count: 1000)
|
let encrypted = try! path.encryptPackets([expectedPayload], key: key)
|
||||||
|
let decrypted = try! path.decryptPackets(encrypted, keepAlive: nil)
|
||||||
|
let payload = decrypted.first!
|
||||||
|
|
||||||
|
XCTAssertEqual(payload, expectedPayload)
|
||||||
|
}
|
||||||
|
|
||||||
|
func privateTestDataPathLow(peerId: UInt32?) {
|
||||||
|
if let peerId = peerId {
|
||||||
|
enc.setPeerId(peerId)
|
||||||
|
dec.setPeerId(peerId)
|
||||||
|
// XCTAssertEqual(enc.peerId(), peerId & 0xffffff)
|
||||||
|
// XCTAssertEqual(dec.peerId(), peerId & 0xffffff)
|
||||||
|
}
|
||||||
|
|
||||||
|
let expectedPayload = Data(hex: "00112233445566778899")
|
||||||
|
let expectedPacketId: UInt32 = 0x56341200
|
||||||
|
let key: UInt8 = 4
|
||||||
|
|
||||||
|
var encryptedPacketBytes: [UInt8] = [UInt8](repeating: 0, count: 1000)
|
||||||
|
var encryptedPacketLength: Int = 0
|
||||||
|
enc.assembleDataPacket(nil, packetId: expectedPacketId, payload: expectedPayload, into: &encryptedPacketBytes, length: &encryptedPacketLength)
|
||||||
|
let encrypted = try! enc.encryptedDataPacket(withKey: key, packetId: expectedPacketId, packetBytes: encryptedPacketBytes, packetLength: encryptedPacketLength)
|
||||||
|
|
||||||
|
var decryptedBytes: [UInt8] = [UInt8](repeating: 0, count: 1000)
|
||||||
var decryptedLength: Int = 0
|
var decryptedLength: Int = 0
|
||||||
var decryptedPacketId: UInt32 = 0
|
var packetId: UInt32 = 0
|
||||||
var decryptedPayloadLength: Int = 0
|
var payloadLength: Int = 0
|
||||||
try! dec.decryptDataPacket(encrypted, into: &decrypted, length: &decryptedLength, packetId: &decryptedPacketId)
|
try! dec.decryptDataPacket(encrypted, into: &decryptedBytes, length: &decryptedLength, packetId: &packetId)
|
||||||
let decryptedPtr = dec.parsePayload(withDataPacket: &decrypted, packetLength: decryptedLength, length: &decryptedPayloadLength)
|
let payloadBytes = dec.parsePayload(nil, length: &payloadLength, packetBytes: &decryptedBytes, packetLength: decryptedLength)
|
||||||
let decryptedPayload = Data(bytes: decryptedPtr, count: decryptedPayloadLength)
|
let payload = Data(bytes: payloadBytes, count: payloadLength)
|
||||||
|
|
||||||
XCTAssertEqual(payload, decryptedPayload)
|
XCTAssertEqual(payload, expectedPayload)
|
||||||
XCTAssertEqual(packetId, decryptedPacketId)
|
XCTAssertEqual(packetId, expectedPacketId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user