Right, so I believe the issue here is the PEM wrapper. The reason I say that is because when I try this on macOS using .pemArmour
, then I am able to create the SecKey:
let privateKey = """
-----BEGIN PRIVATE KEY-----
MHcCAQEEIKJTc3zI8D07Myh7ZIR+wGyQgsjEeKdH0+hSiErK5AjzoAoGCCqGSM49
AwEHoUQDQgAEvbOBrM/D2fX05zKQYuJiTRP6YiUBabImrHb9s+OHimxUxX+E9jVe
oQ6nxSOkfgm0H1OjLfp2xGLqkDTuF38UGQ==
-----END PRIVATE KEY-----
"""
let privateKeyData = privateKey.data(using: .utf8)!
let privateKeyBytes = [UInt8](privateKeyData)
let cfKeyData = CFDataCreate(kCFAllocatorDefault, privateKeyBytes, privateKeyData.count)!
var importedItems: CFArray?
let status = SecItemImport(cfKeyData, "pem" as CFString, nil, nil, .pemArmour, nil, nil, &importedItems)
guard status == errSecSuccess,
let keys = importedItems as? [SecKey],
let secPrivateKey = keys.first else {
fatalError("Private key could not be created")
}
print("Private key: \(secPrivateKey) keys count \(keys.count)")
NOTE I did not try to encrypt or decrypt here with secPrivateKey
, but I just wanted to validate that I could get the key.
Now, when going through SecKeyCreateWithData
with the PEM wrapped bytes I get a nil
key:
guard let filepath = Bundle.main.path(forResource: "key", ofType: "pem") else {
fatalError("File could not be found")
}
let url = URL(fileURLWithPath: filepath)
var privateKeyPemData = Data()
do {
privateKeyPemData = try Data.init(contentsOf: url)
} catch {
print("File could not be opened: \(error.localizedDescription)")
}
let privateKeyPemBytes = [UInt8](privateKeyPemData)
print("privateKeyPemBytes.count: \(privateKeyPemBytes.count)")
//let cfKeyBytes = CFDataCreate(kCFAllocatorDefault, privateKeyPemBytes, privateKeyPemBytes.count)!
var error: Unmanaged<CFError>? = nil
let privateSecKey = SecKeyCreateWithData(Data(privateKeyPemBytes) as CFData, [
kSecAttrKeyType: kSecAttrKeyTypeEC,
kSecAttrKeyClass: kSecAttrKeyClassPrivate] as NSDictionary, &error)
Now, when base64 decoding the PEM wrapper around your key into a ASN.1 structure I see:
$ dumpasn1 AuthKey.bin
0 119: SEQUENCE {
2 1: INTEGER 1
5 32: OCTET STRING
: A2 53 73 7C C8 F0 3D 3B 33 28 7B 64 84 7E C0 6C
: 90 82 C8 C4 78 A7 47 D3 E8 52 88 4A CA E4 08 F3
39 10: [0] {
41 8: OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7)
: }
51 68: [1] {
53 66: BIT STRING
: 04 BD B3 81 AC CF C3 D9 F5 F4 E7 32 90 62 E2 62
: 4D 13 FA 62 25 01 69 B2 26 AC 76 FD B3 E3 87 8A
: 6C 54 C5 7F 84 F6 35 5E A1 0E A7 C5 23 A4 7E 09
: B4 1F 53 A3 2D FA 76 C4 62 EA 90 34 EE 17 7F 14
: 19
: }
: }
And then taking those raw bytes and running them through SecKeyCreateWithData
now a SecKey
can be created:
let privateKeyRawBytes = [UInt8]([
0x04, 0xBD, 0xB3, 0x81, 0xAC, 0xCF, 0xC3, 0xD9, 0xF5, 0xF4, 0xE7, 0x32, 0x90, 0x62, 0xE2, 0x62,
0x4D, 0x13, 0xFA, 0x62, 0x25, 0x01, 0x69, 0xB2, 0x26, 0xAC, 0x76, 0xFD, 0xB3, 0xE3, 0x87, 0x8A,
0x6C, 0x54, 0xC5, 0x7F, 0x84, 0xF6, 0x35, 0x5E, 0xA1, 0x0E, 0xA7, 0xC5, 0x23, 0xA4, 0x7E, 0x09,
0xB4, 0x1F, 0x53, 0xA3, 0x2D, 0xFA, 0x76, 0xC4, 0x62, 0xEA, 0x90, 0x34, 0xEE, 0x17, 0x7F, 0x14,
0x19, 0xA2, 0x53, 0x73, 0x7C, 0xC8, 0xF0, 0x3D, 0x3B, 0x33, 0x28, 0x7B, 0x64, 0x84, 0x7E, 0xC0, 0x6C,
0x90, 0x82, 0xC8, 0xC4, 0x78, 0xA7, 0x47, 0xD3, 0xE8, 0x52, 0x88, 0x4A, 0xCA, 0xE4, 0x08, 0xF3,
])
var error: Unmanaged<CFError>? = nil
let privateSecKey = SecKeyCreateWithData(Data(privateKeyRawBytes) as CFData, [
kSecAttrKeyType: kSecAttrKeyTypeEC,
kSecAttrKeyClass: kSecAttrKeyClassPrivate] as NSDictionary, &error)
print("Private sec key: \(privateSecKey)")
*/
// Private sec key: Optional(<SecKeyRef curve type: kSecECCurveSecp256r1, algorithm id: 3, key type: ECPrivateKey, version: 4, block size: 256 bits, addr: 0x100415920>)
Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com