I have the following Swift code to generate a random key and then sign a message:
let privateKeyAttributes = [
kSecAttrIsPermanent as String : true
] as [String : Any]
let attributes: [String: Any] = [
kSecAttrKeyType as String : kSecAttrKeyTypeECSECPrimeRandom,
kSecAttrKeySizeInBits as String : 256,
kSecPrivateKeyAttrs as String : privateKeyAttributes
]
var error1: Unmanaged<CFError>?
guard let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error1) else {
print(error1!.takeRetainedValue() as Error)
return
}
var error2: Unmanaged<CFError>?
let message = "Hello"
guard let msgData = message.data(using: .utf8), let signature = SecKeyCreateSignature(privateKey, .ecdsaSignatureMessageX962SHA256, msgData as CFData, &error2) as? Data else {
print(error1!.takeRetainedValue() as Error)
return
}
print(signature.count) //sometimes 70, sometimes 71 bytes
print(signature as NSData) //{length = 71, bytes = 0x30450220 0795c7a8 c9c34ba3 732966fb ... 720cad1c 7dc2a173 }
print(signature.hexadecimal) //304502200795c7a8c9c34ba3732966fb24d5bffc01d8d28d81182422559e9a6858b79a520221008c0fed0edcd338881e643ce4a810e4318a83f8f8c1d25657720cad1c7dc2a173
The problem is that when I so something similar in Rust using P256, my signature there is 64 bytes. Whereas in swift, it's sometimes 70 bytes, sometimes 71 bytes.
Here's similar in Rust using the example in this link:
let signing_key = SigningKey::random(&mut OsRng);
let message = b"Hello";
let signature: Signature = signing_key.sign(message);
println!("signature: {}, {:?}",signature.to_bytes().len(),hex::encode(signature.to_bytes()));// prints: signature: 64, "08f7ecf7c4c4f5142ef35e3ca294726fae48675c817a9d46e11e86cb60dd459fca8e580f44fb6a5c9b4b85107c161b2508fc1e198a12f06f3d960e45e4a19559"
Because of this difference, the Swift generated signature doesn't turn into a valid signature in my Rust backend. Why's Swift different?
EDIT: Another thing I have just noticed is that if I change the swift code from .ecdsaSignatureMessageX962SHA256
to .ecdsaSignatureMessageRFC4754SHA256
, then it generates a 64 bytes signature. However, that's only available in iOS 17 onwards:
'ecdsaSignatureMessageRFC4754SHA256' is only available in iOS 17.0 or newer
What's the difference between ecdsaSignatureMessageX962SHA256
and ecdsaSignatureMessageRFC4754SHA256
?