tunnelkit/TunnelKit/Sources/Core/CryptoBox.m
2018-08-23 12:10:56 +02:00

138 lines
3.9 KiB
Objective-C

//
// CryptoBox.m
// TunnelKit
//
// Created by Davide De Rosa on 2/4/17.
// Copyright © 2018 London Trust Media. All rights reserved.
//
#import <openssl/evp.h>
#import <openssl/hmac.h>
#import <openssl/rand.h>
#import "CryptoBox.h"
#import "CryptoMacros.h"
#import "Allocation.h"
#import "Errors.h"
#import "CryptoCBC.h"
#import "CryptoAEAD.h"
@interface CryptoBox ()
@property (nonatomic, strong) NSString *cipherAlgorithm;
@property (nonatomic, strong) NSString *digestAlgorithm;
@property (nonatomic, strong) id<Encrypter> encrypter;
@property (nonatomic, strong) id<Decrypter> decrypter;
@end
@implementation CryptoBox
+ (void)initialize
{
}
+ (BOOL)preparePRNGWithSeed:(const uint8_t *)seed length:(NSInteger)length
{
unsigned char x[1];
// make sure its initialized before seeding
if (RAND_bytes(x, 1) != 1) {
return NO;
}
RAND_seed(seed, (int)length);
return YES;
}
- (instancetype)initWithCipherAlgorithm:(NSString *)cipherAlgorithm digestAlgorithm:(NSString *)digestAlgorithm
{
NSParameterAssert(cipherAlgorithm);
// NSParameterAssert(digestAlgorithm);
if ((self = [super init])) {
self.cipherAlgorithm = [cipherAlgorithm lowercaseString];
self.digestAlgorithm = [digestAlgorithm lowercaseString];
}
return self;
}
- (void)dealloc
{
self.encrypter = nil;
self.decrypter = nil;
}
// these keys are coming from the OpenVPN negotiation despite the cipher
- (BOOL)configureWithCipherEncKey:(ZeroingData *)cipherEncKey
cipherDecKey:(ZeroingData *)cipherDecKey
hmacEncKey:(ZeroingData *)hmacEncKey
hmacDecKey:(ZeroingData *)hmacDecKey
error:(NSError *__autoreleasing *)error
{
NSParameterAssert(cipherEncKey);
NSParameterAssert(cipherDecKey);
NSParameterAssert(hmacEncKey);
NSParameterAssert(hmacDecKey);
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;
}
[self.encrypter configureEncryptionWithCipherKey:cipherEncKey hmacKey:hmacEncKey];
[self.decrypter configureDecryptionWithCipherKey:cipherDecKey hmacKey:hmacDecKey];
return YES;
}
+ (BOOL)hmacWithDigestName:(NSString *)digestName
secret:(const uint8_t *)secret
secretLength:(NSInteger)secretLength
data:(const uint8_t *)data
dataLength:(NSInteger)dataLength
hmac:(uint8_t *)hmac
hmacLength:(NSInteger *)hmacLength
error:(NSError **)error
{
NSParameterAssert(digestName);
NSParameterAssert(secret);
NSParameterAssert(data);
unsigned int l = 0;
int code = 1;
HMAC_CTX *ctx = HMAC_CTX_new();
TUNNEL_CRYPTO_TRACK_STATUS(code) HMAC_CTX_reset(ctx);
TUNNEL_CRYPTO_TRACK_STATUS(code) HMAC_Init_ex(ctx, secret, (int)secretLength, EVP_get_digestbyname([digestName cStringUsingEncoding:NSASCIIStringEncoding]), NULL);
TUNNEL_CRYPTO_TRACK_STATUS(code) HMAC_Update(ctx, data, dataLength);
TUNNEL_CRYPTO_TRACK_STATUS(code) HMAC_Final(ctx, hmac, &l);
HMAC_CTX_free(ctx);
*hmacLength = l;
TUNNEL_CRYPTO_RETURN_STATUS(code)
}
@end