我如何才能知道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程是:

  1. 尝试使用该属性集保存钥匙串上的新项目
  2. 如果成功,则表示当前已启用密码
  3. 如果密码没有保存,则表示没有密码
  4. 清理项目,因为如果它已经在钥匙串上,将会使“添加”失败,看起来像密码没有设置

我已经在我的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.deviceOwnerAuthentica‌​tion, error:nil) } 

需要iOS 9或更高版本。