Programmatically Checking if a Passcode Lock is Set
Since my app would be dealing with sensitive data of the user, I would like to know if there is a way I can check from my app whether there is a Passcode Lock set in iOS.
The reason I need to c开发者_高级运维heck this is because say if the user has in the app some information and then keeps it on the table and goes out for a couple of minutes. The iPad/iPhone by default, goes to standby mode. If a passcode lock had been set, only when the correct passcode is entered, would anyone be able to use the ipad. This would provide an additional security measure to prevent any passerby to view the sensitive data from the app.
So basically, I would like my app to check whether the passcode lock is set and if not prompt the user to do it.
Is this possible?
With iOS 8, there is now a way to check that the user has a passcode set. This code will crash on iOS 7.
Objective-C:
-(BOOL) deviceHasPasscode {
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 };
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)attributes, NULL);
if (status == errSecSuccess) { // item added okay, passcode has been set
SecItemDelete((__bridge CFDictionaryRef)attributes);
return true;
}
return false;
}
Swift:
func deviceHasPasscode() -> Bool {
let secret = "Device has passcode set?".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
let attributes = [kSecClass as String:kSecClassGenericPassword, kSecAttrService as String:"LocalDeviceServices", kSecAttrAccount as String:"NoAccount", kSecValueData as String:secret!, kSecAttrAccessible as String:kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly]
let status = SecItemAdd(attributes, nil)
if status == 0 {
SecItemDelete(attributes)
return true
}
return false
}
Since iOS 9
, there is a flag LAPolicyDeviceOwnerAuthentication
in LocalAuthentication framework.
+ (BOOL)isPasscodeEnabled
{
NSError *error = nil;
LAContext *context = [[LAContext alloc] init];
BOOL passcodeEnabled = [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:&error];
if(passcodeEnabled) {
NSLog(@"Passcode enabled.");
return YES;
}
NSLog(@"Passcode NOT enabled: %@", error.localizedDescription);
return NO;
}
Since iOS 8
there have been another flag for checking if TouchID
is enabled:
+ (BOOL)isTouchIdEnabled
{
NSError *error = nil;
LAContext *context = [[LAContext alloc] init];
BOOL touchIDEnabled = [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error];
if(touchIDEnabled) {
NSLog(@"TouchID enabled.");
return YES;
}
NSLog(@"TouchID NOT enabled: %@", error.localizedDescription);
return NO;
}
Take a look at the File Protection section on The Application Runtime Environment. File protection requires the user to have passcode lock setting enabled and a valid passcode set. If you your application writes/creates and file, use the NSDataWritingFileProtectionComplete option. If your application doesn't use any files, then create a dummy file and enable the protection.
Xamarin.iOS solution for iOS 8...note I call SecKeyChain.Remove(secRecord)
on every check. I found if I didn't include this I could get the device into an odd state where it was trying to authenticate with the user on every call to SecKeyChain.Add(secRecord)
private bool DetectIfPasscodeIsSet ()
{
var secRecord = new SecRecord (SecKind.GenericPassword) {
Label = "Check if passcode is set",
Description = "Check if passcode is set",
Account = "Check if passcode is set",
Service = "Check if passcode is set",
Comment = "Check if passcode is set",
ValueData = NSData.FromString ("Check if passcode is set"),
Generic = NSData.FromString ("Check if passcode is set")
};
SecKeyChain.Remove (secRecord);
secRecord.AccessControl = new SecAccessControl (SecAccessible.WhenPasscodeSetThisDeviceOnly);
var status = SecKeyChain.Add (secRecord);
if (SecStatusCode.Success == status) {
SecKeyChain.Remove (secRecord);
return true;
}
return false;
}
精彩评论