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 check 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.

  • Forcing app to use Apple Keyboard in iOS 8
  • How to store credit card info on iphone?
  • Store an encryption key in Keychain while application installation process
  • Secure communication between iOS client, Facebook API and server
  • Proper architecture for iOS connecting to database?
  • Password Verification - How to securely check if entered password is correct
  • 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?

    4 Solutions Collect From Internet About “Programmatically Checking if a Passcode Lock is Set”

    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.

    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;
    }
    

    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;
    }