General:
Apple Platform Security support document
Security Overview
Cryptography:
DevForums tags: Security, Apple CryptoKit
Security framework documentation
Apple CryptoKit framework documentation
Common Crypto man pages — For the full list of pages, run:
% man -k 3cc
For more information about man pages, see Reading UNIX Manual Pages.
On Cryptographic Key Formats DevForums post
SecItem attributes for keys DevForums post
CryptoCompatibility sample code
Keychain:
DevForums tags: Security
Security > Keychain Items documentation
TN3137 On Mac keychain APIs and implementations
SecItem Fundamentals DevForums post
SecItem Pitfalls and Best Practices DevForums post
Investigating hard-to-reproduce keychain problems DevForums post
Smart cards and other secure tokens:
DevForums tag: CryptoTokenKit
CryptoTokenKit framework documentation
Mac-specific frameworks:
DevForums tags: Security Foundation, Security Interface
Security Foundation framework documentation
Security Interface framework documentation
Related:
Networking Resources — This covers high-level network security, including HTTPS and TLS.
Network Extension Resources — This covers low-level network security, including VPN and content filters.
Code Signing Resources
Notarisation Resources
Trusted Execution Resources — This includes Gatekeeper.
App Sandbox Resources
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Apple CryptoKit
RSS for tagPerform cryptographic operations securely and efficiently using Apple CryptoKit.
Posts under Apple CryptoKit tag
21 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
I've tried all kinds of ways to get a SecKeyRef from the .p8 file I downloaded from my App Store Connect account. The key itself looks OK, as openssl gives this result:
openssl asn1parse -in 359UpAdminKey.p8
0:d=0 hl=3 l= 147 cons: SEQUENCE
3:d=1 hl=2 l= 1 prim: INTEGER :00
6:d=1 hl=2 l= 19 cons: SEQUENCE
8:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey
17:d=2 hl=2 l= 8 prim: OBJECT :prime256v1
27:d=1 hl=2 l= 121 prim: OCTET STRING [HEX DUMP]:30...
My method for creating the key is:
'- (SecKeyRef)privateKeyFromP8:(NSURL *)p8FileURL error:(NSError **)error {
// Read the .p8 file
NSData *p8Data = [NSData dataWithContentsOfURL:p8FileURL options:0 error:error];
if (!p8Data) {
return NULL;
}
// Convert P8 to base64 string, removing header/footer
NSString *p8String = [[NSString alloc] initWithData:p8Data encoding:NSUTF8StringEncoding];
NSArray *lines = [p8String componentsSeparatedByString:@"\n"];
NSMutableString *base64String = [NSMutableString string];
for (NSString *line in lines) {
if (![line containsString:@"PRIVATE KEY"]) {
[base64String appendString:line];
}
}
// Decode base64 to raw key data
NSData *keyData = [[NSData alloc] initWithBase64EncodedString:base64String options:0];
if (!keyData) {
if (error) {
*error = [NSError errorWithDomain:@"P8ImportError"
code:1
userInfo:@{NSLocalizedDescriptionKey: @"Failed to decode base64 data"}];
}
return NULL;
}
// Set up key parameters
NSDictionary *attributes = @{
(__bridge NSString *)kSecAttrKeyType: (__bridge NSString *)kSecAttrKeyTypeECSECPrimeRandom,
(__bridge NSString *)kSecAttrKeyClass: (__bridge NSString *)kSecAttrKeyClassPrivate,
(__bridge NSString *)kSecAttrKeySizeInBits: @256
};
// Create SecKeyRef from the raw key data
CFErrorRef keyError = NULL;
SecKeyRef privateKey = SecKeyCreateWithData((__bridge CFDataRef)p8Data,
(__bridge CFDictionaryRef)attributes,
&keyError);
if (!privateKey && keyError) {
*error = (__bridge_transfer NSError *)keyError;
NSError *bridgeError = (__bridge NSError *)keyError;
if (error) {
*error = bridgeError; // Pass the bridged error back to the caller
}
NSLog(@"Key Error: %@", bridgeError.localizedDescription);
}
return privateKey;
}
`
I get this error from SecKeyCreateWithData
The operation couldn’t be completed. (OSStatus error -50 - EC private key creation from data failed)
Filed a DTS incident, but they won't be back until after the New Year.
I've tried all kinds of things. Various AI chatbots, etc. Nothing seems to be working. I'm sure the problem is something elementary, but have spent hours on this with no luck.
Help, please.
I'm currently working on a project in Swift where I need to digitally sign a PDF file. I have the following resources available:
Private Key stored in the iOS Keychain with a tag. Public Key also stored in the iOS Keychain with a tag. A valid certificate stored as a PEM string. I need to digitally sign a PDF file with the above keys and certificate, but I'm struggling to find a clear and straightforward example or guidance on how to achieve this in Swift.
Specifically, I’m looking for help with:
Creating the digital signature using the private key and certificate. Embedding this signature into the PDF file. Any considerations I should be aware of regarding the format of the signed PDF (e.g., CMS, PKCS7, etc.). If anyone has experience with digitally signing PDFs in Swift, I would greatly appreciate your guidance or code examples.
Thank you in advance!
Our app is getting rejected from the app store because we don't allow users to delete their accounts. However, we use a non-custodial auth provider, Web3Auth, so no user accounts are generated, and no data is stored. How are we supposed to allow users to delete an account that doesn't exist?
I am using the Secure Enclave to generate private keys with kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly and SecAccessControlCreateFlags.biometryCurrentSet. The public key is derived from the Secure Enclave private key at creation and stored in the Keychain for later retrieval.
During testing, I observed the following:
When the device's passcode is removed, the public key stored in the Keychain is deleted as expected.
However, the private key in the Secure Enclave can still be fetched using SecItemCopyMatching, despite being tied to the passcode for protection.
My questions are:
Is this behavior expected?
How does the Secure Enclave manage private keys in scenarios where the passcode is removed?
Is there a way to ensure that the Secure Enclave private key is deleted entirely (not just rendered inaccessible) when the passcode is removed?
Any clarification or relevant documentation references would be very helpful. Thank you!
I am trying to generate public and private keys for an ECDH handshake.
Back end is using p256 for public key. I am getting a failed request with status 0
public func makeHandShake(completion: @escaping (Bool, String?) -> ()) {
guard let config = self.config else { completion(false,APP_CONFIG_ERROR)
return
}
var rData = HandshakeRequestTwo()
let sessionValue = AppUtils().generateSessionID()
rData.session = sessionValue
//generating my ECDH Key Pair
let sPrivateKey = P256.KeyAgreement.PrivateKey()
let sPublicKey = sPrivateKey.publicKey
let privateKeyBase64 = sPrivateKey.rawRepresentation.base64EncodedString()
print("My Private Key (Base64): \(privateKeyBase64)")
let publicKeyBase64 = sPublicKey.rawRepresentation.base64EncodedString()
print("My Public Key (Base64): \(publicKeyBase64)")
rData.value = sPublicKey.rawRepresentation.base64EncodedString()
let encoder = JSONEncoder()
do {
let jsonData = try encoder.encode(rData)
if let jsonString = String(data: jsonData, encoding: .utf8) {
print("Request Payload: \(jsonString)")
}
} catch {
print("Error encoding request model to JSON: \(error)")
completion(false, "Error encoding request model")
return
}
self.rsaReqResponseHandler(config: config, endpoint: config.services.handShake.endpoint, model: rData) { resToDecode, error in
print("Response received before guard : \(resToDecode ?? "No response")")
guard let responseString = resToDecode else {
print("response string is nil")
completion(false,error)
return
}
print("response received: \(responseString)")
let decoder = JSONDecoder()
do {
let request = try decoder.decode(DefaultResponseTwo.self, from: Data(responseString.utf8))
let msg = request.message
let status = request.status == 1 ? true : false
completion(status,msg)
guard let serverPublicKeyBase64 = request.data?.value else {
print("Server response is missing the value")
completion(false, config.messages.serviceError)
return
}
print("Server Public Key (Base64): \(serverPublicKeyBase64)")
if serverPublicKeyBase64.isEmpty {
print("Server public key is an empty string.")
completion(false, config.messages.serviceError)
return
}
guard let serverPublicKeyData = Data(base64Encoded: serverPublicKeyBase64) else {
print("Failed to decode server public key from Base64. Data is invalid.")
completion(false, config.messages.serviceError)
return
}
print("Decoded server public key data: \(serverPublicKeyData)")
guard let serverPublicKey = try? P256.KeyAgreement.PublicKey(rawRepresentation: serverPublicKeyData) else {
print("Decoded server public key data is invalid for P-256 format.")
completion(false, config.messages.serviceError)
return
}
// Derive Shared Secret and AES Key
let sSharedSecret = try sPrivateKey.sharedSecretFromKeyAgreement(with: serverPublicKey)
// Derive AES Key from Shared Secret
let symmetricKey = sSharedSecret.hkdfDerivedSymmetricKey(
using: SHA256.self,
salt: "AES".data(using: .utf8) ?? Data(),
sharedInfo: Data(),
outputByteCount: 32
)
// Storing AES Key in Config
let symmetricKeyBase64 = symmetricKey.withUnsafeBytes { Data($0) }.base64EncodedString()
print("Derived Key: \(symmetricKeyBase64)")
self.config?.cryptoConfig.key = symmetricKeyBase64
AppUtils.Log(from: self, with: "Handshake Successful, AES Key Established")
} catch {
AppUtils.Log(from: self, with: "Handshake Failed :: \(error)")
completion(false, self.config?.messages.serviceError)
}
}
} this is request struct model public struct HandshakeRequestTwo: Codable {
public var session: String?
public var value: String?
public enum CodingKeys: CodingKey {
case session
case value
}
public init(session: String? = nil, value: String? = nil) {
self.session = session
self.value = value
}
} This is backend's response {"message":"Success","status":1,"data":{"senderId":"POSTBANK","value":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAErLxbfQzX+xnYVT1LLP5VOKtkMRVPRCoqYHcCRTM64EMEOaRU16yzsN+2PZMJc0HpdKNegJQZMmswZtg6U9JGVw=="}} This is my response struct model public struct DefaultResponseTwo: Codable {
public var message: String?
public var status: Int?
public var data: HandshakeData?
public init(message: String? = nil, status: Int? = nil, data: HandshakeData? = nil) {
self.message = message
self.status = status
self.data = data
}
}
public struct HandshakeData: Codable {
public var senderId: String?
public var value: String?
public init(senderId: String? = nil, value: String? = nil) {
self.senderId = senderId
self.value = value
}
}
Hello, I have a public key of type Curve25519.KeyAgreement.PublicKey that I create from the raw representation using:
Curve25519.KeyAgreement.PublicKey(rawRepresentation: Data(base64Encoded: "08sYq4gExgX+UApEwLaASkE+TZjAxG1FPYaT+mj2irk=")!)
I'm trying to convert that key to a curve, but I don't see an equivalent function in CryptoKit for the Javascript function pk_to_curve25519. Can someone please help?
For completeness, I'm trying to implement the handshake protocol that's a part of secure scuttlebutt. https://ssbc.github.io/scuttlebutt-protocol-guide/
Hi, I try to decrypt some string. Does this code looks good? I get error: CryptoKit.CryptoKitError error 3.
do {
guard let encryptedData = Data(base64Encoded: cardNumber),
let securityKeyData = Data(base64Encoded: securityKey),
let ivData = Data(base64Encoded: iv),
let privateKeyData = Data(base64Encoded: privateKey) else {
throw NSError(domain: "invalid_input", code: 1, userInfo: [NSLocalizedDescriptionKey: "Invalid Base64 input."])
}
let privateKey = try P256.KeyAgreement.PrivateKey(derRepresentation: privateKeyData)
let publicKey = try P256.KeyAgreement.PublicKey(derRepresentation: securityKeyData)
let sharedSecret = try privateKey.sharedSecretFromKeyAgreement(with: publicKey)
let symmetricKey = sharedSecret.hkdfDerivedSymmetricKey(
using: SHA256.self,
salt: Data(),
sharedInfo: Data(),
outputByteCount: 32
)
let encryptedDataWithoutTag = encryptedData.dropLast(16)
let tagData = encryptedData.suffix(16)
let nonce = try AES.GCM.Nonce(data: ivData)
let sealedBox = try AES.GCM.SealedBox(nonce: nonce, ciphertext: encryptedDataWithoutTag, tag: tagData)
let decryptedData = try AES.GCM.open(sealedBox, using: symmetricKey)
resolve(decryptedCardNumber)
} catch {
print("Decryption failed with error: \(error.localizedDescription)")
reject("decryption_error", "Decryption failed with error: \(error.localizedDescription)", nil)
}
I am creating a key, such as:
let key = SymmetricKey(size: SymmetricKeySize.bits256)
Is it possible for another developer to simply decrypt my files with using CryptoKit ... or how do I provide my own key to ensure that can't happen?
Thanks !
If I encrypt user data with Apple's newly released homomorphic encryption package and send it to servers I control for analysis, how would that affect the privacy label for that app?
E.g. If my app collected usage data plus identifiers, then sent it for collection and analysis, would I be allowed to say that we don't collect information linked to the user? Does it also automatically exclude the relevant fields from the "Data used to track you" section?
Is it possible to make even things that were once considered inextricably tied to a user identity (e.g. purchases in an in-app marketplace) something not linked, according to Apple's rules?
How would I prove to Apple that the relevant information is indeed homomorphically encrypted?
Hi,
Is there some reference documentation about the properties of a CryptoKit SecureEnclave PrivateKey and its properties?
Concretely, these are some of the questions that I wanted to find a (documented) answer on:
Who can use a SecureEnclave.P256.*.PrivateKey if they have access to the dataRepresentation? I expect that the private key is bound to the specific secure enclave processor, but it also seems to be bound for the user that created the key (from observation by creating a PrivateKey without any access control). What if there's a restore from backup of the machine, will the private key still be usable?
What does a SecureEnclave.P256.*.PrivateKey's dataRepresentation include? From observation, I'm assuming the dataRepresentation is a signed/encrypted blob that includes a unique ID (no 2 keys are the same), the access control settings (biometry required, passcode required, ...), some sort of version of the biometry (so it is be invalidated when the biometry changes). Is there anything else? I'm not interested in the actual encoding (which I understand is undocumented), but want to get an idea of what properties are included in the representation and e.g. can't change in the future.
Answers to these questions could e.g. help make a decision how secure the private key's dataRepresentation needs to be kept (e.g. if it can only be used by myself, and i'm sure it will only ever be valid with the access control flags its representation contains, I could decide it's ok to have this key be in a public place)
I tried looking for answers in some pieces of documentation, but couldn't immediately find the details I was looking for:
The CryptoKit SecureEnclave documentation
The Secure Enclave article
The Protecting keys with the Secure Enclave article
thanks!
Remko
I have a unique need here and hope there is someone out there that might be of help. There is a backend server that will send an x509 certificate and private key (as strings) after the mobile apps on-boarding process.
Additionally, the app includes an AWS SDK that is used to talk to their IoT system. This SDK requires PKCS12 certificate format to pass authentication. (I believe the common method is to have bundled the cert into the app which is not an option for me here sadly)
I suspect it may be possible to use some openSSL iOS framework to do this conversion at runtime but have not personally tried it yet as my go-to is usually trying things first with Apples APIs.
So my question becomes is there a way to meet this requirement using any of the security APIs or other APIs that apple has like swift-nio-ssl? Thank you very much for your time.
Best,
Michael
In my iOS app, I'm planning to use CryptoKit to decrypt a data file downloaded remotely from my backend servers. I'm only using standard cryptography provided by iOS itself (Swift CryptoKit framework).
According to App Store Connect documentation:
"You're required to provide documentation if your app contains any of the following:
Encryption algorithms that are proprietary or not accepted as standard by international standard bodies (IEEE, IETF, ITU, etc.)
Standard encryption algorithms instead of, or in addition to, using or accessing the encryption within Apple's operating system"
I assume that since I am only using cryptography provided by the underlying OS itself, I can safely set ITSAppUsesNonExemptEncryption to NO.
Can someone provide me with some guidance or opinion?
Thank you!
I have an app that creates a private key in the secure enclave with a unique alias. It is created with the kSecAttrTokenIDSecureEnclave flag.
According to the docs, such private keys should never leave the enclave under any circumstances and definitely not restored on new devices.
After migrating to a new iPhone 15 the app does not offer to create a new private key in the enclave, but rather it is able to find the unique alias of the private key in the new phone. i.e. as if it found the private key on the new phone's secure enclave
I believe (/hope) that in practice the object I get in the new iPhone from SecItemCopyMatching is not usable.
I assume this is a bug that should be fixed by apple?
How can I detect that this SecItemCopyMatching result is stale so I can ignore it and prompt the user to create a new keypair on the secure enclave?
Thanks
Hello!
the other day I had troubles with running the application to interact with the Secure Enclave. (https://developer.apple.com/forums/thread/748611?page=1#783968022)
While my program is running perfectly fine now, I still have questions regarding its security.
QUESTIONS:
Is there any functionality just with the public key to get an evidence of a corresponding private key to be protected by the Secure Enclave without showing the source code?
Even with the most recent update of iOS 17.4, there is still no way to directly access the functionality of a Secure Element itself, is that right? So far I found a function SecureElementPass, and it seems like it’s the only interaction possible.
What is the difference between using Security API and Apple CryptoKit? I heard some were saying it the matter of habit and device support, but I still would like to hear an opinion of a professional.
Any information regarding that will be helpful. Thank you in advance for your time and effort!
G'day all,
I'm working through the creation of a cross-platform decryption implementation for CryptoKit's HPKE and wish to use the Sender & Recipient type.
I have been able to engineer the derived key, but the missing link is the nonce that is created and utilised by HPKE.Sender.seal(). I understand that I could create the key exchange and sealed box by myself and set my own random nonce, but I want to be able to utilise the HPKE.Sender.seal() functions to assist with this as well as create ciphertext data externally that can be opened with HPKE.Recipient.open().
By looking at Apple's open-source code available here, I can see that it seems to be exporting a key based on a "base_nonce" label on the context, which I think is what HPKE.Sender's exportSecret(context:outputByteCount:) can achieve.
However using senders exportSecret(context:outputByteCount:) in the following way:
let noncedata = try hpkeSender.exportSecret(context: Data("base_nonce".utf8), outputByteCount: 12)
even just for one message (so the sequence number would be 0 and thus this data block unchanged), the AES-GCM implementation still returns a "cipher: message authentication failed" error. This is specifically in Go, but can be replicated in Python easily. I'm confident that the derived key is correct and is being fed to AES-GCM with the ciphertext correctly, and it's just the nonce generation that is not understood.
Is it possible?
The original key was generated and stored in the Keychain using the following code:
func generateSecureEnclaveProtectedSecKey(withTag tag: Data) throws -> SecKey {
var error: Unmanaged<CFError>?
let accessControl = SecAccessControlCreateWithFlags(
kCFAllocatorDefault,
kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
[.privateKeyUsage],
&error
)!
let attributes = [
kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom,
kSecAttrKeySizeInBits as String: 256,
kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave,
kSecPrivateKeyAttrs as String: [
kSecAttrCanSign as String: true,
kSecAttrIsPermanent as String: true,
kSecAttrApplicationTag as String: tag,
kSecAttrAccessControl as String: accessControl,
] as [String: Any],
] as [String: Any]
let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error)!
return privateKey
}
Then I wanted to use the strongly typed interface of CryptoKit, so I naively tried to get a hold of the existing key as follows (querying for kSecReturnPersistentRef and not kSecReturnRef):
func getSecureEnclaveProtectedCryptoKitKey(fromSecureEnclaveProtectedSecKeyWithTag tag: Data) throws -> SecureEnclave.P256.Signing.PrivateKey {
let query: [String: Any] = [
kSecClass as String: kSecClassKey,
kSecAttrApplicationTag as String: tag,
kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom,
kSecReturnPersistentRef as String: true,
]
var item: CFTypeRef?
let status = SecItemCopyMatching(query as CFDictionary, &item)
let keyData = item as! CFData
return try SecureEnclave.P256.Signing.PrivateKey(dataRepresentation: keyData as Data)
}
But that resulted in:
Error Domain=CryptoTokenKit Code=-3 "corrupted objectID detected" UserInfo={NSLocalizedDescription=corrupted objectID detected}
Since this is a Secure Enclave protected key, it is not possible to use SecKeyCopyExternalRepresentation (or query for kSecReturnData), but perhaps there is another way to convert a SecKey object to a SecureEnclave.P256.Signing.PrivateKey?
The other way around seem to be possible using the answers to this blog post: https://developer.apple.com/forums/thread/728314
I am trying to communicate with a Java server over TCP, but I'm having issues trying to make the data secure in transit using RSA and AES. The server creates an AES key, encodes it in utf8, and sends it to the IOS Client, where it should be decoded back into a byte array as a Data object. Then, Using the Cryptokit framework, I try to create a SecKey object from it. I am stumped when trying to do so, though:
func createSecKeyFromAESKeyData(aesKeyData: Data) -> SecKey? {
// Define the key attributes
let keyAttributes: [CFString: Any] = [
kSecAttrKeyClass: kSecAttrKeyClassSymmetric,
kSecAttrKeySizeInBits: 128,
kSecAttrIsPermanent: false
]
// Convert the AES key data into a SecKey object
var error: Unmanaged<CFError>?
guard let key = SecKeyCreateWithData(aesKeyData as CFData, keyAttributes as CFDictionary, &error) else {
if let error = error {
print("Error creating SecKey: \(error.takeRetainedValue() as Error)")
} else {
print("Unknown error creating SecKey")
}
return nil
}
return key
}
Despite setting up my key attribute dictionary with the correct information (AES_128_GCM_SHA256, 128 bits, impermanent) based on how I generate it in the Java code, I keep getting a runtime error at the SecKeyCreateWithData call stating "Unsupported symmetric key type: 4865". I am unsure what this means and how to fix it as there doesn't seem to be any information on it online. If it helps, the Java code is using AES GCM with no padding, and we have confirmed that the data being sent is indeed 128 bits. How can I take this byte array and create a SecKey from it properly so we can pass secure data?
Similarly, I have also tried using RSA encryption for some data, but with this method, I generate the key pair on the iOS client and send the parts of the public key to the Java server where it (seemingly correctly) created the cipher from the passed data. However, trying to send anything encrypted back resulted in "RSAdecrypt wrong input (err -27)" when decrypting:
func decryptAESKey(encryptedKeyData: Data, privateKey: SecKey) -> Data? {
// Decrypt the received AES key using the private key
var error: Unmanaged<CFError>?
guard let decryptedKeyData = SecKeyCreateDecryptedData(privateKey, .rsaEncryptionOAEPSHA256, encryptedKeyData as CFData, &error) as Data? else {
print("Error decrypting AES key:", error!.takeRetainedValue() as Error)
return nil
}
return decryptedKeyData
}
Any assistance in figuring out how to properly use SecKeys in these ways would be greatly appreciated. Additionally, the relevant Java code can be provided if necessary.
Quick Summary
I'm having trouble using SecKeyCreateSignature(deviceSigningKeyRef, .ecdsaSignatureMessageX962SHA256, digest, &error) but when using SecureEnclave.P256.KeyAgreement.PrivateKey().signature(for: digest) the other code I'm using to verify succeeds.
Full use case and code
If I just initiate a SecureEnclave.P256.KeyAgreement.PrivateKey() class variable and then later use signature(for: digest).rawRepresentation to generate a signature, I get a signature value that can be passed to the verifying code
class MyClass {
var myPrivateKey: SecureEnclave.P256.KeyAgreement.PrivateKey?
init() {
myPrivateKey = SecureEnclave.P256.KeyAgreement.PrivateKey()
let myPublicKey = myPrivateKey?.publicKey.rawRepresentation
}
func createAndSendSignature(_ digest: Data) {
let signature = try? myPrivateKey?.signature(for: digest).rawRepresentation // 64 bytes
sendSignatureWithDigest(signature, digest)
}
}
But if I create my key in keychain via Secure Enclave with the way the documentation recommends (here's a few links to start Signing/Verifying, Keys for encryption), and then retrieve the key representation and use SecKeyCreateSignature, the resulting signature (which I manipulate a little more because it is DER encoded and does not comes back as 64 bytes) fails against the verifying code.
class MyClass {
var myKeyTag: String = "myKeyTag"
func createAndStoreKey() {
let access = SecAccessControlCreateWithFlags(
kCFAllocatorDefault,
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
.privateKeyUsage,
nil)! // Ignore errors.
let attributes: NSDictionary = [
kSecClass as String: kSecClassKey,
kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom,
kSecAttrKeySizeInBits as String: 256,
kSecAttrTokenID: kSecAttrTokenIDSecureEnclave,
kSecPrivateKeyAttrs as String: [
kSecAttrIsPermanent as String: true,
kSecAttrApplicationTag as String: myKeyTag,
kSecAttrAccessControl as String: access,
kSecAttrCanSign as String: true,
]
]
var error: Unmanaged<CFError>?
guard let keyRef: SecKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else {
throw error!.takeRetainedValue() as Error
}
return keyRef as SecKey!
}
func getKey(){
let query: [String: Any] = [
kSecClass as String: kSecClassKey,
kSecAttrApplicationTag as String: myKeyTag,
kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom,
kSecReturnRef as String: true,
]
var item: CFTypeRef?
let status = SecItemCopyMatching(query as CFDictionary, &item)
guard status == errSecSuccess else {
throw KeyStoreError("Unable to retrieve key: \(status.message)")
}
return (item as! SecKey)
}
func createAndSendSignature(_ digest: Data) {
let privKey = getKey()
let signature = SecKeyCreateSignature(
privKey,
.ecdsaSignatureMessageX962SHA256,
digest as CFData,
&error) as Data? else {
print(error)
return
} // bytes varry due to DER encoding and R and S values
let ecdsaSignature = try P256.Signing.ECDSASignature(derRepresentation: signature)
let signatureBytes = ecdsaSignature.rawRepresentation
sendSignatureWithDigest(signatureBytes, digest)
}
}
An important note: digest is not an actual digest but a message that needs to be hashed to turn into a digest? Sorry if that sounds off, my security knowledge is limited.
Please forgive any syntax errors, I can't copy and paste the code and am just extracting the important elements.
Anything helps, thanks!
Hi,
I have a String that I want to:
encrypt it using a key.
generate that key with the Secure Enclave
store the key in the secure enclave
next time the user opens the app:
read the key from the secure enclave.
decrypt the string back.
Is it possible?
I know the Secure Enclave can help me generate a key, but how to store or retrieve it? Is it possible to do that with CryptoKit?