Antidote/local_pod_repo/objcTox/Classes/Private/Wrapper/OCTToxEncryptSave.m
2024-02-22 21:43:11 +02:00

273 lines
7.9 KiB
Objective-C

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#import "OCTToxEncryptSave.h"
#import <toxcore/toxencryptsave/toxencryptsave.h>
#import "OCTToxEncryptSaveConstants.h"
#import "OCTTox+Private.h"
@interface OCTToxEncryptSave ()
@property (assign, nonatomic) Tox_Pass_Key *passKey;
@end
@implementation OCTToxEncryptSave
#pragma mark - Lifecycle
- (nullable instancetype)initWithPassphrase:(nonnull NSString *)passphrase
toxData:(nullable NSData *)toxData
error:(NSError *__nullable *__nullable)error
{
self = [super init];
if (! self) {
return nil;
}
TOX_ERR_KEY_DERIVATION cError;
uint8_t salt[TOX_PASS_SALT_LENGTH];
bool hasSalt = false;
if (toxData) {
hasSalt = tox_get_salt(toxData.bytes, salt, NULL);
}
if (hasSalt) {
_passKey = tox_pass_key_derive_with_salt(
(const uint8_t *)[passphrase cStringUsingEncoding:NSUTF8StringEncoding],
[passphrase lengthOfBytesUsingEncoding:NSUTF8StringEncoding],
salt,
&cError);
}
else {
_passKey = tox_pass_key_derive(
(const uint8_t *)[passphrase cStringUsingEncoding:NSUTF8StringEncoding],
[passphrase lengthOfBytesUsingEncoding:NSUTF8StringEncoding],
&cError);
}
[OCTToxEncryptSave fillError:error withCErrorKeyDerivation:cError];
return (_passKey != NULL) ? self : nil;
}
- (void)dealloc
{
if (_passKey) {
tox_pass_key_free(_passKey);
}
}
#pragma mark - Public class methods
+ (BOOL)isDataEncrypted:(nonnull NSData *)data
{
return tox_is_data_encrypted(data.bytes);
}
+ (nullable NSData *)encryptData:(nonnull NSData *)data
withPassphrase:(nonnull NSString *)passphrase
error:(NSError *__nullable *__nullable)error
{
NSParameterAssert(data);
NSParameterAssert(passphrase);
return [OCTToxEncryptSave convertDataOfLength:data.length encrypt:YES withConvertBlock:^bool (uint8_t *out) {
TOX_ERR_ENCRYPTION cError;
bool result = tox_pass_encrypt(
data.bytes,
data.length,
(const uint8_t *)[passphrase cStringUsingEncoding:NSUTF8StringEncoding],
[passphrase lengthOfBytesUsingEncoding:NSUTF8StringEncoding],
out,
&cError);
[OCTToxEncryptSave fillError:error withCErrorEncryption:cError];
return result;
}];
}
+ (nullable NSData *)decryptData:(nonnull NSData *)data
withPassphrase:(nonnull NSString *)passphrase
error:(NSError *__nullable *__nullable)error
{
NSParameterAssert(data);
NSParameterAssert(passphrase);
return [OCTToxEncryptSave convertDataOfLength:data.length encrypt:NO withConvertBlock:^bool (uint8_t *out) {
TOX_ERR_DECRYPTION cError;
bool result = tox_pass_decrypt(
data.bytes,
data.length,
(const uint8_t *)[passphrase cStringUsingEncoding:NSUTF8StringEncoding],
[passphrase lengthOfBytesUsingEncoding:NSUTF8StringEncoding],
out,
&cError);
[OCTToxEncryptSave fillError:error withCErrorDecryption:cError];
return result;
}];
}
#pragma mark - Public instance method
- (nullable NSData *)encryptData:(nonnull NSData *)data error:(NSError *__nullable *__nullable)error
{
NSParameterAssert(data);
return [OCTToxEncryptSave convertDataOfLength:data.length encrypt:YES withConvertBlock:^bool (uint8_t *out) {
TOX_ERR_ENCRYPTION cError;
bool result = tox_pass_key_encrypt(
self.passKey,
data.bytes,
data.length,
out,
&cError);
[OCTToxEncryptSave fillError:error withCErrorEncryption:cError];
return result;
}];
}
- (nullable NSData *)decryptData:(nonnull NSData *)data error:(NSError *__nullable *__nullable)error
{
NSParameterAssert(data);
return [OCTToxEncryptSave convertDataOfLength:data.length encrypt:NO withConvertBlock:^bool (uint8_t *out) {
TOX_ERR_DECRYPTION cError;
bool result = tox_pass_key_decrypt(
self.passKey,
data.bytes,
data.length,
out,
&cError);
[OCTToxEncryptSave fillError:error withCErrorDecryption:cError];
return result;
}];
}
#pragma mark - Private
+ (NSData *)convertDataOfLength:(NSUInteger)dataLength
encrypt:(BOOL)encrypt
withConvertBlock:(bool (^)(uint8_t *out))convertBlock
{
NSUInteger outLength = dataLength + (encrypt ? TOX_PASS_ENCRYPTION_EXTRA_LENGTH : -TOX_PASS_ENCRYPTION_EXTRA_LENGTH);
uint8_t *out = malloc(outLength);
bool result = convertBlock(out);
NSData *resultData = nil;
if (result) {
resultData = [NSData dataWithBytes:out length:outLength];
}
if (out) {
free(out);
}
return resultData;
}
+ (BOOL)fillError:(NSError **)error withCErrorKeyDerivation:(TOX_ERR_KEY_DERIVATION)cError
{
if (! error || (cError == TOX_ERR_KEY_DERIVATION_OK)) {
return NO;
}
switch (cError) {
case TOX_ERR_KEY_DERIVATION_OK:
NSAssert(NO, @"We shouldn't be here");
return NO;
case TOX_ERR_KEY_DERIVATION_NULL:
case TOX_ERR_KEY_DERIVATION_FAILED:
*error = [OCTTox createErrorWithCode:OCTToxEncryptSaveKeyDerivationErrorFailed
description:@"Cannot create key from given passphrase"
failureReason:nil];
break;
}
return YES;
}
+ (BOOL)fillError:(NSError **)error withCErrorEncryption:(TOX_ERR_ENCRYPTION)cError
{
if (! error || (cError == TOX_ERR_ENCRYPTION_OK)) {
return NO;
}
OCTToxEncryptSaveEncryptionError code;
NSString *description = @"Encryption failed";
NSString *failureReason = nil;
switch (cError) {
case TOX_ERR_ENCRYPTION_OK:
NSAssert(NO, @"We shouldn't be here");
return NO;
case TOX_ERR_ENCRYPTION_NULL:
code = OCTToxEncryptSaveEncryptionErrorNull;
failureReason = @"Some input data was empty.";
break;
case TOX_ERR_ENCRYPTION_KEY_DERIVATION_FAILED:
case TOX_ERR_ENCRYPTION_FAILED:
code = OCTToxEncryptSaveEncryptionErrorFailed;
failureReason = @"Encryption failed, please report";
break;
}
*error = [OCTTox createErrorWithCode:code description:description failureReason:failureReason];
return YES;
}
+ (BOOL)fillError:(NSError **)error withCErrorDecryption:(TOX_ERR_DECRYPTION)cError
{
if (! error || (cError == TOX_ERR_DECRYPTION_OK)) {
return NO;
}
OCTToxEncryptSaveDecryptionError code;
NSString *description = @"Decryption failed";
NSString *failureReason = nil;
switch (cError) {
case TOX_ERR_DECRYPTION_OK:
NSAssert(NO, @"We shouldn't be here");
return NO;
case TOX_ERR_DECRYPTION_NULL:
code = OCTToxEncryptSaveDecryptionErrorNull;
failureReason = @"Some input data was empty.";
break;
case TOX_ERR_DECRYPTION_BAD_FORMAT:
code = OCTToxEncryptSaveDecryptionErrorBadFormat;
failureReason = @"The input data has bad format";
break;
case TOX_ERR_DECRYPTION_INVALID_LENGTH:
case TOX_ERR_DECRYPTION_KEY_DERIVATION_FAILED:
case TOX_ERR_DECRYPTION_FAILED:
code = OCTToxEncryptSaveDecryptionErrorFailed;
failureReason = @"Decryption failed, passphrase is incorrect or data is corrupt";
break;
}
*error = [OCTTox createErrorWithCode:code description:description failureReason:failureReason];
return YES;
}
@end