8

Is there a certain way to detect if storing in Secure Enclave is available on current device?

kragekjaer
  • 232
  • 4
  • 10

4 Answers4

4

Here is another solution:

Device.h

#import <Foundation/Foundation.h>

@interface Device : NSObject

+(BOOL) hasSecureEnclave;
+(BOOL) isSimulator;
+(BOOL) hasBiometrics;

@end

Device.m

#import "Device.h"
#import <LocalAuthentication/LocalAuthentication.h>

@implementation Device

//To check that device has secure enclave or not
+(BOOL) hasSecureEnclave {
    NSLog(@"IS Simulator : %d", [Device isSimulator]);
    return [Device hasBiometrics] && ![Device isSimulator] ;
}

//To Check that this is this simulator
+(BOOL) isSimulator {
    return TARGET_OS_SIMULATOR == 1;
}

//Check that this device has Biometrics features available
+(BOOL) hasBiometrics {

    //Local Authentication Context
    LAContext *localAuthContext = [[LAContext alloc] init];
    NSError *error = nil;

    /// Policies can have certain requirements which, when not satisfied, would always cause
    /// the policy evaluation to fail - e.g. a passcode set, a fingerprint
    /// enrolled with Touch ID or a face set up with Face ID. This method allows easy checking
    /// for such conditions.
    BOOL isValidPolicy = [localAuthContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error];

    if (isValidPolicy) {

        if (@available(ios 11.0, *)){
            if (error.code != kLAErrorBiometryNotAvailable){
                isValidPolicy = true;
            } else{
                isValidPolicy = false;
            }
        }else{
            if (error.code != kLAErrorTouchIDNotAvailable){
                isValidPolicy = true;
            }else{
                isValidPolicy = false;
            }
        }
        return isValidPolicy;
    }
    return isValidPolicy;
}

@end

If you want solution in Swift 4, then refer this link.

Solution in Swift 4

technerd
  • 14,144
  • 10
  • 61
  • 92
2

For a developer, there is exactly one thing the Secure Enclave can do: Create and hold private keys for elliptic curve cryptography, and encrypt or decrypt data using these keys. On iOS 9, the attributes describing elliptic curve algorithms are not there - therefore, if you are running iOS 9, then you can assume the Secure Enclave is not there, because you cannot use it.

On iOS 10 and above, there is just one way to decide guaranteed correctly if the Secure Enclave is present: Create an elliptic curve encryption key in the Secure Enclave, as described by Apple's documentation. If this fails, and the error has a code of -4 = errSecUnimplemented, then there is no Secure Enclave.

If you insist on checking a list of devices, you only need the devices that are documented as having no Secure Enclave but are able to run iOS 10, because on iOS 9 it is never available.

Pranav Kasetti
  • 8,770
  • 2
  • 50
  • 71
gnasher729
  • 51,477
  • 5
  • 75
  • 98
  • 4
    Hi, while generating EC key using `SecKeyCreateRandomKey` on a simulator, instead of getting an error code, the `SecKeyCreateRandomKey` crashes with EXC_BAD_ACCESS. Code runs fine on a real device that has secure enclave. Any ideas why this might be happening and how I can check for secure enclave instead? Thanks! – SeaJelly Oct 09 '19 at 05:08
0

I did it myself:

+ (BOOL) isDeviceOkForSecureEnclave
    {

    double OSVersionNumber                  = floor(NSFoundationVersionNumber);
    UIUserInterfaceIdiom deviceType         = [[UIDevice currentDevice] userInterfaceIdiom];

    BOOL isOSForSecureEnclave               = OSVersionNumber > NSFoundationVersionNumber_iOS_8_4 ? YES:NO;
    //iOS 9 and up are ready for SE


    BOOL isDeviceModelForSecureEnclave  = NO;

    switch (deviceType) {

        case UIUserInterfaceIdiomPhone:
            //iPhone
            isDeviceModelForSecureEnclave = [self isPhoneForSE];
            break;
        case UIUserInterfaceIdiomPad:
            //iPad
            isDeviceModelForSecureEnclave = [self isPadForSE];

            break;
        default:
            isDeviceModelForSecureEnclave = false;
            break;
    }

    return (isOSForSecureEnclave && isDeviceModelForSecureEnclave) ? YES:NO;
}


