// // CryptoBox.m // TunnelKit // // Created by Davide De Rosa on 2/4/17. // Copyright © 2018 London Trust Media. All rights reserved. // #import #import #import #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; @property (nonatomic, strong) id 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