Cleaner Keychain storage

This commit is contained in:
Frederic Jacobs 2014-05-07 00:33:20 +02:00
parent 6373507108
commit a6bf143855
18 changed files with 159 additions and 307 deletions

View File

@ -2,6 +2,7 @@ platform :ios, '7.0'
link_with ["Signal", "SignalTests"]
pod 'UICKeyChainStore', '~> 1.0.5'
pod 'OpenSSL', '~> 1.0.1'
pod 'MMDrawerController', '~> 0.5.0'
pod 'libPhoneNumber-iOS', '~> 0.7'

View File

@ -381,9 +381,7 @@
A1C32D5117A06544000A904E /* AddressBook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1C32D4D17A0652C000A904E /* AddressBook.framework */; };
AA0C8E498E2046B0B81EEE6E /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8313AE91B4954215858A5662 /* libPods.a */; };
B67EBF5D19194AC60084CCFD /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = B67EBF5C19194AC60084CCFD /* Settings.bundle */; };
B68DF7B71918D7FC00C7BAB9 /* KeyChainStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = B68DF7B61918D7FC00C7BAB9 /* KeyChainStorage.m */; };
B6B6C3C71919440C00C0B76B /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = B6B6C3C51919440C00C0B76B /* Localizable.strings */; };
B6BAB53F1918CA4100E4DF53 /* KeychainWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = B6BAB53E1918CA4100E4DF53 /* KeychainWrapper.m */; };
B90418E6183E9DD40038554A /* DateUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = B90418E5183E9DD40038554A /* DateUtil.m */; };
B90418E7183E9DD40038554A /* DateUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = B90418E5183E9DD40038554A /* DateUtil.m */; };
B942EB0E183A9633000887BB /* SearchBarTitleView.m in Sources */ = {isa = PBXBuildFile; fileRef = B942EB0D183A9633000887BB /* SearchBarTitleView.m */; };
@ -1091,8 +1089,6 @@
A1FDCBEE16DAA6C300868894 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
B657DDC91911A40500F45B0C /* Signal.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = Signal.entitlements; sourceTree = "<group>"; };
B67EBF5C19194AC60084CCFD /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = Settings.bundle; path = SettingsBundle/Settings.bundle; sourceTree = SOURCE_ROOT; };
B68DF7B51918D7FC00C7BAB9 /* KeyChainStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KeyChainStorage.h; path = ../environment/KeyChainStorage.h; sourceTree = "<group>"; };
B68DF7B61918D7FC00C7BAB9 /* KeyChainStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = KeyChainStorage.m; path = ../environment/KeyChainStorage.m; sourceTree = "<group>"; };
B6B6C3C61919440C00C0B76B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
B6B6C3C81919441D00C0B76B /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
B6B6C3C91919448900C0B76B /* ca-ES */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "ca-ES"; path = "ca-ES.lproj/Localizable.strings"; sourceTree = "<group>"; };
@ -1101,8 +1097,6 @@
B6B6C3CC1919454200C0B76B /* ro-RO */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "ro-RO"; path = "ro-RO.lproj/Localizable.strings"; sourceTree = "<group>"; };
B6B6C3CD1919455400C0B76B /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = "<group>"; };
B6B6C3CE1919456C00C0B76B /* sv-SE */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "sv-SE"; path = "sv-SE.lproj/Localizable.strings"; sourceTree = "<group>"; };
B6BAB53D1918CA4100E4DF53 /* KeychainWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KeychainWrapper.h; path = ../storage/KeychainWrapper.h; sourceTree = "<group>"; };
B6BAB53E1918CA4100E4DF53 /* KeychainWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = KeychainWrapper.m; path = ../storage/KeychainWrapper.m; sourceTree = "<group>"; };
B90418E4183E9DD40038554A /* DateUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DateUtil.h; sourceTree = "<group>"; };
B90418E5183E9DD40038554A /* DateUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DateUtil.m; sourceTree = "<group>"; };
B942EB0C183A9633000887BB /* SearchBarTitleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SearchBarTitleView.h; sourceTree = "<group>"; };
@ -1579,7 +1573,6 @@
70BAFD5C190584BE00FA5E0B /* NotificationTracker.m */,
76EB048818170B33006006FC /* phone */,
76EB04B118170B33006006FC /* profiling */,
B6BAB53C1918CA1300E4DF53 /* storage */,
76EB04C818170B33006006FC /* util */,
76EB04FE18170B33006006FC /* view controllers */,
76EB052B18170B33006006FC /* views */,
@ -2013,8 +2006,6 @@
76EB04E918170B33006006FC /* DictionaryUtil.m */,
76EB04EA18170B33006006FC /* FunctionalUtil.h */,
76EB04EB18170B33006006FC /* FunctionalUtil.m */,
B6BAB53D1918CA4100E4DF53 /* KeychainWrapper.h */,
B6BAB53E1918CA4100E4DF53 /* KeychainWrapper.m */,
76EB04EC18170B33006006FC /* NumberUtil.h */,
76EB04ED18170B33006006FC /* NumberUtil.m */,
76EB04EE18170B33006006FC /* Operation.h */,
@ -2442,15 +2433,6 @@
name = Translations;
sourceTree = "<group>";
};
B6BAB53C1918CA1300E4DF53 /* storage */ = {
isa = PBXGroup;
children = (
B68DF7B51918D7FC00C7BAB9 /* KeyChainStorage.h */,
B68DF7B61918D7FC00C7BAB9 /* KeyChainStorage.m */,
);
path = storage;
sourceTree = "<group>";
};
D221A07E169C9E5E00537ABF = {
isa = PBXGroup;
children = (
@ -3074,7 +3056,6 @@
76EB065A18170B34006006FC /* NextResponderScrollView.m in Sources */,
76EB062618170B33006006FC /* Queue.m in Sources */,
D221A09A169C9E5E00537ABF /* main.m in Sources */,
B6BAB53F1918CA4100E4DF53 /* KeychainWrapper.m in Sources */,
76EB061618170B33006006FC /* AnonymousOccurrenceLogger.m in Sources */,
76EB063018170B33006006FC /* Conversions.m in Sources */,
76EB065618170B34006006FC /* InCallViewController.m in Sources */,
@ -3124,7 +3105,6 @@
E197B60C18BBEC1A00F073E5 /* AudioPacker.m in Sources */,
76EB055018170B33006006FC /* ObservableValue.m in Sources */,
E197B61218BBEC1A00F073E5 /* AudioStretcher.m in Sources */,
B68DF7B71918D7FC00C7BAB9 /* KeyChainStorage.m in Sources */,
76EB05A218170B33006006FC /* IpEndPoint.m in Sources */,
70B8010D190C55660042E3F0 /* AbstractMessage_Builder.m in Sources */,
E197B61A18BBEC1A00F073E5 /* SpeexCodec.m in Sources */,
@ -3625,7 +3605,7 @@
LLVM_LTO = NO;
OTHER_LDFLAGS = "$(inherited)";
PRODUCT_NAME = Signal;
PROVISIONING_PROFILE = "";
PROVISIONING_PROFILE = "25E52683-9ADD-415E-A1E0-63A1C7ECF872";
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = 1;
TEST_AFTER_BUILD = YES;
@ -3673,7 +3653,7 @@
LLVM_LTO = NO;
OTHER_LDFLAGS = "$(inherited)";
PRODUCT_NAME = Signal;
PROVISIONING_PROFILE = "";
PROVISIONING_PROFILE = "25E52683-9ADD-415E-A1E0-63A1C7ECF872";
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = 1;
TEST_AFTER_BUILD = YES;

View File

@ -5,17 +5,16 @@
#import "DialerViewController.h"
#import "DiscardingLog.h"
#import "InCallViewController.h"
#import "KeyChainStorage.h"
#import "LeftSideMenuViewController.h"
#import "MMDrawerController.h"
#import "NotificationTracker.h"
#import "PreferencesUtil.h"
#import "PriorityQueue.h"
#import "RecentCallManager.h"
#import "Release.h"
#import "SettingsViewController.h"
#import "TabBarParentViewController.h"
#import "Util.h"
#import <UICKeyChainStore/UICKeyChainStore.h>
#define kSignalVersionKey @"SignalUpdateVersionKey"
@ -42,7 +41,7 @@
NSString *currentVersion = [NSString stringWithFormat:@"%@", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]];
if (!previousVersion) {
[KeyChainStorage clear];
[UICKeyChainStore removeAllItems];
} else if ([currentVersion compare:previousVersion options:NSNumericSearch] == NSOrderedDescending) {
// The application was updated
}

View File

@ -1,24 +0,0 @@
//
// KeyChainStorage.h
// Signal
//
// Created by Frederic Jacobs on 06/05/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import <Foundation/Foundation.h>
@class PhoneNumber, Zid;
@interface KeyChainStorage : NSObject
+(PhoneNumber*) forceGetLocalNumber;
+(PhoneNumber*)tryGetLocalNumber;
+(void) setLocalNumberTo:(PhoneNumber*)localNumber;
+(Zid*) getOrGenerateZid;
+(NSString*) getOrGenerateSavedPassword;
+(NSData*) getOrGenerateSignalingMacKey;
+(NSData*) getOrGenerateSignalingCipherKey;
+(NSData*) getOrGenerateSignalingExtraKey;
+ (void)clear;
@end

View File

@ -1,105 +0,0 @@
//
// KeyChainStorage.m
// Signal
//
// Created by Frederic Jacobs on 06/05/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import "Constraints.h"
#import "CryptoTools.h"
#import "DataUtil.h"
#import "KeyChainStorage.h"
#import "KeychainWrapper.h"
#import "StringUtil.h"
#import "PhoneNumber.h"
#import "Zid.h"
#define LOCAL_NUMBER_KEY @"Number"
#define SAVED_PASSWORD_KEY @"Password"
#define SIGNALING_MAC_KEY @"Signaling Mac Key"
#define SIGNALING_CIPHER_KEY @"Signaling Cipher Key"
#define ZID_KEY @"ZID"
#define SIGNALING_EXTRA_KEY @"Signaling Extra Key"
#define SIGNALING_MAC_KEY_LENGTH 20
#define SIGNALING_CIPHER_KEY_LENGTH 16
#define SAVED_PASSWORD_LENGTH 18
#define SIGNALING_EXTRA_KEY_LENGTH 4
@implementation KeyChainStorage
+(PhoneNumber*) forceGetLocalNumber {
NSString* localNumber = [self tryGetValueForKey:LOCAL_NUMBER_KEY];
checkOperation(localNumber != nil);
return [PhoneNumber tryParsePhoneNumberFromE164:localNumber];
}
+(void) setLocalNumberTo:(PhoneNumber*)localNumber {
require(localNumber != nil);
[self setValueForKey:LOCAL_NUMBER_KEY toValue:[localNumber toE164]];
}
+(PhoneNumber*)tryGetLocalNumber {
NSString* localNumber = [self tryGetValueForKey:LOCAL_NUMBER_KEY];
return (localNumber != nil ? [PhoneNumber tryParsePhoneNumberFromE164:localNumber] : nil);
}
+(Zid*) getOrGenerateZid {
return [Zid zidWithData:[self getOrGenerateRandomDataWithKey:ZID_KEY andLength:12]];
}
+(NSString*) getOrGenerateSavedPassword {
NSString *password = [KeychainWrapper keychainStringFromMatchingIdentifier:SAVED_PASSWORD_KEY];
if (!password) {
password = [[CryptoTools generateSecureRandomData:SAVED_PASSWORD_LENGTH] encodedAsBase64];
[KeychainWrapper createKeychainValue:password forIdentifier:SAVED_PASSWORD_KEY];
}
return password;
}
+(NSData*) getOrGenerateSignalingMacKey {
return [self getOrGenerateRandomDataWithKey:SIGNALING_MAC_KEY andLength:SIGNALING_MAC_KEY_LENGTH];
}
+(NSData*) getOrGenerateSignalingCipherKey {
return [self getOrGenerateRandomDataWithKey:SIGNALING_CIPHER_KEY andLength:SIGNALING_CIPHER_KEY_LENGTH];
}
+(NSData*) getOrGenerateSignalingExtraKey {
return [self getOrGenerateRandomDataWithKey:SIGNALING_EXTRA_KEY andLength:SIGNALING_EXTRA_KEY_LENGTH];
}
+(NSData*) getOrGenerateRandomDataWithKey:(NSString*)key andLength:(NSUInteger)length {
require(key != nil);
NSData *password = [[KeychainWrapper keychainStringFromMatchingIdentifier:key] decodedAsBase64Data];
if (!password) {
password = [CryptoTools generateSecureRandomData:length];
[KeychainWrapper createKeychainValue:[password encodedAsBase64] forIdentifier:key];
}
return password;
}
+ (NSString*)tryGetValueForKey:(NSString*)key{
return [KeychainWrapper keychainStringFromMatchingIdentifier:key];
}
+ (void)setValueForKey:(NSString*)key toValue:(NSString*)string{
[KeychainWrapper createKeychainValue:string forIdentifier:key];
}
+ (void)clear{
[KeychainWrapper deleteItemFromKeychainWithIdentifier:SIGNALING_MAC_KEY];
[KeychainWrapper deleteItemFromKeychainWithIdentifier:SIGNALING_EXTRA_KEY];
[KeychainWrapper deleteItemFromKeychainWithIdentifier:SIGNALING_CIPHER_KEY];
[KeychainWrapper deleteItemFromKeychainWithIdentifier:SAVED_PASSWORD_KEY];
[KeychainWrapper deleteItemFromKeychainWithIdentifier:ZID_KEY];
[KeychainWrapper deleteItemFromKeychainWithIdentifier:LOCAL_NUMBER_KEY];
}
@end

View File

@ -13,6 +13,14 @@
-(NSTimeInterval) getCachedOrDefaultDesiredBufferDepth;
-(void) setCachedDesiredBufferDepth:(double)value;
-(int64_t) getAndIncrementOneTimeCounter;
-(PhoneNumber*) forceGetLocalNumber;
-(PhoneNumber*)tryGetLocalNumber;
-(void) setLocalNumberTo:(PhoneNumber*)localNumber;
-(Zid*) getOrGenerateZid;
-(NSString*) getOrGenerateSavedPassword;
-(NSData*) getOrGenerateSignalingMacKey;
-(NSData*) getOrGenerateSignalingCipherKey;
-(NSData*) getOrGenerateSignalingExtraKey;
-(void) setSettingsRowExpandedPrefs:(NSArray *)prefs;
-(NSArray *) getOrGenerateSettingsRowExpandedPrefs;
-(NSArray *) getAvailableDateFormats;

View File

@ -1,18 +1,29 @@
#import "PreferencesUtil.h"
#import "CryptoTools.h"
#import "Constraints.h"
#import "KeychainWrapper.h"
#import "PhoneNumber.h"
#import "Util.h"
#import "NotificationManifest.h"
#define CALL_STREAM_DES_BUFFER_LEVEL_KEY @"CallStreamDesiredBufferLevel"
#define LOCAL_NUMBER_KEY @"Number"
#define PASSWORD_COUNTER_KEY @"PasswordCounter"
#define SAVED_PASSWORD_KEY @"Password"
#define SIGNALING_MAC_KEY @"Signaling Mac Key"
#define SIGNALING_CIPHER_KEY @"Signaling Cipher Key"
#define ZID_KEY @"ZID"
#define SIGNALING_EXTRA_KEY @"Signaling Extra Key"
#define PHONE_DIRECTORY_BLOOM_FILTER_HASH_COUNT_KEY @"Directory Bloom Hash Count"
#define PHONE_DIRECTORY_BLOOM_FILTER_DATA_KEY @"Directory Bloom Data"
#define PHONE_DIRECTORY_EXPIRATION @"Directory Expiration"
#define DEFAULT_CALL_STREAM_DES_BUFFER_LEVEL 0.5
#define SIGNALING_MAC_KEY_LENGTH 20
#define SIGNALING_CIPHER_KEY_LENGTH 16
#define SAVED_PASSWORD_LENGTH 18
#define SIGNALING_EXTRA_KEY_LENGTH 4
#define SETTINGS_EXPANDED_ROW_PREF_DICT_KEY @"Settings Expanded Row Pref Dict Key"
#define FRESH_INSTALL_TUTORIALS_ENABLED_KEY @"Fresh Install Tutorials Enabled Key"
@ -21,11 +32,6 @@
#define HISTORY_LOG_ENABLED_KEY @"History Log Enabled Key"
#define ANONYMOUS_FEEDBACK_ENABLED_KEY @"Anonymous Feedback Enabled Key"
#define CALL_STREAM_DES_BUFFER_LEVEL_KEY @"CallStreamDesiredBufferLevel"
#define DEFAULT_CALL_STREAM_DES_BUFFER_LEVEL 0.5
#define PASSWORD_COUNTER_KEY @"PasswordCounter"
#define DATE_FORMAT_KEY @"Date Format Key"
#define DATE_FORMAT_1 @"dd-MM-yyyy"
#define DATE_FORMAT_2 @"yyyy-MM-dd"
@ -67,6 +73,20 @@
[[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_DIRECTORY_UPDATE object:nil];
}
-(NSData*) getOrGenerateRandomDataWithKey:(NSString*)key andLength:(NSUInteger)length {
require(key != nil);
return [self secureDataStoreAdjustAndTryGetNewValueForKey:key afterAdjuster:^NSData*(NSData* oldValue) {
if (oldValue != nil) {
requireState([oldValue isKindOfClass:[NSData class]]);
requireState([oldValue length] == length);
return oldValue;
}
return [CryptoTools generateSecureRandomData:length];
}];
}
-(NSTimeInterval) getCachedOrDefaultDesiredBufferDepth {
id v = [self tryGetValueForKey:CALL_STREAM_DES_BUFFER_LEVEL_KEY];
if (v == nil) return DEFAULT_CALL_STREAM_DES_BUFFER_LEVEL;
@ -89,6 +109,49 @@
return oldCounter;
}
-(PhoneNumber*) forceGetLocalNumber {
NSString* localNumber = [self tryGetValueForKey:LOCAL_NUMBER_KEY];
checkOperation(localNumber != nil);
return [PhoneNumber tryParsePhoneNumberFromE164:localNumber];
}
-(void) setLocalNumberTo:(PhoneNumber*)localNumber {
require(localNumber != nil);
[self setValueForKey:LOCAL_NUMBER_KEY toValue:[localNumber toE164]];
}
-(PhoneNumber*)tryGetLocalNumber {
NSString* localNumber = [self tryGetValueForKey:LOCAL_NUMBER_KEY];
return (localNumber != nil ? [PhoneNumber tryParsePhoneNumberFromE164:localNumber] : nil);
}
-(Zid*) getOrGenerateZid {
return [Zid zidWithData:[self getOrGenerateRandomDataWithKey:ZID_KEY andLength:12]];
}
-(NSString*) getOrGenerateSavedPassword {
return [self secureStringStoreAdjustAndTryGetNewValueForKey:SAVED_PASSWORD_KEY afterAdjuster:^NSString*(id oldValue) {
if (oldValue != nil) {
requireState([oldValue isKindOfClass:[NSString class]]);
return oldValue;
}
NSString *string = [[CryptoTools generateSecureRandomData:SAVED_PASSWORD_LENGTH] encodedAsBase64];
return string;
}];
}
-(NSData*) getOrGenerateSignalingMacKey {
return [self getOrGenerateRandomDataWithKey:SIGNALING_MAC_KEY andLength:SIGNALING_MAC_KEY_LENGTH];
}
-(NSData*) getOrGenerateSignalingCipherKey {
return [self getOrGenerateRandomDataWithKey:SIGNALING_CIPHER_KEY andLength:SIGNALING_CIPHER_KEY_LENGTH];
}
-(NSData*) getOrGenerateSignalingExtraKey {
return [self getOrGenerateRandomDataWithKey:SIGNALING_EXTRA_KEY andLength:SIGNALING_EXTRA_KEY_LENGTH];
}
-(void) setSettingsRowExpandedPrefs:(NSArray *)prefs {
[self setValueForKey:SETTINGS_EXPANDED_ROW_PREF_DICT_KEY toValue:prefs];
}

View File

@ -12,4 +12,10 @@
-(id) adjustAndTryGetNewValueForKey:(NSString*)key afterAdjuster:(id (^)(id oldValue))adjuster;
-(void) clear;
-(void) secureTryValueForKey:(NSString *)key toValue:(id)value;
-(NSData*) secureTryGetDataForKey:(NSString *)key;
-(NSString*) secureTryGetStringForKey:(NSString *)key;
-(NSData*) secureDataStoreAdjustAndTryGetNewValueForKey:(NSString *)key afterAdjuster:(id (^)(id))adjuster;
-(NSString*) secureStringStoreAdjustAndTryGetNewValueForKey:(NSString *)key afterAdjuster:(id (^)(id))adjuster;
@end

View File

@ -1,5 +1,6 @@
#import "PropertyListPreferences.h"
#import "Constraints.h"
#import <UICKeyChainStore/UICKeyChainStore.h>
@implementation PropertyListPreferences
@ -72,4 +73,58 @@
}
}
#pragma mark KeyChain store
-(void) secureTrySetValueForKey:(NSString *)key toValue:(id)value {
require(key != nil);
@synchronized(self) {
if (value == nil) {
[UICKeyChainStore removeItemForKey:key];
} else {
if ([value isKindOfClass:[NSData class]]) {
[UICKeyChainStore setData:value forKey:key];
} else if ([value isKindOfClass:[NSString class]]){
[UICKeyChainStore setString:value forKey:key];
}
}
}
}
-(NSData*) secureTryGetDataForKey:(NSString *)key {
require(key != nil);
@synchronized(self) {
return [UICKeyChainStore dataForKey:key];
}
}
-(NSString*) secureTryGetStringForKey:(NSString *)key {
require(key != nil);
@synchronized(self) {
return [UICKeyChainStore stringForKey:key];
}
}
-(NSData*) secureDataStoreAdjustAndTryGetNewValueForKey:(NSString *)key afterAdjuster:(id (^)(id))adjuster {
require(key != nil);
require(adjuster != nil);
@synchronized(self) {
NSData* oldValue = [self secureTryGetDataForKey:key];
NSData* newValue = adjuster(oldValue);
[UICKeyChainStore setData:newValue forKey:key];
return newValue;
}
}
-(NSString*) secureStringStoreAdjustAndTryGetNewValueForKey:(NSString *)key afterAdjuster:(id (^)(id))adjuster {
require(key != nil);
require(adjuster != nil);
@synchronized(self) {
NSString *oldValue = [self secureTryGetStringForKey:key];
NSString *newValue = adjuster(oldValue);
[UICKeyChainStore setString:newValue forKey:key];
return newValue;
}
}
@end

