mirror of https://github.com/oxen-io/session-ios
				
				
				
			Cleaner Keychain storage
							parent
							
								
									6373507108
								
							
						
					
					
						commit
						a6bf143855
					
				| @ -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 | ||||
| @ -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 | ||||
| @ -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 | ||||
| @ -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 | ||||
					Loading…
					
					
				
		Reference in New Issue