Post

Replies

Boosts

Views

Activity

Signature Creation with PrivateKey().signature(for:) vs SecKeyCreateSignature
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!
2
1
871
Feb ’24