View File

@ -1,6 +1,5 @@
#import "HttpRequestUtil.h"
#import "Constraints.h"
#import "KeyChainStorage.h"
#import "PreferencesUtil.h"
#import "Util.h"
@ -18,8 +17,8 @@
return [HttpRequest httpRequestWithBasicAuthenticationAndMethod:method
andLocation:location
andOptionalBody:optionalBody
andLocalNumber:[KeyChainStorage forceGetLocalNumber]
andPassword:[KeyChainStorage getOrGenerateSavedPassword]];
andLocalNumber:[[[Environment getCurrent] preferences] forceGetLocalNumber]
andPassword:[[[Environment getCurrent] preferences] getOrGenerateSavedPassword]];
}
+(HttpRequest*)httpRequestWithOtpAuthenticationAndMethod:(NSString*)method
andLocation:(NSString*)location {
@ -33,8 +32,8 @@
return [HttpRequest httpRequestWithOtpAuthenticationAndMethod:method
andLocation:location
andOptionalBody:optionalBody
andLocalNumber:[KeyChainStorage forceGetLocalNumber]
andPassword:[KeyChainStorage getOrGenerateSavedPassword]
andLocalNumber:[[[Environment getCurrent] preferences] forceGetLocalNumber]
andPassword:[[[Environment getCurrent] preferences] getOrGenerateSavedPassword]
andCounter:[[[Environment getCurrent] preferences] getAndIncrementOneTimeCounter]];
}
+(HttpRequest*)httpRequestUnauthenticatedWithMethod:(NSString*)method

