Simon
Simon

Reputation: 25984

Can I check whether the user has set a passcode?

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.

Upvotes: 7

Views: 4384

Answers (2)

Tumata
Tumata

Reputation: 1600

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.

Upvotes: 11

Aaron Bratcher
Aaron Bratcher

Reputation: 6451

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
}

Upvotes: 4

Related Questions