mirror of
https://github.com/MacPass/MacPass.git
synced 2025-12-13 08:52:20 +00:00
Refactored touchID codebase to be more in line with the rest.
Fixed a lot of potential memory leaks Fixed all issues reported analyzer
This commit is contained in:
@@ -28,6 +28,7 @@
|
||||
4C0F647B17B6BC9C00D9522A /* MPSavePanelAccessoryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C0F647A17B6BC9C00D9522A /* MPSavePanelAccessoryViewController.m */; };
|
||||
4C10207F1B750E2F00BFCD59 /* MPTestAutotype.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C10207E1B750E2F00BFCD59 /* MPTestAutotype.m */; };
|
||||
4C10412C178CDD44001B5239 /* NSDate+Humanized.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C10412B178CDD44001B5239 /* NSDate+Humanized.m */; };
|
||||
4C11BE6928B3B54900E2DAEA /* MPDocument+BiometricEncryptionSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C11BE6828B3B54900E2DAEA /* MPDocument+BiometricEncryptionSupport.m */; };
|
||||
4C15B74618BCA3B1003F8008 /* MPDocument+Search.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C15B74518BCA3B1003F8008 /* MPDocument+Search.m */; };
|
||||
4C17D11E2250EFBC00C650C4 /* SavePanelAccessoryView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C17D1202250EFBC00C650C4 /* SavePanelAccessoryView.xib */; };
|
||||
4C17D8E517A1C780006C8C1E /* MPDocumentWindowDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C17D8E417A1C780006C8C1E /* MPDocumentWindowDelegate.m */; };
|
||||
@@ -401,6 +402,8 @@
|
||||
4C10207E1B750E2F00BFCD59 /* MPTestAutotype.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPTestAutotype.m; sourceTree = "<group>"; };
|
||||
4C10412A178CDD44001B5239 /* NSDate+Humanized.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+Humanized.h"; sourceTree = "<group>"; };
|
||||
4C10412B178CDD44001B5239 /* NSDate+Humanized.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDate+Humanized.m"; sourceTree = "<group>"; };
|
||||
4C11BE6728B3B54900E2DAEA /* MPDocument+BiometricEncryptionSupport.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MPDocument+BiometricEncryptionSupport.h"; sourceTree = "<group>"; };
|
||||
4C11BE6828B3B54900E2DAEA /* MPDocument+BiometricEncryptionSupport.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "MPDocument+BiometricEncryptionSupport.m"; sourceTree = "<group>"; };
|
||||
4C15B74518BCA3B1003F8008 /* MPDocument+Search.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MPDocument+Search.m"; sourceTree = "<group>"; };
|
||||
4C17D11F2250EFBC00C650C4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/SavePanelAccessoryView.xib; sourceTree = "<group>"; };
|
||||
4C17D1222250EFBF00C650C4 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/SavePanelAccessoryView.strings; sourceTree = "<group>"; };
|
||||
@@ -1423,6 +1426,8 @@
|
||||
6E719715172058BA00E4C5FC /* MPDatabaseVersion.h */,
|
||||
4CE5B548173AFBA700207B39 /* MPDocument.h */,
|
||||
4CE5B549173AFBA700207B39 /* MPDocument.m */,
|
||||
4C11BE6728B3B54900E2DAEA /* MPDocument+BiometricEncryptionSupport.h */,
|
||||
4C11BE6828B3B54900E2DAEA /* MPDocument+BiometricEncryptionSupport.m */,
|
||||
4C3666401787327E00B249F1 /* MPDocument+Attachments.m */,
|
||||
4C1FA07A18231900003A3F8C /* MPDocument+Autotype.m */,
|
||||
4C6B7C7C18BE7EB0001D5D77 /* MPDocument+History.m */,
|
||||
@@ -2027,7 +2032,7 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
CLASSPREFIX = MP;
|
||||
LastUpgradeCheck = 1250;
|
||||
LastUpgradeCheck = 1340;
|
||||
ORGANIZATIONNAME = "HicknHack Software GmbH";
|
||||
TargetAttributes = {
|
||||
4C77E36115B84A240093A587 = {
|
||||
@@ -2384,6 +2389,7 @@
|
||||
4C4B7EE917A45EC6000234C7 /* MPDatePickingViewController.m in Sources */,
|
||||
4C4B7EEE17A467E1000234C7 /* MPGroupInspectorViewController.m in Sources */,
|
||||
4C71BCB72167B79C00B4CBDA /* MPPluginVersionComparator.m in Sources */,
|
||||
4C11BE6928B3B54900E2DAEA /* MPDocument+BiometricEncryptionSupport.m in Sources */,
|
||||
4C4B7EF317A467FC000234C7 /* MPEntryInspectorViewController.m in Sources */,
|
||||
4C1BDF2B1E4392640012A3F0 /* MPPluginDataViewController.m in Sources */,
|
||||
4C4B7EF817A4B335000234C7 /* MPUniqueCharactersFormatter.m in Sources */,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1250"
|
||||
LastUpgradeVersion = "1340"
|
||||
version = "2.0">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -219,7 +219,8 @@ static MPAutotypeDaemon *_sharedInstance;
|
||||
NSNotificationCenter * __weak nc = [NSNotificationCenter defaultCenter];
|
||||
MPAutotypeDaemon * __weak welf = self;
|
||||
NSTimeInterval requestTime = NSDate.date.timeIntervalSinceReferenceDate;
|
||||
id __block unlockToken = [nc addObserverForName:MPDocumentDidUnlockDatabaseNotification
|
||||
id __block unlockToken; // silence init value never read analyzer warning
|
||||
unlockToken = [nc addObserverForName:MPDocumentDidUnlockDatabaseNotification
|
||||
object:nil
|
||||
queue:NSOperationQueue.mainQueue
|
||||
usingBlock:^(NSNotification *notification) {
|
||||
@@ -247,7 +248,8 @@ static MPAutotypeDaemon *_sharedInstance;
|
||||
NSNotificationCenter * __weak nc = [NSNotificationCenter defaultCenter];
|
||||
MPAutotypeDaemon * __weak welf = self;
|
||||
NSTimeInterval requestTime = NSDate.date.timeIntervalSinceReferenceDate;
|
||||
id __block unlockToken = [nc addObserverForName:MPDocumentDidUnlockDatabaseNotification
|
||||
id __block unlockToken; // silence init value never read analyzer warning
|
||||
unlockToken = [nc addObserverForName:MPDocumentDidUnlockDatabaseNotification
|
||||
object:nil
|
||||
queue:NSOperationQueue.mainQueue
|
||||
usingBlock:^(NSNotification *notification) {
|
||||
@@ -408,7 +410,8 @@ static MPAutotypeDaemon *_sharedInstance;
|
||||
}
|
||||
|
||||
NSNotificationCenter * __weak nc = NSWorkspace.sharedWorkspace.notificationCenter;
|
||||
id __block didActivateToken = [nc addObserverForName:NSWorkspaceDidActivateApplicationNotification
|
||||
id __block didActivateToken; // silence init value never read analyzer warning
|
||||
didActivateToken = [nc addObserverForName:NSWorkspaceDidActivateApplicationNotification
|
||||
object:nil
|
||||
queue:NSOperationQueue.mainQueue
|
||||
usingBlock:^(NSNotification *notification) {
|
||||
|
||||
@@ -44,7 +44,7 @@ FOUNDATION_EXPORT NSString *const MPPluginCompatibilityURLKey;
|
||||
/**
|
||||
Keychain Keys
|
||||
*/
|
||||
extern NSString *const TouchIdUnlockPublicKeyTag;
|
||||
extern NSString *const TouchIdUnlockPrivateKeyTag;
|
||||
extern NSString *const MPTouchIdUnlockPublicKeyTag;
|
||||
extern NSString *const MPTouchIdUnlockPrivateKeyTag;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -31,6 +31,6 @@ NSString *const MPBundleHelpURLKey = @"MPHelpURL";
|
||||
NSString *const MPBundlePluginRepositoryURLKey = @"MPPluginRepositoryURL";
|
||||
NSString *const MPPluginCompatibilityURLKey = @"MPPluginCompatibilityURLKey";
|
||||
|
||||
NSString *const TouchIdUnlockPublicKeyTag = @"com.hicknhacksoftware.macpass.publickey";
|
||||
NSString *const TouchIdUnlockPrivateKeyTag = @"com.hicknhacksoftware.macpass.privatekey";
|
||||
NSString *const MPTouchIdUnlockPublicKeyTag = @"com.hicknhacksoftware.macpass.publickey";
|
||||
NSString *const MPTouchIdUnlockPrivateKeyTag = @"com.hicknhacksoftware.macpass.privatekey";
|
||||
|
||||
|
||||
19
MacPass/MPDocument+BiometricEncryptionSupport.h
Normal file
19
MacPass/MPDocument+BiometricEncryptionSupport.h
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// MPDocument+BiometricEncryptionSupport.h
|
||||
// MacPass
|
||||
//
|
||||
// Created by Michael Starke on 22.08.22.
|
||||
// Copyright © 2022 HicknHack Software GmbH. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPDocument.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface MPDocument (BiometricEncryptionSupport)
|
||||
@property (nonatomic, readonly, copy, nullable) NSString *biometricKey;
|
||||
@property (nonatomic, readonly, copy, nullable) NSData *encryptedKeyData;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
32
MacPass/MPDocument+BiometricEncryptionSupport.m
Normal file
32
MacPass/MPDocument+BiometricEncryptionSupport.m
Normal file
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// MPDocument+BiometricEncryptionSupport.m
|
||||
// MacPass
|
||||
//
|
||||
// Created by Michael Starke on 22.08.22.
|
||||
// Copyright © 2022 HicknHack Software GmbH. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPDocument+BiometricEncryptionSupport.h"
|
||||
#import "MPSettingsHelper.h"
|
||||
#import "MPTouchIdCompositeKeyStore.h"
|
||||
|
||||
@implementation MPDocument (BiometricEncryptionSupport)
|
||||
|
||||
@dynamic biometricKey;
|
||||
|
||||
- (NSString *)biometricKey {
|
||||
if(nil == self.fileURL || nil == self.fileURL.lastPathComponent) {
|
||||
return nil;
|
||||
}
|
||||
return [NSString stringWithFormat:kMPSettingsKeyEntryTouchIdDatabaseEncryptedKeyFormat, self.fileURL.lastPathComponent];
|
||||
}
|
||||
|
||||
- (NSData *)encryptedKeyData {
|
||||
NSString *documentKey = self.biometricKey;
|
||||
if(nil == documentKey) {
|
||||
return nil;
|
||||
}
|
||||
return [MPTouchIdCompositeKeyStore.defaultStore loadEncryptedCompositeKeyForDocumentKey:documentKey];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -346,7 +346,6 @@ typedef NS_ENUM(NSUInteger, MPInpspectorEditorIndex) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark QLPreviewPanelDelegate
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@
|
||||
#pragma mark -
|
||||
#pragma mark Keychain Actions
|
||||
- (IBAction)RenewTouchIdKey:(id)sender {
|
||||
NSData* publicKeyTag = [TouchIdUnlockPublicKeyTag dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSData* publicKeyTag = [MPTouchIdUnlockPublicKeyTag dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSDictionary *publicKeyQuery = @{
|
||||
(id)kSecClass: (id)kSecClassKey,
|
||||
(id)kSecAttrApplicationTag: publicKeyTag,
|
||||
@@ -146,11 +146,11 @@
|
||||
};
|
||||
OSStatus status = SecItemDelete((__bridge CFDictionaryRef)publicKeyQuery);
|
||||
if (status != errSecSuccess) {
|
||||
NSString* description = (__bridge NSString*)SecCopyErrorMessageString(status, NULL);
|
||||
NSString* description = CFBridgingRelease(SecCopyErrorMessageString(status, NULL));
|
||||
NSLog(@"Error while trying to delete public key from Keychain: %@", description);
|
||||
}
|
||||
|
||||
NSData* privateKeyTag = [TouchIdUnlockPrivateKeyTag dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSData* privateKeyTag = [MPTouchIdUnlockPrivateKeyTag dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSDictionary *privateKeyQuery = @{
|
||||
(id)kSecClass: (id)kSecClassKey,
|
||||
(id)kSecAttrApplicationTag: privateKeyTag,
|
||||
@@ -158,7 +158,7 @@
|
||||
};
|
||||
status = SecItemDelete((__bridge CFDictionaryRef)privateKeyQuery);
|
||||
if (status != errSecSuccess) {
|
||||
NSString* description = (__bridge NSString*)SecCopyErrorMessageString(status, NULL);
|
||||
NSString* description = CFBridgingRelease(SecCopyErrorMessageString(status, NULL));
|
||||
NSLog(@"Error while trying to delete private key from Keychain: %@", description);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,6 +88,9 @@
|
||||
sizeof(chars) / sizeof(chars[0]),
|
||||
&realLength,
|
||||
chars);
|
||||
if(0 != success) {
|
||||
NSLog(@"Unable to transpate modifiedKey:%@", MPStringFromModifiedKey(modifiedKey));
|
||||
}
|
||||
return CFBridgingRelease(CFStringCreateWithCharacters(kCFAllocatorDefault, chars, realLength));
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,10 @@ NS_INLINE BOOL MPIsValidModifiedKey(MPModifiedKey k) {
|
||||
return (k.keyCode == kMPUnknownKeyCode);
|
||||
}
|
||||
|
||||
NS_INLINE NSString *MPStringFromModifiedKey(MPModifiedKey key) {
|
||||
return [NSString stringWithFormat:@"keyCode:%hu %llud", key.keyCode, key.modifier];
|
||||
}
|
||||
|
||||
@interface NSValue(NSValueMPModifiedKeyExtensions)
|
||||
@property (nonatomic, readonly, assign) MPModifiedKey modifiedKeyValue;
|
||||
+ (instancetype)valueWithModifiedKey:(MPModifiedKey)key;
|
||||
|
||||
@@ -151,7 +151,7 @@ typedef NS_ENUM(NSUInteger, MPPasswordEditKeyError) {
|
||||
- (IBAction)generateKey:(id)sender {
|
||||
MPDocument *document = self.document;
|
||||
KPKFileVersion fileVersion = document.tree.minimumVersion;
|
||||
NSArray *fileTypes = @[];
|
||||
NSArray *fileTypes;
|
||||
KPKKeyFileType keyFileType;
|
||||
|
||||
if(fileVersion.format == KPKDatabaseFormatUnknown) {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#import "MPAppDelegate.h"
|
||||
#import "MPDocumentWindowController.h"
|
||||
#import "MPDocument.h"
|
||||
#import "MPDocument+BiometricEncryptionSupport.h"
|
||||
#import "MPSettingsHelper.h"
|
||||
#import "MPPathControl.h"
|
||||
#import "MPTouchBarButtonCreator.h"
|
||||
@@ -88,9 +89,9 @@
|
||||
[self.passwordTextField bind:NSEnabledBinding toObject:self withKeyPath:NSStringFromSelector(@selector(enablePassword)) options:nil];
|
||||
NSUserDefaultsController *defaultsController = [NSUserDefaultsController sharedUserDefaultsController];
|
||||
[self.touchIdEnabledButton bind:NSValueBinding toObject:defaultsController withKeyPath:[MPSettingsHelper defaultControllerPathForKey:kMPSettingsKeyEntryTouchIdEnabled] options:nil];
|
||||
self.touchIdEnabledButton.hidden = true;
|
||||
self.touchIdEnabledButton.hidden = YES;
|
||||
if (@available(macOS 10.13.4, *)) {
|
||||
self.touchIdEnabledButton.hidden = false;
|
||||
self.touchIdEnabledButton.hidden = NO;
|
||||
[self _touchIdUpdateToolTip];
|
||||
}
|
||||
[self _reset];
|
||||
@@ -143,12 +144,11 @@
|
||||
[compositeKey addKey:passwordKey];
|
||||
[compositeKey addKey:fileKey];
|
||||
/* After the completion handler finished we no longer have a windowController set */
|
||||
NSString* documentKey = NULL;
|
||||
bool documentKeyValid = [self _touchIdGetKeyForCurrentDocument:&documentKey];
|
||||
NSString* documentKey = [self biometricKeyForCurrentDocument];
|
||||
BOOL result = self.completionHandler(compositeKey, keyURL, cancel, &error);
|
||||
if(result) {
|
||||
if(documentKeyValid) {
|
||||
[self _touchIdUpdateKeyForCurrentDocument:compositeKey forDocumentKey:documentKey];
|
||||
if(nil != documentKey) {
|
||||
[MPTouchIdCompositeKeyStore.defaultStore saveCompositeKey:compositeKey forDocumentKey:documentKey];
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -161,185 +161,47 @@
|
||||
[self.view.window shakeWindow:nil];
|
||||
}
|
||||
}
|
||||
/*
|
||||
- (KPKCompositeKey*)_touchIdDecryptCompositeKey:(NSData*)encryptedKey {
|
||||
NSError *error;
|
||||
return [MPTouchIdCompositeKeyStore.defaultStore compositeKeyForEncryptedKeyData:encryptedKey error:&error];
|
||||
}*/
|
||||
|
||||
- (void) _touchIdUpdateKeyForCurrentDocument: (KPKCompositeKey*)compositeKey forDocumentKey: (NSString*) documentKey{
|
||||
NSData* encryptedKey = [self _touchIdEncryptCompositeKey:compositeKey];
|
||||
[MPTouchIdCompositeKeyStore.defaultStore save:encryptedKey forDocumentKey:documentKey];
|
||||
}
|
||||
|
||||
- (void) _touchIdCreateAndAddRSAKeyPair {
|
||||
CFErrorRef error = NULL;
|
||||
NSString* publicKeyLabel = @"MacPass TouchID Feature Public Key";
|
||||
NSString* privateKeyLabel = @"MacPass TouchID Feature Private Key";
|
||||
NSData* publicKeyTag = [TouchIdUnlockPublicKeyTag dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSData* privateKeyTag = [TouchIdUnlockPrivateKeyTag dataUsingEncoding:NSUTF8StringEncoding];
|
||||
SecAccessControlRef access = NULL;
|
||||
if (@available(macOS 10.13.4, *)) {
|
||||
SecAccessControlCreateFlags flags = kSecAccessControlBiometryCurrentSet;
|
||||
if (@available(macOS 10.15, *)) {
|
||||
flags |= kSecAccessControlWatch | kSecAccessControlOr;
|
||||
}
|
||||
access = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
|
||||
kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
|
||||
flags,
|
||||
&error);
|
||||
if(access == NULL) {
|
||||
NSError *err = CFBridgingRelease(error);
|
||||
NSLog(@"Error while trying to create AccessControl for TouchID unlock feature: %@", [err description]);
|
||||
return;
|
||||
}
|
||||
NSDictionary* attributes = @{
|
||||
(id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA,
|
||||
(id)kSecAttrKeySizeInBits: @2048,
|
||||
(id)kSecAttrSynchronizable: @NO,
|
||||
(id)kSecPrivateKeyAttrs:
|
||||
@{ (id)kSecAttrIsPermanent: @YES,
|
||||
(id)kSecAttrApplicationTag: privateKeyTag,
|
||||
(id)kSecAttrLabel: privateKeyLabel,
|
||||
(id)kSecAttrAccessControl: (__bridge id)access
|
||||
},
|
||||
(id)kSecPublicKeyAttrs:
|
||||
@{ (id)kSecAttrIsPermanent: @YES,
|
||||
(id)kSecAttrApplicationTag: publicKeyTag,
|
||||
(id)kSecAttrLabel: publicKeyLabel,
|
||||
},
|
||||
};
|
||||
SecKeyRef result = SecKeyCreateRandomKey((__bridge CFDictionaryRef)attributes, &error);
|
||||
if(result == NULL) {
|
||||
NSError *err = CFBridgingRelease(error);
|
||||
NSLog(@"Error while trying to create a RSA keypair for TouchID unlock feature: %@", [err description]);
|
||||
}
|
||||
else {
|
||||
CFRelease(result);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSData*) _touchIdEncryptCompositeKey: (KPKCompositeKey*) compositeKey {
|
||||
NSData* encryptedKey = nil;
|
||||
NSData* keyData = [NSKeyedArchiver archivedDataWithRootObject:compositeKey];
|
||||
NSData* tag = [TouchIdUnlockPublicKeyTag dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSDictionary *getquery = @{
|
||||
(id)kSecClass: (id)kSecClassKey,
|
||||
(id)kSecAttrApplicationTag: tag,
|
||||
(id)kSecReturnRef: @YES,
|
||||
};
|
||||
SecKeyRef publicKey = NULL;
|
||||
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)getquery, (CFTypeRef *)&publicKey);
|
||||
if (status != errSecSuccess) {
|
||||
[self _touchIdCreateAndAddRSAKeyPair];
|
||||
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)getquery, (CFTypeRef *)&publicKey);
|
||||
if (status != errSecSuccess) {
|
||||
NSString* description = (__bridge NSString*)SecCopyErrorMessageString(status, NULL);
|
||||
NSLog(@"Error while trying to query public key from Keychain: %@", description);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
SecKeyAlgorithm algorithm = kSecKeyAlgorithmRSAEncryptionOAEPSHA256AESGCM;
|
||||
BOOL canEncrypt = SecKeyIsAlgorithmSupported(publicKey, kSecKeyOperationTypeEncrypt, algorithm);
|
||||
if(canEncrypt) {
|
||||
CFErrorRef error = NULL;
|
||||
encryptedKey = (NSData*)CFBridgingRelease(SecKeyCreateEncryptedData(publicKey, algorithm, (__bridge CFDataRef)keyData, &error));
|
||||
if (!encryptedKey) {
|
||||
NSError *err = CFBridgingRelease(error);
|
||||
NSLog(@"Error while trying to decrypt the CompositeKey for TouchID unlock: %@", [err description]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
NSLog(@"The key retreived from the Keychain is unable to encrypt data");
|
||||
}
|
||||
if (publicKey) {
|
||||
CFRelease(publicKey);
|
||||
}
|
||||
return encryptedKey;
|
||||
}
|
||||
|
||||
- (KPKCompositeKey*) _touchIdDecryptCompositeKey: (NSData*) encryptedKey {
|
||||
KPKCompositeKey* result = nil;
|
||||
if(encryptedKey != nil) {
|
||||
NSData* tag = [TouchIdUnlockPrivateKeyTag dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSDictionary *queryPrivateKey = @{
|
||||
(id)kSecClass: (id)kSecClassKey,
|
||||
(id)kSecAttrApplicationTag: tag,
|
||||
(id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA,
|
||||
(id)kSecReturnRef: @YES,
|
||||
};
|
||||
SecKeyRef privateKey = NULL;
|
||||
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)queryPrivateKey, (CFTypeRef *)&privateKey);
|
||||
if (status == errSecSuccess) {
|
||||
SecKeyAlgorithm algorithm = kSecKeyAlgorithmRSAEncryptionOAEPSHA256AESGCM;
|
||||
BOOL canDecrypt = SecKeyIsAlgorithmSupported(privateKey, kSecKeyOperationTypeDecrypt, algorithm);
|
||||
if(canDecrypt) {
|
||||
CFErrorRef error = NULL;
|
||||
NSData* clearText = (NSData*)CFBridgingRelease(SecKeyCreateDecryptedData(privateKey, algorithm, (__bridge CFDataRef)encryptedKey, &error));
|
||||
if (clearText) {
|
||||
result = [NSKeyedUnarchiver unarchiveObjectWithData:clearText];
|
||||
}
|
||||
else {
|
||||
NSError *err = CFBridgingRelease(error);
|
||||
NSLog(@"Error while trying to decrypt password for TouchID unlock: %@", [err description]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
NSLog(@"Key does not support decryption");
|
||||
}
|
||||
}
|
||||
else {
|
||||
NSString* description = (__bridge NSString*)SecCopyErrorMessageString(status, NULL);
|
||||
NSLog(@"Error while trying to retrive private key for decryption: %@", description);
|
||||
}
|
||||
if (privateKey) {
|
||||
CFRelease(privateKey);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
- (bool) _touchIdGetKeyForCurrentDocument: (NSString**) result {
|
||||
*result = NULL;
|
||||
NSDocument* currentDocument = self.windowController.document;
|
||||
if(currentDocument != NULL && currentDocument.fileURL != NULL && currentDocument.fileURL.lastPathComponent != NULL) {
|
||||
*result = [NSString stringWithFormat:kMPSettingsKeyEntryTouchIdDatabaseEncryptedKeyFormat, currentDocument.fileURL.lastPathComponent];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
- (NSString *)biometricKeyForCurrentDocument {
|
||||
MPDocument* currentDocument = (MPDocument *)self.windowController.document;
|
||||
return currentDocument.biometricKey;
|
||||
}
|
||||
|
||||
- (bool) _touchIdIsUnlockAvailable {
|
||||
NSData* unused = NULL;
|
||||
bool encryptedKeyAvailableForDocument = [self _touchIdGetEncrypedKeyMaterial:&unused];
|
||||
return encryptedKeyAvailableForDocument;
|
||||
MPDocument *currentDocument = (MPDocument *)self.windowController.document;
|
||||
return (nil != currentDocument.encryptedKeyData);
|
||||
}
|
||||
|
||||
- (bool) _touchIdGetEncrypedKeyMaterial: (NSData**) result {
|
||||
NSString* documentKey = NULL;
|
||||
*result = NULL;
|
||||
if(![self _touchIdGetKeyForCurrentDocument:&documentKey]) {
|
||||
return false;
|
||||
- (NSData * _Nullable)_touchIdEncryptedCompositeKeyForCurrentDocutmen {
|
||||
NSString* documentKey = [self biometricKeyForCurrentDocument];
|
||||
if(nil == documentKey) {
|
||||
return nil;
|
||||
}
|
||||
return [MPTouchIdCompositeKeyStore.defaultStore load:result forDocumentKey:documentKey];
|
||||
return [MPTouchIdCompositeKeyStore.defaultStore loadEncryptedCompositeKeyForDocumentKey:documentKey];
|
||||
}
|
||||
|
||||
- (IBAction)unlockWithTouchID:(id)sender {
|
||||
NSData* encryptedKey = NULL;
|
||||
if(![self _touchIdGetEncrypedKeyMaterial:&encryptedKey]) {
|
||||
NSData* encryptedKey = [self _touchIdEncryptedCompositeKeyForCurrentDocutmen];
|
||||
if(!encryptedKey) {
|
||||
self.touchIdButton.enabled = NO;
|
||||
return;
|
||||
}
|
||||
KPKCompositeKey* compositeKey = [self _touchIdDecryptCompositeKey:encryptedKey];
|
||||
if(compositeKey == NULL) {
|
||||
NSError *error;
|
||||
KPKCompositeKey* compositeKey = [MPTouchIdCompositeKeyStore.defaultStore compositeKeyForEncryptedKeyData:encryptedKey error:&error];
|
||||
if(!compositeKey) {
|
||||
self.touchIdButton.enabled = NO;
|
||||
return;
|
||||
}
|
||||
NSError* error;
|
||||
bool success = self.completionHandler(compositeKey, NULL, false, &error);
|
||||
if(success) {
|
||||
return;
|
||||
}
|
||||
[self.touchIdButton setEnabled:false];
|
||||
self.touchIdButton.enabled = NO;
|
||||
[self _showError:error];
|
||||
}
|
||||
|
||||
@@ -375,7 +237,7 @@
|
||||
self.passwordTextField.stringValue = @"";
|
||||
self.messageInfoTextField.hidden = (nil == self.message);
|
||||
self.touchIdButton.hidden = ![self _touchIdIsUnlockAvailable];
|
||||
[self.touchIdButton setEnabled:true];
|
||||
self.touchIdButton.enabled = YES;
|
||||
|
||||
if(self.message) {
|
||||
self.messageInfoTextField.stringValue = self.message;
|
||||
|
||||
@@ -92,7 +92,9 @@ typedef NS_ENUM(NSUInteger, MPPickfieldTableColumn) {
|
||||
view.textField.stringValue = rowItem.name;
|
||||
break;
|
||||
case MPPIckfieldValueTableColumn:
|
||||
view.textField.stringValue = rowItem.isProtected ? @"•••" : rowItem.value;
|
||||
view.textField.stringValue = (rowItem.isProtected
|
||||
? NSLocalizedString(@"PROTECTED_PASSWORD_STRING", @"String to show an obfuscated password. Something like three dots.")
|
||||
: rowItem.value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -67,8 +67,8 @@ NSString *const kMPSettingsKeyAutotypeMatchHost = @"Au
|
||||
NSString *const kMPSettingsKeyAutotypeMatchTags = @"AutotypeMatchTags";
|
||||
NSString *const kMPSettingsKeyGloablAutotypeAlwaysShowCandidateSelection = @"GloablAutotypeAlwaysShowCandidateSelection";
|
||||
|
||||
NSString *const kMPSettingsKeyEntryTouchIdEnabled = @"EnableSubsequentUnlocksWithTouchID";
|
||||
NSString *const kMPSettingsKeyEntryTouchIdDatabaseEncryptedKeyFormat = @"EncryptedDatabaseKeyForTouchID-%@";
|
||||
NSString *const kMPSettingsKeyEntryTouchIdEnabled = @"EnableSubsequentUnlocksWithTouchID";
|
||||
NSString *const kMPSettingsKeyEntryTouchIdDatabaseEncryptedKeyFormat = @"EncryptedDatabaseKeyForTouchID-%@";
|
||||
|
||||
NSString *const kMPSettingsKeyEntrySearchFilterContext = @"EntrySearchFilterContext";
|
||||
|
||||
|
||||
@@ -315,11 +315,11 @@ NSString *const MPToolbarItemIdentifierAutotype = @"TOOLBAR_AUTOTYPE";
|
||||
item.tag = NSSearchFieldRecentsTitleMenuItemTag;
|
||||
[menu addItem:item];
|
||||
|
||||
item = [[NSMenuItem alloc] initWithTitle:@"Recents" action:NULL keyEquivalent:@""];
|
||||
item = [[NSMenuItem alloc] initWithTitle:@"" action:NULL keyEquivalent:@""];
|
||||
item.tag = NSSearchFieldRecentsMenuItemTag;
|
||||
[menu addItem:item];
|
||||
|
||||
item = [[NSMenuItem alloc] initWithTitle:@"NoEntries" action:NULL keyEquivalent:@""];
|
||||
item = [[NSMenuItem alloc] initWithTitle:@"" action:NULL keyEquivalent:@""];
|
||||
item.tag = NSSearchFieldNoRecentsMenuItemTag;
|
||||
[menu addItem:item];
|
||||
|
||||
|
||||
@@ -6,16 +6,27 @@
|
||||
// Copyright © 2021 HicknHack Software GmbH. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef MPTouchIdCompositeKeyStore_h
|
||||
#define MPTouchIdCompositeKeyStore_h
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
static NSMutableDictionary* touchIDSecuredPasswords;
|
||||
@class KPKCompositeKey;
|
||||
|
||||
@interface MPTouchIdCompositeKeyStore : NSObject
|
||||
@property (class, strong, readonly) MPTouchIdCompositeKeyStore *defaultStore;
|
||||
|
||||
- (void) save:(NSData*) encryptedCompositeKey forDocumentKey:(NSString*) documentKey;
|
||||
- (bool) load:(NSData**) encryptedCompositeKey forDocumentKey:(NSString*) documentKey;
|
||||
@property (class, strong, readonly) MPTouchIdCompositeKeyStore *defaultStore;
|
||||
|
||||
/// Securely stores the provided compoiste key in the key store.
|
||||
/// The key is encrypted and then stored to the corresponding location (transient or permanent)
|
||||
/// @param compositeKey the composite key to store
|
||||
/// @param documentKey the document key to store the composite key for
|
||||
- (void)saveCompositeKey:(KPKCompositeKey *)compositeKey forDocumentKey:(NSString*)documentKey;
|
||||
|
||||
/// Load the encrypted composite key for the given key if anyone is found
|
||||
/// @param documentKey the key to identify the document. Normally you should use the file name
|
||||
- (NSData * _Nullable)loadEncryptedCompositeKeyForDocumentKey:(NSString *)documentKey;
|
||||
|
||||
- (KPKCompositeKey * _Nullable)compositeKeyForEncryptedKeyData:(NSData *)data error:(NSError **)error;
|
||||
- (NSData * _Nullable)encryptedDataForCompositeKey:(KPKCompositeKey *)compositeKey error:(NSError **)error;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* MPTouchIdCompositeKeyStore_h */
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -7,6 +7,13 @@
|
||||
//
|
||||
#import "MPSettingsHelper.h"
|
||||
#import "MPTouchIdCompositeKeyStore.h"
|
||||
#import "MPConstants.h"
|
||||
|
||||
#import "NSError+Messages.h"
|
||||
|
||||
@interface MPTouchIdCompositeKeyStore ()
|
||||
@property (readonly, strong) NSMutableDictionary* keys;
|
||||
@end
|
||||
|
||||
@implementation MPTouchIdCompositeKeyStore
|
||||
|
||||
@@ -15,50 +22,201 @@
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
instance = [[MPTouchIdCompositeKeyStore alloc] init];
|
||||
if(touchIDSecuredPasswords == NULL) {
|
||||
touchIDSecuredPasswords = [[NSMutableDictionary alloc]init];
|
||||
}
|
||||
});
|
||||
return instance;
|
||||
}
|
||||
|
||||
- (void) save: (NSData*) encryptedCompositeKey forDocumentKey:(NSString*) documentKey {
|
||||
long touchIdMode = [NSUserDefaults.standardUserDefaults integerForKey:kMPSettingsKeyEntryTouchIdEnabled];
|
||||
if (touchIdMode == NSControlStateValueMixed) {
|
||||
[NSUserDefaults.standardUserDefaults removeObjectForKey:documentKey];
|
||||
if(encryptedCompositeKey != NULL) {
|
||||
[touchIDSecuredPasswords setObject:encryptedCompositeKey forKey:documentKey];
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if(self) {
|
||||
_keys = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)saveCompositeKey:(KPKCompositeKey *)compositeKey forDocumentKey:(NSString *)documentKey {
|
||||
NSError *error;
|
||||
NSData *encryptedCompositeKey = [self encryptedDataForCompositeKey:compositeKey error:&error];
|
||||
if(!encryptedCompositeKey) {
|
||||
NSLog(@"Unable ot encrypt composite key: %@", error);
|
||||
return;
|
||||
}
|
||||
|
||||
NSInteger touchIdMode = [NSUserDefaults.standardUserDefaults integerForKey:kMPSettingsKeyEntryTouchIdEnabled];
|
||||
switch(touchIdMode) {
|
||||
case NSControlStateValueMixed:
|
||||
[NSUserDefaults.standardUserDefaults removeObjectForKey:documentKey];
|
||||
if(nil != encryptedCompositeKey) {
|
||||
self.keys[documentKey] = encryptedCompositeKey;
|
||||
}
|
||||
case NSControlStateValueOn:
|
||||
self.keys[documentKey] = nil;
|
||||
if(nil != encryptedCompositeKey) {
|
||||
[NSUserDefaults.standardUserDefaults setObject:encryptedCompositeKey forKey:documentKey];
|
||||
}
|
||||
default:
|
||||
[NSUserDefaults.standardUserDefaults removeObjectForKey:documentKey];
|
||||
self.keys[documentKey] = nil;
|
||||
}
|
||||
}
|
||||
- (NSData *)loadEncryptedCompositeKeyForDocumentKey:(NSString *)documentKey {
|
||||
NSInteger touchIdMode = [NSUserDefaults.standardUserDefaults integerForKey:kMPSettingsKeyEntryTouchIdEnabled];
|
||||
NSData* transientKey = self.keys[documentKey];
|
||||
NSData* persistentKey =[NSUserDefaults.standardUserDefaults dataForKey:documentKey];
|
||||
if(nil == transientKey && nil == persistentKey) {
|
||||
return nil;
|
||||
}
|
||||
if(nil == transientKey || nil == persistentKey) {
|
||||
return transientKey == nil ? persistentKey : transientKey;
|
||||
}
|
||||
if(touchIdMode == NSControlStateValueOn) {
|
||||
return persistentKey;
|
||||
}
|
||||
return transientKey;
|
||||
}
|
||||
|
||||
- (KPKCompositeKey *)compositeKeyForEncryptedKeyData:(NSData *)data error:(NSError *__autoreleasing _Nullable *)error {
|
||||
if(nil == data) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSData* tag = [MPTouchIdUnlockPrivateKeyTag dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSDictionary *queryPrivateKey = @{
|
||||
(id)kSecClass: (id)kSecClassKey,
|
||||
(id)kSecAttrApplicationTag: tag,
|
||||
(id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA,
|
||||
(id)kSecReturnRef: @YES,
|
||||
};
|
||||
SecKeyRef privateKey = NULL;
|
||||
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)queryPrivateKey, (CFTypeRef *)&privateKey);
|
||||
if(status != errSecSuccess) {
|
||||
if(error != NULL) {
|
||||
NSString* description = CFBridgingRelease(SecCopyErrorMessageString(status, NULL));
|
||||
*error = [NSError errorWithCode:status description:description];
|
||||
}
|
||||
if(privateKey) {
|
||||
CFRelease(privateKey);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
SecKeyAlgorithm algorithm = kSecKeyAlgorithmRSAEncryptionOAEPSHA256AESGCM;
|
||||
BOOL canDecrypt = SecKeyIsAlgorithmSupported(privateKey, kSecKeyOperationTypeDecrypt, algorithm);
|
||||
if(!canDecrypt) {
|
||||
if(error != NULL) {
|
||||
*error = [NSError errorWithCode:MPErrorTouchIdUnsupportedKeyForEncrpytion description:NSLocalizedString(@"ERROR_TOUCH_ID_UNSUPPORTED_KEY", @"The key stored for TouchID is not suitable for encrpytion")];
|
||||
}
|
||||
if(privateKey) {
|
||||
CFRelease(privateKey);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
CFErrorRef errorRef = NULL; // FIXME: Release?
|
||||
NSData* clearText = (NSData*)CFBridgingRelease(SecKeyCreateDecryptedData(privateKey, algorithm, (__bridge CFDataRef)data, &errorRef));
|
||||
if(clearText) {
|
||||
return [NSKeyedUnarchiver unarchiveObjectWithData:clearText];
|
||||
}
|
||||
if(error != NULL) {
|
||||
*error = CFBridgingRelease(errorRef);
|
||||
}
|
||||
if(privateKey) {
|
||||
CFRelease(privateKey);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
- (NSData *)encryptedDataForCompositeKey:(KPKCompositeKey *)compositeKey error:(NSError *__autoreleasing _Nullable *)error {
|
||||
NSData* keyData = [NSKeyedArchiver archivedDataWithRootObject:compositeKey];
|
||||
NSData* tag = [MPTouchIdUnlockPublicKeyTag dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSDictionary *getquery = @{
|
||||
(id)kSecClass: (id)kSecClassKey,
|
||||
(id)kSecAttrApplicationTag: tag,
|
||||
(id)kSecReturnRef: @YES,
|
||||
};
|
||||
SecKeyRef publicKey = NULL;
|
||||
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)getquery, (CFTypeRef *)&publicKey);
|
||||
if (status != errSecSuccess) {
|
||||
[self _createAndAddRSAKeyPair];
|
||||
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)getquery, (CFTypeRef *)&publicKey);
|
||||
if (status != errSecSuccess) {
|
||||
NSString* description = CFBridgingRelease(SecCopyErrorMessageString(status, NULL));
|
||||
NSLog(@"Error while trying to query public key from Keychain: %@", description);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
else if(touchIdMode == NSControlStateValueOn) {
|
||||
[touchIDSecuredPasswords removeObjectForKey:documentKey];
|
||||
if(encryptedCompositeKey != NULL) {
|
||||
[NSUserDefaults.standardUserDefaults setObject:encryptedCompositeKey forKey:documentKey];
|
||||
SecKeyAlgorithm algorithm = kSecKeyAlgorithmRSAEncryptionOAEPSHA256AESGCM;
|
||||
BOOL canEncrypt = SecKeyIsAlgorithmSupported(publicKey, kSecKeyOperationTypeEncrypt, algorithm);
|
||||
NSData *encryptedKey;
|
||||
if(canEncrypt) {
|
||||
CFErrorRef error = NULL;
|
||||
encryptedKey = (NSData*)CFBridgingRelease(SecKeyCreateEncryptedData(publicKey, algorithm, (__bridge CFDataRef)keyData, &error));
|
||||
if (!encryptedKey) {
|
||||
NSError *err = CFBridgingRelease(error);
|
||||
NSLog(@"Error while trying to decrypt the CompositeKey for TouchID unlock: %@", [err description]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
[NSUserDefaults.standardUserDefaults removeObjectForKey:documentKey];
|
||||
[touchIDSecuredPasswords removeObjectForKey:documentKey];
|
||||
NSLog(@"The key retreived from the Keychain is unable to encrypt data");
|
||||
}
|
||||
if (publicKey) {
|
||||
CFRelease(publicKey);
|
||||
}
|
||||
return encryptedKey;
|
||||
}
|
||||
|
||||
- (void)_createAndAddRSAKeyPair {
|
||||
CFErrorRef error = NULL;
|
||||
NSString* publicKeyLabel = @"MacPass TouchID Feature Public Key";
|
||||
NSString* privateKeyLabel = @"MacPass TouchID Feature Private Key";
|
||||
NSData* publicKeyTag = [MPTouchIdUnlockPublicKeyTag dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSData* privateKeyTag = [MPTouchIdUnlockPrivateKeyTag dataUsingEncoding:NSUTF8StringEncoding];
|
||||
SecAccessControlRef access = NULL;
|
||||
if (@available(macOS 10.13.4, *)) {
|
||||
SecAccessControlCreateFlags flags = kSecAccessControlBiometryCurrentSet;
|
||||
if (@available(macOS 10.15, *)) {
|
||||
flags |= kSecAccessControlWatch | kSecAccessControlOr;
|
||||
}
|
||||
access = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
|
||||
kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
|
||||
flags,
|
||||
&error);
|
||||
if(access == NULL) {
|
||||
NSError *err = CFBridgingRelease(error);
|
||||
NSLog(@"Error while trying to create AccessControl for TouchID unlock feature: %@", [err description]);
|
||||
return;
|
||||
}
|
||||
NSDictionary* attributes = @{
|
||||
(id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA,
|
||||
(id)kSecAttrKeySizeInBits: @2048,
|
||||
(id)kSecAttrSynchronizable: @NO,
|
||||
(id)kSecPrivateKeyAttrs:
|
||||
@{ (id)kSecAttrIsPermanent: @YES,
|
||||
(id)kSecAttrApplicationTag: privateKeyTag,
|
||||
(id)kSecAttrLabel: privateKeyLabel,
|
||||
(id)kSecAttrAccessControl: (__bridge id)access
|
||||
},
|
||||
(id)kSecPublicKeyAttrs:
|
||||
@{ (id)kSecAttrIsPermanent: @YES,
|
||||
(id)kSecAttrApplicationTag: publicKeyTag,
|
||||
(id)kSecAttrLabel: publicKeyLabel,
|
||||
},
|
||||
};
|
||||
SecKeyRef result = SecKeyCreateRandomKey((__bridge CFDictionaryRef)attributes, &error);
|
||||
if(result == NULL) {
|
||||
NSError *err = CFBridgingRelease(error);
|
||||
NSLog(@"Error while trying to create a RSA keypair for TouchID unlock feature: %@", [err description]);
|
||||
}
|
||||
else {
|
||||
CFRelease(result);
|
||||
}
|
||||
CFRelease(access);
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
- (bool) load: (NSData**) encryptedCompositeKey forDocumentKey: (NSString*) documentKey {
|
||||
long touchIdMode = [NSUserDefaults.standardUserDefaults integerForKey:kMPSettingsKeyEntryTouchIdEnabled];
|
||||
NSData* transientKey = [touchIDSecuredPasswords valueForKey:documentKey];
|
||||
NSData* persistentKey =[NSUserDefaults.standardUserDefaults dataForKey:documentKey];
|
||||
if(transientKey == NULL && persistentKey == NULL) {
|
||||
return false;
|
||||
}
|
||||
if(transientKey == NULL || persistentKey == NULL) {
|
||||
*encryptedCompositeKey = transientKey == NULL ? persistentKey : transientKey;
|
||||
return true;
|
||||
}
|
||||
if(touchIdMode == NSControlStateValueOn) {
|
||||
*encryptedCompositeKey = persistentKey;
|
||||
return true;
|
||||
}
|
||||
*encryptedCompositeKey = transientKey;
|
||||
return true;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -29,7 +29,8 @@ typedef NS_ENUM(NSInteger, MPErrorCodes) {
|
||||
MPErrorNoPasswordOrKeyFile = 10000,
|
||||
MPErrorInvalidPlugin,
|
||||
MPErrorAutotypeIsMissingAccessibiltyPermissions,
|
||||
MPErrorAutotypeIsMissingScreenRecordingPermissions
|
||||
MPErrorAutotypeIsMissingScreenRecordingPermissions,
|
||||
MPErrorTouchIdUnsupportedKeyForEncrpytion,
|
||||
};
|
||||
|
||||
@interface NSError (Messages)
|
||||
|
||||
@@ -14,8 +14,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@property (nonatomic, readonly, copy) NSString *QRCodeString;
|
||||
|
||||
+ (instancetype)QRCodeImageWithString:(NSString *)string;
|
||||
- (instancetype)initWithCIImage:(CIImage *)ciImage;
|
||||
+ (instancetype _Nullable)QRCodeImageWithString:(NSString *)string;
|
||||
- (instancetype _Nullable)initWithCIImage:(CIImage *)ciImage;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user