View File

@ -3,7 +3,6 @@
#import "DH3KKeyAgreementProtocol.h"
#import "Constraints.h"
#import "FunctionalUtil.h"
#import "KeyChainStorage.h"
#import "MasterSecret.h"
#import "Util.h"
#import "ZrtpInitiator.h"
@ -24,7 +23,7 @@
s->allowedKeyAgreementProtocols = [[Environment getCurrent] keyAgreementProtocolsInDescendingPriority];
s->dhSharedSecretHashes = [DhPacketSharedSecretHashes dhPacketSharedSecretHashesRandomized];
s->zid = [KeyChainStorage getOrGenerateZid];
s->zid = [[Environment preferences] getOrGenerateZid];
s->confirmIv = [CryptoTools generateSecureRandomData:IV_LENGTH];
s->hashChain = [HashChain hashChainWithSecureGeneratedData];
s->badPacketLogger = [[Environment logging] getOccurrenceLoggerForSender:self withKey:@"Bad Packet"];

View File

@ -1,7 +1,6 @@
#import "CommitPacket.h"
#import "ConfirmPacket.h"
#import "DH3KKeyAgreementProtocol.h"
#import "KeyChainStorage.h"
#import "PreferencesUtil.h"
#import "FunctionalUtil.h"
#import "MasterSecret.h"
@ -30,7 +29,7 @@
s->badPacketLogger = [[Environment logging] getOccurrenceLoggerForSender:self withKey:@"Bad Packet"];
s->localHello = [HelloPacket helloPacketWithDefaultsAndHashChain:s->hashChain
andZid:[KeyChainStorage getOrGenerateZid]
andZid:[[Environment preferences] getOrGenerateZid]
andKeyAgreementProtocols:s->allowedKeyAgreementProtocols];
s->packetExpectation = EXPECTING_HELLO;
s->callController = callController;

