Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I check whether the user has set a passcode?

Tags:

security

ios

We have an app that stores sensitive data. We've enabled file protection, but that only has an effect if the user has set a passcode. If the user hasn't set a passcode, we need to show an alert telling the user to do that, and then not to load the rest of the app.

Basically we're in the exact situation as in this question, and my question is exactly their question. But the accepted answer there is "enable file protection", which is not an answer to that question, or to this one; I'm already enabling file protection and it doesn't tell me whether they've set a passcode or not.

So is it possible to check, and if so, how? Ideally we'd like to check whether the user has set a long passcode or a simple one, and if they've only set a simple one we would warn them to set a proper one.

like image 701
Simon Avatar asked Mar 27 '14 09:03

Simon


2 Answers

There is an official answer to this question with iOS 9:

LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;

if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:&authError]) 
{
    // Device has either passcode enable (or passcode and touchID)
} 
else 
{
    // Device does not have a passcode
    // authError can be checked for more infos (is of type LAError)
}

A link to Apple's LAContext class

A note: LAPolicyDeviceOwnerAuthentication is a constant available in iOS 9 only. iOS 8 had LAPolicyDeviceOwnerAuthenticationWithBiometrics available. It can be used to achieve some results but these do not answer your question.

like image 157
Tumata Avatar answered Sep 23 '22 00:09

Tumata


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
}
like image 22
Aaron Bratcher Avatar answered Sep 26 '22 00:09

Aaron Bratcher