Merge branch 'crypto-with-optional-cipher'

This commit is contained in:
Davide De Rosa 2018-09-12 15:39:08 +02:00
commit 03cf900996
14 changed files with 238 additions and 111 deletions

View File

@ -45,13 +45,13 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, assign) int extraLength;
- (instancetype)initWithCipherName:(nonnull NSString *)cipherName;
- (instancetype)initWithCipherName:(NSString *)cipherName;
@end
@interface DataPathCryptoAEAD : NSObject <DataPathEncrypter, DataPathDecrypter>
- (instancetype)initWithCrypto:(nonnull CryptoAEAD *)crypto;
- (instancetype)initWithCrypto:(CryptoAEAD *)crypto;
@end

View File

@ -97,11 +97,17 @@ const NSInteger CryptoAEADTagLength = 16;
self.cipher = NULL;
}
- (int)digestLength
{
return 0;
}
#pragma mark Encrypter
- (void)configureEncryptionWithCipherKey:(ZeroingData *)cipherKey hmacKey:(ZeroingData *)hmacKey
{
NSParameterAssert(cipherKey.count >= self.cipherKeyLength);
NSParameterAssert(hmacKey);
EVP_CIPHER_CTX_reset(self.cipherCtxEnc);
EVP_CipherInit(self.cipherCtxEnc, self.cipher, cipherKey.bytes, NULL, 1);
@ -109,7 +115,7 @@ const NSInteger CryptoAEADTagLength = 16;
[self prepareIV:self.cipherIVEnc withHMACKey:hmacKey];
}
- (NSData *)encryptData:(NSData *)data offset:(NSInteger)offset extra:(nonnull const uint8_t *)extra error:(NSError *__autoreleasing *)error
- (NSData *)encryptData:(NSData *)data offset:(NSInteger)offset extra:(const uint8_t *)extra error:(NSError *__autoreleasing *)error
{
NSParameterAssert(data);
NSParameterAssert(extra);
@ -127,7 +133,7 @@ const NSInteger CryptoAEADTagLength = 16;
return dest;
}
- (BOOL)encryptBytes:(const uint8_t *)bytes length:(NSInteger)length dest:(uint8_t *)dest destLength:(NSInteger *)destLength extra:(nonnull const uint8_t *)extra error:(NSError *__autoreleasing *)error
- (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);
@ -165,14 +171,15 @@ const NSInteger CryptoAEADTagLength = 16;
- (void)configureDecryptionWithCipherKey:(ZeroingData *)cipherKey hmacKey:(ZeroingData *)hmacKey
{
NSParameterAssert(cipherKey.count >= self.cipherKeyLength);
NSParameterAssert(hmacKey);
EVP_CIPHER_CTX_reset(self.cipherCtxDec);
EVP_CipherInit(self.cipherCtxDec, self.cipher, cipherKey.bytes, NULL, 0);
[self prepareIV:self.cipherIVDec withHMACKey:hmacKey];
}
- (NSData *)decryptData:(NSData *)data offset:(NSInteger)offset extra:(nonnull const uint8_t *)extra error:(NSError *__autoreleasing *)error
- (NSData *)decryptData:(NSData *)data offset:(NSInteger)offset extra:(const uint8_t *)extra error:(NSError *__autoreleasing *)error
{
NSParameterAssert(data);
NSParameterAssert(extra);
@ -190,7 +197,7 @@ const NSInteger CryptoAEADTagLength = 16;
return dest;
}
- (BOOL)decryptBytes:(const uint8_t *)bytes length:(NSInteger)length dest:(uint8_t *)dest destLength:(NSInteger *)destLength extra:(nonnull const uint8_t *)extra error:(NSError *__autoreleasing *)error
- (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);
@ -218,6 +225,18 @@ 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");
return NO;
}
- (id<DataPathDecrypter>)dataPathDecrypter
{
return [[DataPathCryptoAEAD alloc] initWithCrypto:self];

View File

@ -38,34 +38,40 @@
#import "ZeroingData.h"
NS_ASSUME_NONNULL_BEGIN
@protocol Encrypter;
@protocol Decrypter;
@interface CryptoBox : NSObject
+ (BOOL)preparePRNGWithSeed:(nonnull const uint8_t *)seed length:(NSInteger)length;
+ (BOOL)preparePRNGWithSeed:(const uint8_t *)seed length:(NSInteger)length;
- (nonnull instancetype)initWithCipherAlgorithm:(nonnull NSString *)cipherAlgorithm
- (instancetype)initWithCipherAlgorithm:(nullable NSString *)cipherAlgorithm
digestAlgorithm:(nullable NSString *)digestAlgorithm;
- (BOOL)configureWithCipherEncKey:(nonnull ZeroingData *)cipherEncKey
cipherDecKey:(nonnull ZeroingData *)cipherDecKey
hmacEncKey:(nonnull ZeroingData *)hmacEncKey
hmacDecKey:(nonnull ZeroingData *)hmacDecKey
- (BOOL)configureWithCipherEncKey:(nullable ZeroingData *)cipherEncKey
cipherDecKey:(nullable ZeroingData *)cipherDecKey
hmacEncKey:(nullable ZeroingData *)hmacEncKey
hmacDecKey:(nullable ZeroingData *)hmacDecKey
error:(NSError **)error;
// WARNING: hmac must be able to hold HMAC result
+ (BOOL)hmacWithDigestName:(nonnull NSString *)digestName
secret:(nonnull const uint8_t *)secret
+ (BOOL)hmacWithDigestName:(NSString *)digestName
secret:(const uint8_t *)secret
secretLength:(NSInteger)secretLength
data:(nonnull const uint8_t *)data
data:(const uint8_t *)data
dataLength:(NSInteger)dataLength
hmac:(nonnull uint8_t *)hmac
hmacLength:(nonnull NSInteger *)hmacLength
hmac:(uint8_t *)hmac
hmacLength:(NSInteger *)hmacLength
error:(NSError **)error;
// encrypt/decrypt are mutually thread-safe
- (nonnull id<Encrypter>)encrypter;
- (nonnull id<Decrypter>)decrypter;
- (id<Encrypter>)encrypter;
- (id<Decrypter>)decrypter;
- (NSInteger)digestLength;
@end
NS_ASSUME_NONNULL_END

View File

@ -50,6 +50,7 @@
@property (nonatomic, strong) NSString *cipherAlgorithm;
@property (nonatomic, strong) NSString *digestAlgorithm;
@property (nonatomic, assign) NSInteger digestLength;
@property (nonatomic, strong) id<Encrypter> encrypter;
@property (nonatomic, strong) id<Decrypter> decrypter;
@ -75,8 +76,7 @@
- (instancetype)initWithCipherAlgorithm:(NSString *)cipherAlgorithm digestAlgorithm:(NSString *)digestAlgorithm
{
NSParameterAssert(cipherAlgorithm);
// NSParameterAssert(digestAlgorithm);
NSParameterAssert(cipherAlgorithm || digestAlgorithm);
if ((self = [super init])) {
self.cipherAlgorithm = [cipherAlgorithm lowercaseString];
@ -98,39 +98,45 @@
hmacDecKey:(ZeroingData *)hmacDecKey
error:(NSError *__autoreleasing *)error
{
NSParameterAssert(cipherEncKey);
NSParameterAssert(cipherDecKey);
NSParameterAssert(hmacEncKey);
NSParameterAssert(hmacDecKey);
NSParameterAssert((cipherEncKey && cipherDecKey) || (hmacEncKey && hmacDecKey));
if ([self.cipherAlgorithm hasSuffix:@"-cbc"]) {
if (!self.digestAlgorithm) {
if (self.cipherAlgorithm) {
if ([self.cipherAlgorithm hasSuffix:@"-cbc"]) {
if (!self.digestAlgorithm) {
if (error) {
*error = TunnelKitErrorWithCode(TunnelKitErrorCodeCryptoBoxAlgorithm);
}
return NO;
}
CryptoCBC *cbc = [[CryptoCBC alloc] initWithCipherName:self.cipherAlgorithm digestName:self.digestAlgorithm];
self.encrypter = cbc;
self.decrypter = cbc;
}
else if ([self.cipherAlgorithm hasSuffix:@"-gcm"]) {
CryptoAEAD *gcm = [[CryptoAEAD alloc] initWithCipherName:self.cipherAlgorithm];
self.encrypter = gcm;
self.decrypter = gcm;
}
// not supported
else {
if (error) {
*error = TunnelKitErrorWithCode(TunnelKitErrorCodeCryptoBoxAlgorithm);
}
return NO;
}
CryptoCBC *cbc = [[CryptoCBC alloc] initWithCipherName:self.cipherAlgorithm
digestName:self.digestAlgorithm];
}
else {
CryptoCBC *cbc = [[CryptoCBC alloc] initWithCipherName:nil digestName:self.digestAlgorithm];
self.encrypter = cbc;
self.decrypter = cbc;
}
else if ([self.cipherAlgorithm hasSuffix:@"-gcm"]) {
CryptoAEAD *gcm = [[CryptoAEAD alloc] initWithCipherName:self.cipherAlgorithm];
self.encrypter = gcm;
self.decrypter = gcm;
}
// not supported
else {
if (error) {
*error = TunnelKitErrorWithCode(TunnelKitErrorCodeCryptoBoxAlgorithm);
}
return NO;
}
[self.encrypter configureEncryptionWithCipherKey:cipherEncKey hmacKey:hmacEncKey];
[self.decrypter configureDecryptionWithCipherKey:cipherDecKey hmacKey:hmacDecKey];
NSAssert(self.encrypter.digestLength == self.decrypter.digestLength, @"Digest length mismatch in encrypter/decrypter");
self.digestLength = self.encrypter.digestLength;
return YES;
}

View File

@ -43,14 +43,13 @@ NS_ASSUME_NONNULL_BEGIN
@interface CryptoCBC : NSObject <Encrypter, Decrypter>
- (instancetype)initWithCipherName:(nonnull NSString *)cipherName
digestName:(nonnull NSString *)digestName;
- (instancetype)initWithCipherName:(nullable NSString *)cipherName digestName:(NSString *)digestName;
@end
@interface DataPathCryptoCBC : NSObject <DataPathEncrypter, DataPathDecrypter>
- (instancetype)initWithCrypto:(nonnull CryptoCBC *)crypto;
- (instancetype)initWithCrypto:(CryptoCBC *)crypto;
@end

View File

@ -52,6 +52,7 @@ const NSInteger CryptoCBCMaxHMACLength = 100;
@property (nonatomic, unsafe_unretained) const EVP_MD *digest;
@property (nonatomic, assign) int cipherKeyLength;
@property (nonatomic, assign) int cipherIVLength;
@property (nonatomic, assign) int hmacKeyLength;
@property (nonatomic, assign) int digestLength;
@property (nonatomic, assign) int overheadLength;
@ -67,22 +68,31 @@ const NSInteger CryptoCBCMaxHMACLength = 100;
- (instancetype)initWithCipherName:(NSString *)cipherName digestName:(NSString *)digestName
{
NSParameterAssert([[cipherName uppercaseString] hasSuffix:@"CBC"]);
NSParameterAssert(!cipherName || [[cipherName uppercaseString] hasSuffix:@"CBC"]);
NSParameterAssert(digestName);
self = [super init];
if (self) {
self.cipher = EVP_get_cipherbyname([cipherName cStringUsingEncoding:NSASCIIStringEncoding]);
NSAssert(self.cipher, @"Unknown cipher '%@'", cipherName);
if (cipherName) {
self.cipher = EVP_get_cipherbyname([cipherName cStringUsingEncoding:NSASCIIStringEncoding]);
NSAssert(self.cipher, @"Unknown cipher '%@'", cipherName);
}
self.digest = EVP_get_digestbyname([digestName cStringUsingEncoding:NSASCIIStringEncoding]);
NSAssert(self.digest, @"Unknown digest '%@'", digestName);
self.cipherKeyLength = EVP_CIPHER_key_length(self.cipher);
self.cipherIVLength = EVP_CIPHER_iv_length(self.cipher);
if (cipherName) {
self.cipherKeyLength = EVP_CIPHER_key_length(self.cipher);
self.cipherIVLength = EVP_CIPHER_iv_length(self.cipher);
}
// 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;
self.cipherCtxEnc = EVP_CIPHER_CTX_new();
self.cipherCtxDec = EVP_CIPHER_CTX_new();
if (cipherName) {
self.cipherCtxEnc = EVP_CIPHER_CTX_new();
self.cipherCtxDec = EVP_CIPHER_CTX_new();
}
self.hmacCtxEnc = HMAC_CTX_new();
self.hmacCtxDec = HMAC_CTX_new();
self.bufferDecHMAC = allocate_safely(CryptoCBCMaxHMACLength);
@ -92,8 +102,10 @@ const NSInteger CryptoCBCMaxHMACLength = 100;
- (void)dealloc
{
EVP_CIPHER_CTX_free(self.cipherCtxEnc);
EVP_CIPHER_CTX_free(self.cipherCtxDec);
if (self.cipher) {
EVP_CIPHER_CTX_free(self.cipherCtxEnc);
EVP_CIPHER_CTX_free(self.cipherCtxDec);
}
HMAC_CTX_free(self.hmacCtxEnc);
HMAC_CTX_free(self.hmacCtxDec);
bzero(self.bufferDecHMAC, CryptoCBCMaxHMACLength);
@ -112,16 +124,21 @@ const NSInteger CryptoCBCMaxHMACLength = 100;
- (void)configureEncryptionWithCipherKey:(ZeroingData *)cipherKey hmacKey:(ZeroingData *)hmacKey
{
NSParameterAssert(cipherKey.count >= self.cipherKeyLength);
NSParameterAssert(hmacKey);
NSParameterAssert(hmacKey.count >= self.hmacKeyLength);
EVP_CIPHER_CTX_reset(self.cipherCtxEnc);
EVP_CipherInit(self.cipherCtxEnc, self.cipher, cipherKey.bytes, NULL, 1);
if (self.cipher) {
NSParameterAssert(cipherKey.count >= self.cipherKeyLength);
EVP_CIPHER_CTX_reset(self.cipherCtxEnc);
EVP_CipherInit(self.cipherCtxEnc, self.cipher, cipherKey.bytes, NULL, 1);
}
HMAC_CTX_reset(self.hmacCtxEnc);
HMAC_Init_ex(self.hmacCtxEnc, hmacKey.bytes, self.digestLength, self.digest, NULL);
HMAC_Init_ex(self.hmacCtxEnc, hmacKey.bytes, self.hmacKeyLength, self.digest, NULL);
}
- (NSData *)encryptData:(NSData *)data offset:(NSInteger)offset extra:(nonnull const uint8_t *)extra error:(NSError *__autoreleasing *)error
- (NSData *)encryptData:(NSData *)data offset:(NSInteger)offset extra:(const uint8_t *)extra error:(NSError *__autoreleasing *)error
{
NSParameterAssert(data);
@ -138,24 +155,32 @@ const NSInteger CryptoCBCMaxHMACLength = 100;
return dest;
}
- (BOOL)encryptBytes:(const uint8_t *)bytes length:(NSInteger)length dest:(uint8_t *)dest destLength:(NSInteger *)destLength extra:(nonnull const uint8_t *)extra error:(NSError *__autoreleasing *)error
- (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;
uint8_t *outEncrypted = dest + self.digestLength + self.cipherIVLength;
int l1 = 0, l2 = 0;
unsigned int l3 = 0;
int code = 1;
if (RAND_bytes(outIV, self.cipherIVLength) != 1) {
if (error) {
*error = TunnelKitErrorWithCode(TunnelKitErrorCodeCryptoBoxRandomGenerator);
if (self.cipher) {
if (RAND_bytes(outIV, self.cipherIVLength) != 1) {
if (error) {
*error = TunnelKitErrorWithCode(TunnelKitErrorCodeCryptoBoxRandomGenerator);
}
return NO;
}
return NO;
TUNNEL_CRYPTO_TRACK_STATUS(code) EVP_CipherInit(self.cipherCtxEnc, NULL, NULL, outIV, -1);
TUNNEL_CRYPTO_TRACK_STATUS(code) EVP_CipherUpdate(self.cipherCtxEnc, outEncrypted, &l1, bytes, (int)length);
TUNNEL_CRYPTO_TRACK_STATUS(code) EVP_CipherFinal(self.cipherCtxEnc, outEncrypted + l1, &l2);
}
else {
NSAssert(outEncrypted == outIV, @"cipherIVLength is non-zero");
memcpy(outEncrypted, bytes, length);
l1 = (int)length;
}
TUNNEL_CRYPTO_TRACK_STATUS(code) EVP_CipherInit(self.cipherCtxEnc, NULL, NULL, outIV, -1);
TUNNEL_CRYPTO_TRACK_STATUS(code) EVP_CipherUpdate(self.cipherCtxEnc, outEncrypted, &l1, bytes, (int)length);
TUNNEL_CRYPTO_TRACK_STATUS(code) EVP_CipherFinal(self.cipherCtxEnc, outEncrypted + l1, &l2);
TUNNEL_CRYPTO_TRACK_STATUS(code) HMAC_Init_ex(self.hmacCtxEnc, NULL, 0, NULL, NULL);
TUNNEL_CRYPTO_TRACK_STATUS(code) HMAC_Update(self.hmacCtxEnc, outIV, l1 + l2 + self.cipherIVLength);
@ -175,17 +200,23 @@ const NSInteger CryptoCBCMaxHMACLength = 100;
- (void)configureDecryptionWithCipherKey:(ZeroingData *)cipherKey hmacKey:(ZeroingData *)hmacKey
{
NSParameterAssert(cipherKey.count >= self.cipherKeyLength);
NSParameterAssert(hmacKey);
NSParameterAssert(hmacKey.count >= self.hmacKeyLength);
EVP_CIPHER_CTX_reset(self.cipherCtxDec);
EVP_CipherInit(self.cipherCtxDec, self.cipher, cipherKey.bytes, NULL, 0);
if (self.cipher) {
NSParameterAssert(cipherKey.count >= self.cipherKeyLength);
EVP_CIPHER_CTX_reset(self.cipherCtxDec);
EVP_CipherInit(self.cipherCtxDec, self.cipher, cipherKey.bytes, NULL, 0);
}
HMAC_CTX_reset(self.hmacCtxDec);
HMAC_Init_ex(self.hmacCtxDec, hmacKey.bytes, self.digestLength, self.digest, NULL);
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;
@ -203,6 +234,8 @@ const NSInteger CryptoCBCMaxHMACLength = 100;
- (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");
const uint8_t *iv = bytes + self.digestLength;
const uint8_t *encrypted = bytes + self.digestLength + self.cipherIVLength;
int l1 = 0, l2 = 0;
@ -222,12 +255,35 @@ const NSInteger CryptoCBCMaxHMACLength = 100;
TUNNEL_CRYPTO_TRACK_STATUS(code) EVP_CipherInit(self.cipherCtxDec, NULL, NULL, iv, -1);
TUNNEL_CRYPTO_TRACK_STATUS(code) EVP_CipherUpdate(self.cipherCtxDec, dest, &l1, encrypted, (int)length - self.digestLength - self.cipherIVLength);
TUNNEL_CRYPTO_TRACK_STATUS(code) EVP_CipherFinal(self.cipherCtxDec, dest + l1, &l2);
*destLength = l1 + l2;
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;
int code = 1;
TUNNEL_CRYPTO_TRACK_STATUS(code) HMAC_Init_ex(self.hmacCtxDec, NULL, 0, NULL, NULL);
TUNNEL_CRYPTO_TRACK_STATUS(code) HMAC_Update(self.hmacCtxDec, bytes + self.digestLength, length - self.digestLength);
TUNNEL_CRYPTO_TRACK_STATUS(code) HMAC_Final(self.hmacCtxDec, self.bufferDecHMAC, (unsigned *)&l1);
if (TUNNEL_CRYPTO_SUCCESS(code) && CRYPTO_memcmp(self.bufferDecHMAC, bytes, self.digestLength) != 0) {
if (error) {
*error = TunnelKitErrorWithCode(TunnelKitErrorCodeCryptoBoxHMAC);
}
return NO;
}
return YES;
}
- (id<DataPathDecrypter>)dataPathDecrypter
{
return [[DataPathCryptoCBC alloc] initWithCrypto:self];

View File

@ -36,6 +36,8 @@
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@protocol DataPathEncrypter;
@protocol DataPathDecrypter;
@ -45,14 +47,16 @@
@property (nonatomic, assign) uint32_t maxPacketId;
- (nonnull instancetype)initWithEncrypter:(nonnull id<DataPathEncrypter>)encrypter
decrypter:(nonnull id<DataPathDecrypter>)decrypter
- (instancetype)initWithEncrypter:(id<DataPathEncrypter>)encrypter
decrypter:(id<DataPathDecrypter>)decrypter
peerId:(uint32_t)peerId // 24-bit, discard most significant byte
compressionFraming:(CompressionFramingNative)compressionFraming
maxPackets:(NSInteger)maxPackets
usesReplayProtection:(BOOL)usesReplayProtection;
- (NSArray<NSData *> *)encryptPackets:(nonnull NSArray<NSData *> *)packets key:(uint8_t)key error:(NSError **)error;
- (NSArray<NSData *> *)decryptPackets:(nonnull NSArray<NSData *> *)packets keepAlive:(nullable bool *)keepAlive error:(NSError **)error;
- (nullable NSArray<NSData *> *)encryptPackets:(NSArray<NSData *> *)packets key:(uint8_t)key error:(NSError **)error;
- (nullable NSArray<NSData *> *)decryptPackets:(NSArray<NSData *> *)packets keepAlive:(nullable bool *)keepAlive error:(NSError **)error;
@end
NS_ASSUME_NONNULL_END

View File

@ -156,24 +156,24 @@
{
switch (compressionFraming) {
case CompressionFramingNativeDisabled: {
self.assemblePayloadBlock = ^(uint8_t * _Nonnull packetDest, NSInteger * _Nonnull packetLengthOffset, NSData * _Nonnull payload) {
self.assemblePayloadBlock = ^(uint8_t * packetDest, NSInteger * packetLengthOffset, NSData * payload) {
memcpy(packetDest, payload.bytes, payload.length);
*packetLengthOffset = 0;
};
self.parsePayloadBlock = ^(uint8_t * _Nonnull payload, NSInteger *payloadOffset, NSInteger * _Nonnull headerLength, const uint8_t * _Nonnull packet, NSInteger packetLength) {
self.parsePayloadBlock = ^(uint8_t * payload, NSInteger *payloadOffset, NSInteger * headerLength, const uint8_t * packet, NSInteger packetLength) {
*payloadOffset = 0;
*headerLength = 0;
};
break;
}
case CompressionFramingNativeCompress: {
self.assemblePayloadBlock = ^(uint8_t * _Nonnull packetDest, NSInteger * _Nonnull packetLengthOffset, NSData * _Nonnull payload) {
self.assemblePayloadBlock = ^(uint8_t * packetDest, NSInteger * packetLengthOffset, NSData * payload) {
memcpy(packetDest, payload.bytes, payload.length);
packetDest[payload.length] = packetDest[0];
packetDest[0] = DataPacketNoCompressSwap;
*packetLengthOffset = 1;
};
self.parsePayloadBlock = ^(uint8_t * _Nonnull payload, NSInteger *payloadOffset, NSInteger * _Nonnull headerLength, const uint8_t * _Nonnull packet, NSInteger packetLength) {
self.parsePayloadBlock = ^(uint8_t * payload, NSInteger *payloadOffset, NSInteger * headerLength, const uint8_t * packet, NSInteger packetLength) {
NSCAssert(payload[0] == DataPacketNoCompressSwap, @"Expected NO_COMPRESS_SWAP (found %X != %X)", payload[0], DataPacketNoCompressSwap);
payload[0] = packet[packetLength - 1];
*payloadOffset = 0;
@ -182,12 +182,12 @@
break;
}
case CompressionFramingNativeCompLZO: {
self.assemblePayloadBlock = ^(uint8_t * _Nonnull packetDest, NSInteger * _Nonnull packetLengthOffset, NSData * _Nonnull payload) {
self.assemblePayloadBlock = ^(uint8_t * packetDest, NSInteger * packetLengthOffset, NSData * payload) {
memcpy(packetDest + 1, payload.bytes, payload.length);
packetDest[0] = DataPacketNoCompress;
*packetLengthOffset = 1;
};
self.parsePayloadBlock = ^(uint8_t * _Nonnull payload, NSInteger *payloadOffset, NSInteger * _Nonnull headerLength, const uint8_t * _Nonnull packet, NSInteger packetLength) {
self.parsePayloadBlock = ^(uint8_t * payload, NSInteger *payloadOffset, NSInteger * headerLength, const uint8_t * packet, NSInteger packetLength) {
NSCAssert(payload[0] == DataPacketNoCompress, @"Expected NO_COMPRESS (found %X != %X)", payload[0], DataPacketNoCompress);
*payloadOffset = 1;
*headerLength = 1;

View File

@ -36,8 +36,10 @@
#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);
NS_ASSUME_NONNULL_BEGIN
typedef void (^DataPathAssembleBlock)(uint8_t *packetDest, NSInteger *packetLengthOffset, NSData *payload);
typedef void (^DataPathParseBlock)(uint8_t *payload, NSInteger *payloadOffset, NSInteger *headerLength, const uint8_t *packet, NSInteger packetLength);
@protocol DataPathChannel
@ -48,14 +50,16 @@ typedef void (^DataPathParseBlock)(uint8_t *_Nonnull payload, NSInteger *_Nonnul
@protocol DataPathEncrypter <DataPathChannel>
- (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 packetBytes:(const uint8_t *)packetBytes packetLength:(NSInteger)packetLength error:(NSError **)error;
- (void)assembleDataPacketWithBlock:(nullable DataPathAssembleBlock)block packetId:(uint32_t)packetId payload:(NSData *)payload into:(uint8_t *)packetBytes length:(NSInteger *)packetLength;
- (nullable NSData *)encryptedDataPacketWithKey:(uint8_t)key packetId:(uint32_t)packetId packetBytes:(const uint8_t *)packetBytes packetLength:(NSInteger)packetLength error:(NSError **)error;
@end
@protocol DataPathDecrypter <DataPathChannel>
- (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 *)parsePayloadWithBlock:(DataPathParseBlock)block length:(nonnull NSInteger *)length packetBytes:(nonnull uint8_t *)packetBytes packetLength:(NSInteger)packetLength;
- (BOOL)decryptDataPacket:(NSData *)packet into:(uint8_t *)packetBytes length:(NSInteger *)packetLength packetId:(uint32_t *)packetId error:(NSError **)error;
- (const uint8_t *)parsePayloadWithBlock:(nullable DataPathParseBlock)block length:(NSInteger *)length packetBytes:(uint8_t *)packetBytes packetLength:(NSInteger)packetLength;
@end
NS_ASSUME_NONNULL_END

View File

@ -38,33 +38,41 @@
#import "ZeroingData.h"
NS_ASSUME_NONNULL_BEGIN
@protocol DataPathEncrypter;
@protocol DataPathDecrypter;
// WARNING: dest must be able to hold ciphertext
@protocol Encrypter
- (void)configureEncryptionWithCipherKey:(nonnull ZeroingData *)cipherKey hmacKey:(nonnull ZeroingData *)hmacKey;
- (void)configureEncryptionWithCipherKey:(nullable ZeroingData *)cipherKey hmacKey:(nullable ZeroingData *)hmacKey;
- (int)digestLength;
- (int)overheadLength;
- (int)extraLength;
- (NSData *)encryptData:(nonnull NSData *)data offset:(NSInteger)offset extra:(const uint8_t *)extra error:(NSError **)error;
- (BOOL)encryptBytes:(nonnull const uint8_t *)bytes length:(NSInteger)length dest:(nonnull uint8_t *)dest destLength:(nonnull NSInteger *)destLength extra:(const uint8_t *)extra error:(NSError **)error;
- (nullable NSData *)encryptData:(NSData *)data offset:(NSInteger)offset extra:(nullable const uint8_t *)extra error:(NSError **)error;
- (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;
- (nonnull id<DataPathEncrypter>)dataPathEncrypter;
- (id<DataPathEncrypter>)dataPathEncrypter;
@end
// WARNING: dest must be able to hold plaintext
@protocol Decrypter
- (void)configureDecryptionWithCipherKey:(nonnull ZeroingData *)cipherKey hmacKey:(nonnull ZeroingData *)hmacKey;
- (void)configureDecryptionWithCipherKey:(nullable ZeroingData *)cipherKey hmacKey:(nullable ZeroingData *)hmacKey;
- (int)digestLength;
- (int)overheadLength;
- (int)extraLength;
- (NSData *)decryptData:(nonnull NSData *)data offset:(NSInteger)offset extra:(const uint8_t *)extra error:(NSError **)error;
- (BOOL)decryptBytes:(nonnull const uint8_t *)bytes length:(NSInteger)length dest:(nonnull uint8_t *)dest destLength:(nonnull NSInteger *)destLength extra:(const uint8_t *)extra error:(NSError **)error;
- (nullable NSData *)decryptData:(NSData *)data offset:(NSInteger)offset extra:(nullable const uint8_t *)extra error:(NSError **)error;
- (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;
- (nonnull id<DataPathDecrypter>)dataPathDecrypter;
- (id<DataPathDecrypter>)dataPathDecrypter;
@end
NS_ASSUME_NONNULL_END

View File

@ -37,6 +37,8 @@
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
#define PacketPeerIdDisabled 0xffffffu
#define PacketIdLength 4
@ -56,14 +58,15 @@ typedef NS_ENUM(uint8_t, PacketCode) {
extern const uint8_t DataPacketPingData[16];
static inline int PacketHeaderSet(uint8_t *_Nonnull to, PacketCode code, uint8_t key)
// Ruby: header
static inline int PacketHeaderSet(uint8_t *to, PacketCode code, uint8_t key)
{
*(uint8_t *)to = (code << 3) | (key & 0b111);
return sizeof(uint8_t);
}
// Ruby: header
static inline NSData *_Nonnull PacketWithHeader(PacketCode code, uint8_t key, NSData *sessionId)
static inline NSData *PacketWithHeader(PacketCode code, uint8_t key, NSData *_Nullable sessionId)
{
NSMutableData *to = [[NSMutableData alloc] initWithLength:(sizeof(uint8_t) + (sessionId ? sessionId.length : 0))];
const int offset = PacketHeaderSet(to.mutableBytes, code, key);
@ -73,18 +76,18 @@ static inline NSData *_Nonnull PacketWithHeader(PacketCode code, uint8_t key, NS
return to;
}
static inline int PacketHeaderSetDataV2(uint8_t *_Nonnull to, uint8_t key, uint32_t peerId)
static inline int PacketHeaderSetDataV2(uint8_t *to, uint8_t key, uint32_t peerId)
{
*(uint32_t *)to = ((PacketCodeDataV2 << 3) | (key & 0b111)) | htonl(peerId & 0xffffff);
return sizeof(uint32_t);
}
static inline int PacketHeaderGetDataV2PeerId(const uint8_t *_Nonnull from)
static inline int PacketHeaderGetDataV2PeerId(const uint8_t *from)
{
return ntohl(*(const uint32_t *)from & 0xffffff00);
}
static inline NSData *_Nonnull PacketWithHeaderDataV2(uint8_t key, uint32_t peerId, NSData *sessionId)
static inline NSData *PacketWithHeaderDataV2(uint8_t key, uint32_t peerId, NSData *sessionId)
{
NSMutableData *to = [[NSMutableData alloc] initWithLength:(sizeof(uint32_t) + (sessionId ? sessionId.length : 0))];
const int offset = PacketHeaderSetDataV2(to.mutableBytes, key, peerId);
@ -93,3 +96,5 @@ static inline NSData *_Nonnull PacketWithHeaderDataV2(uint8_t key, uint32_t peer
}
return to;
}
NS_ASSUME_NONNULL_END

View File

@ -49,7 +49,7 @@ extern NSString *const TLSBoxPeerVerificationErrorNotification;
//
@interface TLSBox : NSObject
- (nonnull instancetype)initWithCAPath:(NSString *)caPath
- (instancetype)initWithCAPath:(NSString *)caPath
clientCertificatePath:(NSString *)clientCertificatePath
clientKeyPath:(NSString *)clientKeyPath;

View File

@ -37,6 +37,8 @@
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface ZeroingData : NSObject
@property (nonatomic, readonly) const uint8_t *bytes;
@ -44,7 +46,7 @@
@property (nonatomic, readonly) NSInteger count;
- (instancetype)initWithCount:(NSInteger)count;
- (instancetype)initWithBytes:(const uint8_t *)bytes count:(NSInteger)count;
- (instancetype)initWithBytes:(nullable const uint8_t *)bytes count:(NSInteger)count;
- (instancetype)initWithUInt8:(uint8_t)uint8;
- (instancetype)initWithUInt16:(uint16_t)uint16;
@ -57,13 +59,15 @@
- (void)removeUntilOffset:(NSInteger)until;
- (void)zero;
- (nonnull ZeroingData *)appendingData:(ZeroingData *)other;
- (nonnull ZeroingData *)withOffset:(NSInteger)offset count:(NSInteger)count;
- (ZeroingData *)appendingData:(ZeroingData *)other;
- (ZeroingData *)withOffset:(NSInteger)offset count:(NSInteger)count;
- (uint16_t)UInt16ValueFromOffset:(NSInteger)from;
- (uint16_t)networkUInt16ValueFromOffset:(NSInteger)from;
- (NSString *)nullTerminatedStringFromOffset:(NSInteger)from;
- (nullable NSString *)nullTerminatedStringFromOffset:(NSInteger)from;
- (BOOL)isEqualToData:(NSData *)data;
- (nonnull NSString *)toHex;
- (NSString *)toHex;
@end
NS_ASSUME_NONNULL_END

View File

@ -65,6 +65,22 @@ class EncryptionTests: XCTestCase {
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 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)
}
}
func testGCM() {
let gcm = CryptoBox(cipherAlgorithm: "aes-256-gcm", digestAlgorithm: nil)
try! gcm.configure(withCipherEncKey: cipherKey, cipherDecKey: cipherKey, hmacEncKey: hmacKey, hmacDecKey: hmacKey)