Blob Blame History Raw
/*
 Password Encryption Controller
 
 Copyright 2013 Thincast Technologies GmbH, Author: Dorian Johnson
 
 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 "EncryptionController.h"
#import "SFHFKeychainUtils.h"
#import "TSXAdditions.h"

@interface EncryptionController (Private)

- (BOOL)verifyPassword:(Encryptor*)decryptor;
- (NSData*)encryptedVerificationData;
- (void)setEncryptedVerificationData:(Encryptor*)encryptor;

- (NSString*)keychainServerName;
- (NSString*)keychainUsername;
- (void)setKeychainPassword:(NSString*)password;
- (NSString*)keychainPassword;
- (NSString*)keychainDefaultPassword;

@end

static EncryptionController* _shared_encryption_controller = nil;


#pragma mark -

@implementation EncryptionController

+ (EncryptionController*)sharedEncryptionController
{
	@synchronized(self)
	{
		if (_shared_encryption_controller == nil)
			_shared_encryption_controller = [[EncryptionController alloc] init];		
	}
	
	return _shared_encryption_controller;	
}

#pragma mark Getting an encryptor or decryptor

- (Encryptor*)encryptor
{
	if (_shared_encryptor)
		return _shared_encryptor;
	
	NSString* saved_password = [self keychainPassword];    
	if (saved_password == nil)
    {
        saved_password = [self keychainDefaultPassword];        
        Encryptor* encryptor = [[[Encryptor alloc] initWithPassword:saved_password] autorelease];
        [self setEncryptedVerificationData:encryptor];        
        _shared_encryptor = [encryptor retain];
    }
    else
    {
        Encryptor* encryptor = [[[Encryptor alloc] initWithPassword:saved_password] autorelease];
        if ([self verifyPassword:encryptor])
            _shared_encryptor = [encryptor retain];
    }    
    
    return _shared_encryptor;
}

// For the current implementation, decryptors and encryptors are equivilant.
- (Encryptor*)decryptor { return [self encryptor]; }

@end

#pragma mark -

@implementation EncryptionController (Private)

#pragma mark -
#pragma mark Keychain password storage

- (NSString*)keychainServerName
{
	return [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
}

- (NSString*)keychainUsername
{
	return @"master.password";
}

- (void)setKeychainPassword:(NSString*)password
{	
    NSError* error;
	if (password == nil)
	{
        [SFHFKeychainUtils deleteItemForUsername:[self keychainUsername] andServerName:[self keychainServerName] error:&error];
		return;
	}

	[SFHFKeychainUtils storeUsername:[self keychainUsername] andPassword:password forServerName:[self keychainServerName] updateExisting:YES error:&error];
}

- (NSString*)keychainPassword
{
    NSError* error;
    return [SFHFKeychainUtils getPasswordForUsername:[self keychainUsername] andServerName:[self keychainServerName] error:&error];
}

- (NSString*)keychainDefaultPassword
{
    NSString* password = [[NSUserDefaults standardUserDefaults] stringForKey:@"UUID"];
    if ([password length] == 0)
    {
        password = [NSString stringWithUUID];
        [[NSUserDefaults standardUserDefaults] setObject:password forKey:@"UUID"];
        [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"TSXMasterPasswordVerification"];
    }
    return password;
}

#pragma mark -
#pragma mark Verification of encryption key against verification data

- (BOOL)verifyPassword:(Encryptor*)decryptor 
{
	return [[decryptor plaintextPassword] isEqualToString:[decryptor decryptString:[self encryptedVerificationData]]];
}

- (NSData*)encryptedVerificationData
{
	return [[NSUserDefaults standardUserDefaults] dataForKey:@"TSXMasterPasswordVerification"];
}

- (void)setEncryptedVerificationData:(Encryptor*)encryptor
{
	[[NSUserDefaults standardUserDefaults] setObject:[encryptor encryptString:[encryptor plaintextPassword]] forKey:@"TSXMasterPasswordVerification"];
}

@end