我如何才能知道iPhone用户目前是否有密码设置和encryptionfunction?
我正在写一个iPhone应用程序,要求对其数据进行encryption。 我已经学会了如何通过设置NSFileProtectionComplete属性来打开文件的encryption。 我也知道如何检查iPhone版本,以确保它们运行的是iOS 4.0或更高版本。
我已经意识到,如果用户没有select密码,并且没有在设置>常规>密码locking屏幕上专门启用数据保护,那么数据实际上不受保护。
我想popup一个警告,并告诉用户他们必须启用密码并打开数据保护(需要在前4个iPhone上进行备份和恢复),然后退出应用程序(如果他们没有密码的话)并启用数据保护。 无论如何,我无法弄清楚这些设置的状态。 我发现的所有API,比如UIApplication中的“protectedDataAvailable”,如果数据保护被禁用,所有API都会成功。
免责声明:这个答案是有效的,直到ios 4.3.3
如果启用了数据保护,则默认情况下,新创build的文件将具有nil
NSFileProtectionKey
。
如果数据保护被closures,则默认情况下新创build的文件将具有NSFileProtectionNone
NSFileProtectionKey
。
因此,您可以使用以下代码检测文件保护的存在:
NSString *tmpDirectoryPath = [NSHomeDirectory() stringByAppendingPathComponent:@"tmp"]; NSString *testFilePath = [tmpDirectoryPath stringByAppendingPathComponent:@"testFile"]; [@"" writeToFile:testFilePath atomically:YES encoding:NSUTF8StringEncoding error:NULL]; // obviously, do better error handling NSDictionary *testFileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:testFile1Path error:NULL]; BOOL fileProtectionEnabled = [NSFileProtectionNone isEqualToString:[testFile1Attributes objectForKey:NSFileProtectionKey]];
iOS 8(OS X Yosemite)引入了一个新的API /常量来检测用户的设备是否有密码。
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
可用于检测设备上是否设置了密码。
stream程是:
- 尝试使用该属性集保存钥匙串上的新项目
- 如果成功,则表示当前已启用密码
- 如果密码没有保存,则表示没有密码
- 清理项目,因为如果它已经在钥匙串上,将会使“添加”失败,看起来像密码没有设置
我已经在我的iPhone 5S上testing了这个,首先它返回true
,然后我在设置中禁用密码,并返回false
。 最后,我重新启用了密码,它返回true
。 以前的操作系统版本将返回false
。 代码在模拟器中工作,在设置了OS X密码的机器上返回true
(我还没有testing备用的OS X场景)。
另请参阅示例项目在这里: https : //github.com/project-imas/passcode-check/pull/5
最后,据我所知,iOS 8没有禁用数据保护的设置,所以我认为这是保证encryption所需的一切。
BOOL isAPIAvailable = (&kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly != NULL); // Not available prior to iOS 8 - safe to return false rather than crashing if(isAPIAvailable) { // From http://pastebin.com/T9YwEjnL NSData* secret = [@"Device has passcode set?" dataUsingEncoding:NSUTF8StringEncoding]; NSDictionary *attributes = @{ (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, (__bridge id)kSecAttrService: @"LocalDeviceServices", (__bridge id)kSecAttrAccount: @"NoAccount", (__bridge id)kSecValueData: secret, (__bridge id)kSecAttrAccessible: (__bridge id)kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly }; // Original code claimed to check if the item was already on the keychain // but in reality you can't add duplicates so this will fail with errSecDuplicateItem // if the item is already on the keychain (which could throw off our check if // kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly was not set) OSStatus status = SecItemAdd((__bridge CFDictionaryRef)attributes, NULL); if (status == errSecSuccess) { // item added okay, passcode has been set NSDictionary *query = @{ (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, (__bridge id)kSecAttrService: @"LocalDeviceServices", (__bridge id)kSecAttrAccount: @"NoAccount" }; status = SecItemDelete((__bridge CFDictionaryRef)query); return true; } // errSecDecode seems to be the error thrown on a device with no passcode set if (status == errSecDecode) { return false; } } return false;
PS正如苹果在WWDCvideo中所指出的(引用711钥匙串和Touch IDvalidation),他们select不通过API直接使用密码状态,以防止应用程序进入他们不应该be(即“这个设备是否有密码?好吧,好的,我将以纯文本的forms存储这个私人信息”。创build一个encryption密钥,将其存储在kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
并encryption该文件会更好如果用户决定禁用他们的密码,则不可恢复)。
Apple不提供确定用户是否具有密码设置的方法。
如果您的应用程序需要encryption,则应考虑使用受信任的encryption实现来encryption和解密文件,并提示用户input密码或将密钥存储在钥匙串中。
无论NSDataWritingAtomic或NSDataWritingFileProtectionComplete,结果对我来说都是一样的。 奇怪的行为,这里是代码:
BOOL expandTilde = YES; NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, expandTilde); NSString *filePath; filePath = [[paths lastObject] stringByAppendingPathComponent:@"passcode-check"]; NSMutableData *testData; testData = [NSMutableData dataWithLength:1024]; NSLog(@"Attempt to write data of length %u file: %@", [testData length], filePath); NSError *error = nil; if (![testData writeToFile:filePath options:NSDataWritingAtomic error:&error]) { NSLog(@"Unresolved error %@, %@", error, [error userInfo]); return NO; } else { NSLog(@"File write successful."); error = nil; NSDictionary *testFileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:&error]; NSLog(@"Getting attributes: %@", testFileAttributes); if ([NSFileProtectionComplete isEqualToString:[testFileAttributes objectForKey:NSFileProtectionKey]]) { error = nil; [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error]; // passcode disabled return YES; } else { error = nil; [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error]; return NO; } }
从iOS 9开始 ,在LocalAuthentication框架中有一个标志LAPolicyDeviceOwnerAuthentication 。
+ (BOOL)isPasscodeEnabled { NSError *error = nil; LAContext *context = [[LAContext alloc] init]; BOOL passcodeEnabled = [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:&error]; if(passcodeEnabled) { return YES; } return NO; }
Swift 3
func isPasscodeEnabled() -> Bool { return LAContext().canEvaluatePolicy(LAPolicy.deviceOwnerAuthentication, error:nil) }
需要iOS 9或更高版本。