iOS 13.7 - SecureEnclave - Decrypt fails when iPhone is Locked and app is running in background

Hi! I'm having issue with decrypting Data when the app is in background and iPhone gets Locked by the user. The app works as expected when it's in background and the iPhone is NOT Locked.

I'm getting the following error:
Code Block
Unmanaged<CFErrorRef>(_value: Error Domain=NSOSStatusErrorDomain Code=-25308 "setoken: unable to compute shared secret" UserInfo={NSLocalizedDescription=setoken: unable to compute shared secret, AKSError=-536870174})

Here is the code I use to decrypt:
Code Block
     let decryptedData = SecKeyCreateDecryptedData(
      try privateSecKey(),
      .eciesEncryptionStandardVariableIVX963SHA256AESGCM,
      data as CFData,
      &error) as Data?

and encryption code is:
Code Block
     let encryptedData = SecKeyCreateEncryptedData(
      key,
      .eciesEncryptionCofactorVariableIVX963SHA256AESGCM,
      data as CFData,
      &error) as Data?

Query private key for descryption:
Code Block
     let query: [String: Any] = [
      kSecClass as String: kSecClassKey,
      kSecAttrApplicationTag as String: tag,
      kSecAttrKeyType as String: kSecAttrKeyTypeEC,
      kSecReturnRef as String: true
    ]
    var item: CFTypeRef?
    let status = SecItemCopyMatching(query as CFDictionary, &item)

and I create key using
Code Block
     let access = try SecAccessControlCreateWithFlags(
      kCFAllocatorDefault,
      // Since the app is using the key in the app background status (for example during
      // BLE communication), we need a less strict access level.
      kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
      .privateKeyUsage,
      nil).unwrap()
    let tag = try Constants.privateKeyName.data(using: .utf8).unwrap()
    let attributes: [String: Any] = [
      kSecAttrKeyType as String: kSecAttrKeyTypeEC,
      kSecAttrKeySizeInBits as String: 256,
      kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave,
      kSecPrivateKeyAttrs as String: [
        kSecAttrIsPermanent as String: true,
        kSecAttrApplicationTag as String: tag,
        kSecAttrAccessControl as String: access
      ]
    ]
    var error: Unmanaged<CFError>?
    guard let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else {
      let err = try error.unwrap()
      throw err.takeRetainedValue() as Error
    }

The code is compiled as expected and runs normally in foreground and background when iPhone is NOT Locked as mentioned.

Based on my research, the issue could be due to kSecAttrAccessControl, but I clearly set it to kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly and the iPhone I test with is Unlocked before I run the test case.

It looks as OS bug to me, but I might be missing something here.

The test device is iPhone XS MAX.

I would appreciate any help. Thanks!

Accepted Reply

The issue was due to re-using stored key which was generated using another access level policy (whileUnlocked). Since that key persists across app un-installs, it didn't generate a new key with required access level policy (afterFirstUnlock). The fix for it is to just change the label tag to a new one so the key is re-generated.

Replies

The issue was due to re-using stored key which was generated using another access level policy (whileUnlocked). Since that key persists across app un-installs, it didn't generate a new key with required access level policy (afterFirstUnlock). The fix for it is to just change the label tag to a new one so the key is re-generated.

Is there any way, besides full factory reset, to reset/erase Secure Enclave keys? Just wondering about a case where it's impossible to change the ApplicationTag data.

Is there any way, besides full factory reset, to reset/erase Secure Enclave keys?

This question doesn’t really make sense given the way that keys protected by the Secure Enclave actually work. However, it’s also kinda off topic for this thread. If you start a new thread — tag it with Security so that I see it — I should be able to set you straight.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"