Hi,I'm playing around with the new CryptoKit framework on iOS. I'm trying to generate eliptic curve keys, sign some data with them, export the signature and the public key and verify the signature externaly (in this case with openssl).I'm not getting this to work with the format that ECDSASignature.derRepresentation provides. However, I can make it work when using SecKeyRawSign from the old Security framework.Here is the code for both singings using the same key. It creates a shell script that demonstrate the signature verification with on baord openssl.import Foundation
import CryptoKit
struct SignDemo {
private let secp384r1header: [UInt8] = [0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00]
func run() {
var shell: [String] = []
shell.append("\n\n#! /bin/sh")
// The data to sign
let dataToSign = "The data to sign!".data(using: .utf8)!
shell.append("echo \(dataToSign.map { String(format: "%02hhx", $0) }.joined()) | xxd -r -p > dataToSign.dat")
// Keys
let privKey = P384.Signing.PrivateKey()
let pubKey = privKey.publicKey
var pubKeyDER = Data(secp384r1header)
pubKeyDER.append(pubKey.x963Representation)
shell.append("echo \(pubKeyDER.map { String(format: "%02hhx", $0) }.joined()) | xxd -r -p > key.der")
shell.append("cat > key.pem <<eof\n-----begin public="" key-----\n\(pubkeyder.base64encodedstring().separate())\n-----end="" key-----\neof")<br="">
// Sign with Sec
let secSignature = try! secSing(digest: dataToSign, privKeyData: privKey.x963Representation)
shell.append("echo \(secSignature.map { String(format: "%02hhx", $0) }.joined()) | xxd -r -p > sig-sec.dat")
shell.append("/usr/local/opt/openssl/bin/openssl dgst -SHA256 -verify key.pem -signature sig-sec.dat dataToSign.dat")
// Sign with CryptoKit
let ckSignature = try! cryptoKitSing(digest: dataToSign, privKey: privKey)
shell.append("echo \(ckSignature.map { String(format: "%02hhx", $0) }.joined()) | xxd -r -p > sig-ck.dat")
shell.append("/usr/local/opt/openssl/bin/openssl dgst -SHA256 -verify key.pem -signature sig-ck.dat dataToSign.dat")
print(shell.joined(separator: "\n"))
}
private func cryptoKitSing(digest: Data, privKey: P384.Signing.PrivateKey) throws -> Data {
return try privKey.signature(for: digest).derRepresentation
}
private func secSing(digest: Data, privKeyData: Data) throws -> Data {
let attributes: [String:Any] =
[
kSecAttrKeyClass as String: kSecAttrKeyClassPrivate,
kSecAttrKeyType as String: kSecAttrKeyTypeEC,
kSecAttrKeySizeInBits as String: 384,
]
guard let secKey = SecKeyCreateWithData(privKeyData as CFData, attributes as CFDictionary, nil) else {
throw MyError(msg: "Error: Problem in SecKeyCreateWithData()")
}
// TODO: I guess that can be done easier
let digestToSign = SHA256.hash(data: digest).makeIterator()
var digestToSignBytes = [UInt8]()
digestToSign.forEach { byte in
digestToSignBytes.append(byte)
}
var signatureLength = 103
var signatureBytes = [UInt8](repeating: 0, count: signatureLength)
let signErr = SecKeyRawSign(secKey, .PKCS1SHA256, &digestToSignBytes, digestToSignBytes.count, &signatureBytes, &signatureLength)
guard signErr == errSecSuccess else {
throw MyError(msg: "Could not create signature. OSStatus: \(signErr)")
}
return Data(signatureBytes)
}
}
struct MyError: Error {
let msg: String
}
extension String {
func separate(every stride: Int = 64, with separator: Character = "\n") -> String {
return String(enumerated().map { $0 > 0 && $0 % stride == 0 ? [separator, $1] : [$1]}.joined())
}Wenn running that code in an iOS App and then use the script to verify, the following happens:bash-3.2$
bash-3.2$ echo 546865206461746120746f207369676e21 | xxd -r -p > dataToSign.dat
bash-3.2$ echo 3076301006072a8648ce3d020106052b8104002203620004d2d3225b5c46dea5e39a0592e20ae25b8ba823374a110fde409ad6c71bcc334d7b0b5916d7fb0256b7c5716f0a9f339b35c0b96813101e24b8d5849bde61d710b62b71fc3e0e7e59dbdc6ed77820aecd5857ae1545c0d7eaefb43d02641e9b4a | xxd -r -p > key.der
cat > key.pem <<eof
-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE0tMiW1xG3qXjmgWS4griW4uoIzdKEQ/e
QJrWxxvMM017C1kW1/sCVrfFcW8KnzObNcC5aBMQHiS41YSb3mHXELYrcfw+Dn5Z
29xu13ggrs1YV64VRcDX6u+0PQJkHptK
-----END PUBLIC KEY-----
EOF
echo 3065023100e4ad6c0d5fbd68fe0ee6754e4d8651af07e49d72edcd1dffdf2fc3c79d7690ce91196ffe6d5aa67b85560c1283a0db3502307c8769b38f75e7f90ef64432c2746021bf3198507edbc95eefbf43dde7b83d95efd2e06549efc73742439d0aab057a86 | xxd -r -p > sig-sec.dat
/usr/local/opt/openssl/bin/openssl dgst -SHA256 -verify key.pem -signature sig-sec.dat dataToSign.dat
echo 30640230702fd094ca99e0736fa0f7cd005a9d68105d2c3be7de4ecf3e8f47531b6692629449e13abc8162f4bdcf0e6a340f59de023001d45750caf603615eed2404b05007ef44dcc10460a66bc346e62299808bd430a93e96b70e68c73bcd6b320dd026e9c9 | xxd -r -p > sig-ck.dat
/usr/local/opt/openssl/bin/openssl dgst -SHA256 -verify key.pem -signature sig-ck.dat dataToSign.datbash-3.2$ cat > key.pem <<eof
> -----BEGIN PUBLIC KEY-----
> MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE0tMiW1xG3qXjmgWS4griW4uoIzdKEQ/e
> QJrWxxvMM017C1kW1/sCVrfFcW8KnzObNcC5aBMQHiS41YSb3mHXELYrcfw+Dn5Z
> 29xu13ggrs1YV64VRcDX6u+0PQJkHptK
> -----END PUBLIC KEY-----
> EOF
bash-3.2$ echo 3065023100e4ad6c0d5fbd68fe0ee6754e4d8651af07e49d72edcd1dffdf2fc3c79d7690ce91196ffe6d5aa67b85560c1283a0db3502307c8769b38f75e7f90ef64432c2746021bf3198507edbc95eefbf43dde7b83d95efd2e06549efc73742439d0aab057a86 | xxd -r -p > sig-sec.dat
bash-3.2$ /usr/local/opt/openssl/bin/openssl dgst -SHA256 -verify key.pem -signature sig-sec.dat dataToSign.dat
Verified OK
bash-3.2$ echo 30640230702fd094ca99e0736fa0f7cd005a9d68105d2c3be7de4ecf3e8f47531b6692629449e13abc8162f4bdcf0e6a340f59de023001d45750caf603615eed2404b05007ef44dcc10460a66bc346e62299808bd430a93e96b70e68c73bcd6b320dd026e9c9 | xxd -r -p > sig-ck.dat
bash-3.2$ /usr/local/opt/openssl/bin/openssl dgst -SHA256 -verify key.pem -signature sig-ck.dat dataToSign.dat
Verification FailureYou can see in line 22 and 23 that verification works with the signature of the Secutity framework and this also shows that the exported key works. At line 25 and 26 you can see the verification of the CryptoKit signature, which failes.Did anyone got verification of a crypto kit signature to work with external tools (like openssl)?Thanks!BestAlex