Initial commit
This commit is contained in:
@@ -0,0 +1,272 @@
|
||||
// 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
|
||||
Reference in New Issue
Block a user