p256 signature in iOS Swift is 70 or 71 bytes instead of 64 bytes in Rust

92 views Asked by At

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?

0

There are 0 answers