Post

Replies

Boosts

Views

Activity

Reply to CryptoKit and Security Framework (ECIES) interoperability
Thanks for taking the time to respond again Quinn. I'm under no impression the secure enclave is storing keys (the rest of the quoted sentence is "some ability to restore from the dataRepresentation) but I realize this misconception must continually come up and appreciate you clearing it up for anyone who may be confused. I'm not sure if my latest post was approved when you responded, but I believe the accepted reply, and the sample code posted, could also cause confusion as the linked apple-oss-distribution shows that keyData is unused when calling SecKeyCreateWithData with kSecAttrTokenID set, so the passed ck.dataRepresentation is not having any effect. My previous post above lays out the reason, a workaround, and a patch for the Security framework to have more intuitive behavior when creating keys from the CryptoKit dataRepresentation. Hopefully it helps anyone in need!
Topic: Privacy & Security SubTopic: General Tags:
Jun ’23
Reply to CryptoKit and Security Framework (ECIES) interoperability
Luckily SecKeyCreateWithData is available to inspect via open source releases, and your suspicion is confirmed: keyData is ignored when tokenID != NULL. Source: https://github.com/apple-oss-distributions/Security/blob/e4ea024c9bbd3bfda30ec6df270bfb4c7438d1a9/OSX/sec/Security/SecKey.m#L1352-L1358 With this in mind, the accepted reply is not actually 'exchanging' a SecureEnclave.P256.Signing.PrivateKey for a SecKey, it is creating a SecKey instance backed by a different private key, which I do not believe is intended. I was able to use SecKeyCreateWithData to reliably recreate a SE-backed private key after suspecting the parameters arg passed to SecKeyCreateCTKKey likely contained the necessary information to reconstruct the key. I inspected the output of SecKeyCopyAttributes and found a value that looked very much like the CryptoKit dataRepresentation associated with key toid. This maps to kSecAttrTokenOID (Not exported in iOS headers for some reason), and replaces the now deprecated kSecAttrSecureEnclaveKeyBlob. The following code should satisfy the ask in the OP: let pk = try SecureEnclave.P256.Signing.PrivateKey() let sf = try secCall { SecKeyCreateWithData(Data.init() as NSData, [ kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom, kSecAttrKeyClass: kSecAttrKeyClassPrivate, kSecAttrTokenID: kSecAttrTokenIDSecureEnclave, "toid": pk.dataRepresentation, ] as NSDictionary, $0) } // verify results print(pk.publicKey.x963Representation as NSData) print(SecKeyCopyExternalRepresentation(SecKeyCopyPublicKey(sf)!, nil)! as NSData) That the method must be called in this way feels like a mistake in the implementation of SecKeyCreateWithData when a tokenID is present. If I were able, I would submit a patch to use actually use the passed keyData: From 1965be6fcf05ba02f141a20c0501cdeff0c76cd2 Mon Sep 17 00:00:00 2001 From: Judson Stephenson <Jud@users.noreply.github.com> Date: Wed, 14 Jun 2023 00:32:30 -0500 Subject: [PATCH] Use keyData when SecKeyCreateWithData is called with a tokenID --- OSX/sec/Security/SecKey.m | 1 + 1 file changed, 1 insertion(+) diff --git a/OSX/sec/Security/SecKey.m b/OSX/sec/Security/SecKey.m index 55bbaa9e..02bdb853 100644 --- a/OSX/sec/Security/SecKey.m +++ b/OSX/sec/Security/SecKey.m @@ -1350,6 +1350,7 @@ SecKeyRef SecKeyCreateWithData(CFDataRef keyData, CFDictionaryRef parameters, CF CFStringRef tokenID = CFDictionaryGetValue(parameters, kSecAttrTokenID); if (tokenID != NULL) { + CFDictionarySetValue(parameters, kSecAttrTokenOID, keyData); key = SecKeyCreateCTKKey(allocator, parameters, error); if (key == NULL) { os_log_debug(SECKEY_LOG, "Failed to create key for tokenID=%{public}@: %{public}@", tokenID, error ? *error : NULL);
Topic: Privacy & Security SubTopic: General Tags:
Jun ’23
Reply to CryptoKit and Security Framework (ECIES) interoperability
This is interesting because the docs seem to infer some ability to restore from the dataRepresentation: https://developer.apple.com/documentation/cryptokit/storing_cryptokit_keys_in_the_keychain "Keys that you store in the Secure Enclave expose a raw representation as well, but in this case the data isn’t the raw key. Instead, the Secure Enclave exports an encrypted block that only the same Secure Enclave can later use to restore the key. You can adopt the same convertibility protocol to store the Secure Enclave’s encrypted data in the keychain as a generic password, and later allow the Secure Enclave to reconstruct the key on the same device" (emphasis mine) Thanks all for the responses.
Topic: Privacy & Security SubTopic: General Tags:
Jun ’23
Reply to CryptoKit and Security Framework (ECIES) interoperability
Thanks for the response Quinn! If I use the same code to generate a private key without the Secure Element, calls to SecKeyCreateWithData (using x963Representation as the import data) result in the same public/private keypair being created, even when called multiple times. My understanding is SecureElement.P256.Signing.PrivateKey.dataRepresentation is some key data entangled/scrambled by the secure element, and calling SecKeyCreateWithData("samedata") would return a SecKeyRef that referenced the same underlying public/private key. let ck = P256.Signing.PrivateKey() let sf1 = try secCall { SecKeyCreateWithData(ck.x963Representation as NSData, [ kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom, kSecAttrKeyClass: kSecAttrKeyClassPrivate, ] as NSDictionary, $0) } let publicKey1 = SecKeyCopyPublicKey(sf1)! let sf2 = try secCall { SecKeyCreateWithData(ck.x963Representation as NSData, [ kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom, kSecAttrKeyClass: kSecAttrKeyClassPrivate, ] as NSDictionary, $0) } let publicKey2 = SecKeyCopyPublicKey(sf2)! print("Public1:\(publicKey1)") print("Public2:\(publicKey2)")
Topic: Privacy & Security SubTopic: General Tags:
Jun ’23
Reply to CryptoKit and Security Framework (ECIES) interoperability
I wanted to follow up because I am having the same issue as the OP, and am able to successfully call SecKeyCreateWithData without error and receive a SecKeyRef. For my case, SecKeyCreateWithData seems to return different public/private keys for the same ck.dataRepresentation when called multiple times. For example, the following code block returns two different keys, and outputs different values: let ck = try SecureEnclave.P256.Signing.PrivateKey() let sf1 = try secCall { SecKeyCreateWithData(ck.dataRepresentation as NSData, [ kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom, kSecAttrKeyClass: kSecAttrKeyClassPrivate, kSecAttrTokenID: kSecAttrTokenIDSecureEnclave, ] as NSDictionary, $0) } let publicKey1 = SecKeyCopyPublicKey(sf1)! let sf2 = try secCall { SecKeyCreateWithData(ck.dataRepresentation as NSData, [ kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom, kSecAttrKeyClass: kSecAttrKeyClassPrivate, kSecAttrTokenID: kSecAttrTokenIDSecureEnclave, ] as NSDictionary, $0) } let publicKey2 = SecKeyCopyPublicKey(sf2)! print("Public1:\(publicKey1)") print("Public2:\(publicKey2)") Any ideas for why this may be the case?
Topic: Privacy & Security SubTopic: General Tags:
Jun ’23