View File

@ -2,7 +2,6 @@
#import "Constraints.h"
#import "CryptoTools.h"
#import "KeyChainStorage.h"
#import "PreferencesUtil.h"
#import "Util.h"
#import "InitiateSignal.pb.h"
@ -88,7 +87,7 @@
checkOperation([data length] >= HMAC_TRUNCATED_SIZE);
NSData* includedMac = [data takeLast:HMAC_TRUNCATED_SIZE];
NSData* payload = [data skipLast:HMAC_TRUNCATED_SIZE];
NSData* signalingMacKey = [KeyChainStorage getOrGenerateSignalingMacKey];
NSData* signalingMacKey = [[Environment preferences] getOrGenerateSignalingMacKey];
NSData* computedMac = [[payload hmacWithSha1WithKey:signalingMacKey] takeLast:HMAC_TRUNCATED_SIZE];
checkOperation([includedMac isEqualToData_TimingSafe:computedMac]);
return payload;
@ -96,7 +95,7 @@
+(NSData*) decryptRemoteNotificationData:(NSData*)data {
require(data != nil);
checkOperation([data length] >= VERSION_SIZE + IV_SIZE);
NSData* cipherKey = [KeyChainStorage getOrGenerateSignalingCipherKey];
NSData* cipherKey = [[Environment preferences] getOrGenerateSignalingCipherKey];
NSData* iv = [data subdataWithRange:NSMakeRange(VERSION_SIZE, IV_SIZE)];
NSData* cipherText = [data skip:VERSION_SIZE+IV_SIZE];
return [cipherText decryptWithAesInCipherBlockChainingModeWithPkcs7PaddingWithKey:cipherKey andIv:iv];

View File

@ -2,7 +2,6 @@
#import "Constraints.h"
#import "Environment.h"
#import "KeyChainStorage.h"
#import "PreferencesUtil.h"
#import "Util.h"
@ -80,12 +79,12 @@
+(HttpRequest*) httpRequestToVerifyAccessToPhoneNumberWithChallenge:(NSString*)challenge {
require(challenge != nil);
PhoneNumber* localPhoneNumber = [KeyChainStorage forceGetLocalNumber];
PhoneNumber* localPhoneNumber = [[Environment preferences] forceGetLocalNumber];
NSString* query = [NSString stringWithFormat:@"/users/verification/%@", [localPhoneNumber toE164]];
NSData* signalingCipherKey = [KeyChainStorage getOrGenerateSignalingMacKey];
NSData* signalingMacKey = [KeyChainStorage getOrGenerateSignalingMacKey];
NSData* signalingExtraKeyData = [KeyChainStorage getOrGenerateSignalingExtraKey];
NSData* signalingCipherKey = [[Environment preferences] getOrGenerateSignalingCipherKey];
NSData* signalingMacKey = [[Environment preferences] getOrGenerateSignalingMacKey];
NSData* signalingExtraKeyData = [[Environment preferences] getOrGenerateSignalingExtraKey];
NSString* encodedSignalingKey = [[@[signalingCipherKey, signalingMacKey, signalingExtraKeyData] concatDatas] encodedAsBase64];
NSString* body = [@{@"key" : encodedSignalingKey, @"challenge" : challenge} encodedAsJson];

View File

@ -1,24 +0,0 @@
#import <Foundation/Foundation.h>
#import <Security/Security.h>
#import <CommonCrypto/CommonHMAC.h>
@interface KeychainWrapper : NSObject
// Generic exposed method to search the keychain for a given value. Limit one result per search.
+ (NSData *)searchKeychainCopyMatchingIdentifier:(NSString *)identifier;
// Calls searchKeychainCopyMatchingIdentifier: and converts to a string value.
+ (NSString *)keychainStringFromMatchingIdentifier:(NSString *)identifier;
// Default initializer to store a value in the keychain.
// Associated properties are handled for you - setting Data Protection Access, Company Identifer (to uniquely identify string, etc).
+ (BOOL)createKeychainValue:(NSString *)value forIdentifier:(NSString *)identifier;
// Updates a value in the keychain. If you try to set the value with createKeychainValue: and it already exists,
// this method is called instead to update the value in place.
+ (BOOL)updateKeychainValue:(NSString *)value forIdentifier:(NSString *)identifier;
// Delete a value in the keychain.
+ (void)deleteItemFromKeychainWithIdentifier:(NSString *)identifier;
@end

View File

@ -1,100 +0,0 @@
#import "KeychainWrapper.h"
@implementation KeychainWrapper
+ (NSMutableDictionary *)setupSearchDirectoryForIdentifier:(NSString *)identifier {
NSMutableDictionary *searchDictionary = [[NSMutableDictionary alloc] init];
[searchDictionary setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
NSDictionary* infoDict = [[NSBundle mainBundle] infoDictionary];
NSString* appName = [infoDict objectForKey:@"CFBundleDisplayName"];
[searchDictionary setObject:appName forKey:(__bridge id)kSecAttrService];
NSData *encodedIdentifier = [identifier dataUsingEncoding:NSUTF8StringEncoding];
[searchDictionary setObject:encodedIdentifier forKey:(__bridge id)kSecAttrGeneric];
[searchDictionary setObject:encodedIdentifier forKey:(__bridge id)kSecAttrAccount];
return searchDictionary;
}
+ (NSData *)searchKeychainCopyMatchingIdentifier:(NSString *)identifier {
NSMutableDictionary *searchDictionary = [self setupSearchDirectoryForIdentifier:identifier];
[searchDictionary setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
[searchDictionary setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
NSData *result = nil;
CFTypeRef foundDict = NULL;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)searchDictionary, &foundDict);
if (status == noErr) {
result = (__bridge_transfer NSData *)foundDict;
} else {
result = nil;
}
return result;
}
+ (NSString *)keychainStringFromMatchingIdentifier:(NSString *)identifier {
NSData *valueData = [self searchKeychainCopyMatchingIdentifier:identifier];
if (valueData) {
NSString *value = [[NSString alloc] initWithData:valueData
encoding:NSUTF8StringEncoding];
return value;
}
else {
return nil;
}
}
+ (BOOL)createKeychainValue:(NSString *)value forIdentifier:(NSString *)identifier {
NSMutableDictionary *dictionary = [self setupSearchDirectoryForIdentifier:identifier];
NSData *valueData = [value dataUsingEncoding:NSUTF8StringEncoding];
[dictionary setObject:valueData forKey:(__bridge id)kSecValueData];
// Protect the keychain entry so it's only valid when the device is unlocked.
[dictionary setObject:(__bridge id)kSecAttrAccessibleWhenUnlocked forKey:(__bridge id)kSecAttrAccessible];
// Add.
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)dictionary, NULL);
// If the addition was successful, return. Otherwise, attempt to update existing key or quit (return NO).
if (status == errSecSuccess) {
return YES;
}
else if (status == errSecDuplicateItem){
return [self updateKeychainValue:value forIdentifier:identifier];
}
else {
return NO;
}
}
+ (BOOL)updateKeychainValue:(NSString *)value forIdentifier:(NSString *)identifier {
NSMutableDictionary *searchDictionary = [self setupSearchDirectoryForIdentifier:identifier];
NSMutableDictionary *updateDictionary = [[NSMutableDictionary alloc] init];
NSData *valueData = [value dataUsingEncoding:NSUTF8StringEncoding];
[updateDictionary setObject:valueData forKey:(__bridge id)kSecValueData];
OSStatus status = SecItemUpdate((__bridge CFDictionaryRef)searchDictionary,
(__bridge CFDictionaryRef)updateDictionary);
if (status == errSecSuccess) {
return YES;
}
else {
return NO;
}
}
+ (void)deleteItemFromKeychainWithIdentifier:(NSString *)identifier {
NSMutableDictionary *searchDictionary = [self setupSearchDirectoryForIdentifier:identifier];
CFDictionaryRef dictionary = (__bridge CFDictionaryRef)searchDictionary;
SecItemDelete(dictionary);
}
@end

View File

@ -1,6 +1,5 @@
#import "Environment.h"
#import "HttpManager.h"
#import "KeyChainStorage.h"
#import "LocalizableText.h"
#import "NBAsYouTypeFormatter.h"
#import "PhoneNumber.h"
@ -122,7 +121,7 @@
-(Future*) asyncRegister:(PhoneNumber*)phoneNumber untilCancelled:(id<CancelToken>)cancelToken {
// @todo: should we force regenerating of all keys?
// @todo: clear current registered status before making a new one, to avoid splinching issues?
[KeyChainStorage setLocalNumberTo:phoneNumber];
[[Environment preferences] setLocalNumberTo:phoneNumber];
CancellableOperationStarter regStarter = ^Future *(id<CancelToken> internalUntilCancelledToken) {
HttpRequest *registerRequest = [HttpRequest httpRequestToStartRegistrationOfPhoneNumber];

View File

@ -1,6 +1,5 @@
#import "Environment.h"
#import "FutureUtil.h"
#import "KeyChainStorage.h"
#import "LocalizableText.h"
#import "Operation.h"
#import "PreferencesUtil.h"
@ -65,7 +64,7 @@ static NSString *const CHECKBOX_EMPTY_IMAGE_NAME = @"checkbox_empty";
#pragma mark - Local number
- (void)configureLocalNumber {
PhoneNumber *localNumber = [KeyChainStorage tryGetLocalNumber];
PhoneNumber *localNumber = [[[Environment getCurrent] preferences] tryGetLocalNumber];
if (localNumber) {
_phoneNumberLabel.attributedText = [self localNumberAttributedStringForNumber:localNumber];
} else {