/**
 The arrays are models that we know not having SE in hardware, so if the current device is on the list it means it dosent have SE
 */

+ (BOOL) isPhoneForSE
{
    NSString *thisPlatform = [self platform];
    NSArray * oldModels = [NSArray arrayWithObjects:
                           @"x86_64",
                           @"iPhone1,1",
                           @"iPhone1,2",
                           @"iPhone2,1",
                           @"iPhone3,1",
                           @"iPhone3,3",
                           @"iPhone4,1",
                           @"iPhone5,1",
                           @"iPhone5,2",
                           @"iPhone5,3",
                           @"iPhone5,4", nil];

    BOOL isInList = [oldModels containsObject: thisPlatform];
    return !isInList;
}


+ (BOOL) isPadForSE
{
    //iPad Mini 2 is the earliest with SE // "iPad4,4"
    NSString *thisPlatform = [self platform];

    NSArray * oldModels = [NSArray arrayWithObjects:
                           @"x86_64",
                           @"@iPad",
                           @"@iPad1,0",
                           @"@iPad1,1",
                           @"iPad2,1",
                           @"iPad2,2",
                           @"iPad2,3",
                           @"iPad2,4",
                           @"iPad2,5",
                           @"iPad2,6",
                           @"iPad2,7",
                           @"iPad3,1",
                           @"iPad3,2",
                           @"iPad3,3",
                           @"iPad3,4",
                           @"iPad3,5",
                           @"iPad3,6",nil];

    BOOL isInList = [oldModels containsObject: thisPlatform];

    return !isInList;

}


+ (NSString *)platform
{
    size_t size;
    sysctlbyname("hw.machine", NULL, &size, NULL, 0);
    char *machine = malloc(size);
    sysctlbyname("hw.machine", machine, &size, NULL, 0);
    NSString *platform = [NSString stringWithUTF8String:machine];
    free(machine);

    return platform;

}

@end
kragekjaer
  • 232
  • 4
  • 10
  • From what I can see the iPad Air (1st gen) and the iPad mini 2 does not have a secure enclave either. Therefore the iPad exclusion list needs to also include "iPad4,1", "iPad4,4", "iPad4,5", "iPad4,6". Plus remember not iPod touch have a secure enclave so you might also need another list… – wuf810 Sep 26 '17 at 14:42
  • Im not sure if I updated this code, if not hen some models are missing – kragekjaer Oct 03 '17 at 23:54
  • @wuf810 iPad Air (1st gen)s and the iPad mini 2 does have secure enclave. these devices use Apple's A7 processor which is stated to contain Secure Enclave. Anyways, tested and verified on both these devices – Mervyn Ong Dec 15 '17 at 06:52
0

There is a more straightforward way to check if Secure Enclave is available using the CryptoKit framework. The following approach is iOS 13+ and Swift only.

import CryptoKit

if TARGET_OS_SIMULATOR == 0 && SecureEnclave.isAvailable {
    // use Secure Enclave
}

Additional check for Simulator is needed since SecureEnclave.isAvailable returns true running on a Simulator (checked on iOS 14.4).

podkovyr
  • 135
  • 3
  • 11
  • Should have mentioned that this is iOS 13 only. And when it returns true on the simulator, have you checked if that is because it is running on a Mac with Secure Enclave? – gnasher729 Apr 15 '21 at 11:13
  • @gnasher729 Why do you think these were not mentioned? – podkovyr Apr 16 '21 at 12:31
  • "The following approach is iOS 13+ and Swift only." and "Additional check for Simulator is needed since SecureEnclave.isAvailable returns true running on a Simulator (checked on iOS 14.4)." seems like clearly describing your concerns – podkovyr Apr 16 '21 at 12:33
  • 1
    Adding for googleability: SecureEnclave does not work on the simulator. You might get "Error Domain=NSOSStatusErrorDomain Code=-25293 "Key generation failed, error -25293" UserInfo={numberOfErrorsDeep=0, NSDescription=Key generation failed, error -25293}" – Jonas357 Apr 24 '21 at 13:57