admin管理员组文章数量:1124411
I want to generate the same kind of key pair as the result of following openssl command:
openssl ecparam -genkey -name prime256v1 -noout -out ec256-key-pair.pem
openssl ec -in ec256-key-pair.pem -pubout > my-public-ec.pem
When I inspect the result:
openssl pkey -pubin -in my-public-ec.pem -text -noout
I get:
Public-Key: (256 bit)
pub:
04:fc:7a:1d:5a:2d:8b:c9:ff:47:cc:56:ae:66:37:
4b:5d:69:d9:d4:9a:10:72:30:e5:2d:2e:9d:86:19:
30:2a:44:4e:b2:04:09:8f:d3:89:3a:5d:5e:f2:32:
c7:70:12:bb:55:18:28:c1:a7:2d:d4:1c:e6:9b:12:
46:4d:98:07:1b
ASN1 OID: prime256v1
NIST CURVE: P-256
Now I want to do the same in Swift:
The code I use to do this is as follows:
func generateKeys() throws -> (privateKey: SecKey, publicKey: SecKey) {
let query: [String: Any] = [
kSecAttrKeyType as String: kSecAttrKeyTypeEC,
kSecAttrKeySizeInBits as String: 256,
kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave,
kSecAttrIsPermanent as String: false
]
var error: Unmanaged<CFError>?
guard let privateKey = SecKeyCreateRandomKey(query as CFDictionary, &error) else {
throw error as! any Error
}
let publicKey = SecKeyCopyPublicKey(privateKey)!
return (privateKey, publicKey)
}
This runs without errors.
Next I generate the key pair, and print the public key in PEM format:
extension SecKey {
func exportBase64EncodedKey() -> String {
var error: Unmanaged<CFError>?
guard let data = SecKeyCopyExternalRepresentation(self, &error) else {
fatalError("Failed to export key: \(error!.takeRetainedValue())")
}
return (data as Data).base64EncodedString(options: [.lineLength64Characters])
}
}
func printPublicKey() {
let keyPair = try! generateKeys()
let encodedPublicKey = keyPair.publicKey.exportBase64EncodedKey()
var header = "-----BEGIN PUBLIC KEY-----"
var footer = "-----END PUBLIC KEY-----"
var pemKey = "\(header)\n\(encodedPublicKey)\n\(footer)\n"
print(pemKey)
}
printPublicKey()
This prints something like:
-----BEGIN PUBLIC KEY-----
BJe2Tq7I1H6gbzcTW0Mq8c8FOhOakEbq6EPQXYSnlDF4IHHyzlERs6YUdcwy8KvT
fuNHfOQ7b3ITi5FFHcCXmps=
-----END PUBLIC KEY-----
If I copy this in a pem file and I run the same command:
openssl pkey -pubin -in new_public_key.pem -text -noout
I get the following error:
Could not find private key of Public Key from new_public_key.pem
404278EC01000000:error:1E08010C:DECODER routines:OSSL_DECODER_from_bio:unsupported:crypto/encode_decode/decoder_lib.c:102:No supported data to decode.
What am I doing wrong?
Running the above code with the following parameters:
kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
kSecAttrKeySizeInBits as String: 1024,
Results in a public key that Openssl can parse without problems.
For easy testing, here code you can copy-paste in a Swift Playground to run it:
import Foundation
import Security
import CryptoKit
func generateKeys() throws -> (privateKey: SecKey, publicKey: SecKey) {
let query: [String: Any] = [
kSecAttrKeyType as String: kSecAttrKeyTypeEC,
kSecAttrKeySizeInBits as String: 256,
kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave,
kSecAttrIsPermanent as String: false
]
var error: Unmanaged<CFError>?
guard let privateKey = SecKeyCreateRandomKey(query as CFDictionary, &error) else {
throw error as! any Error
}
let publicKey = SecKeyCopyPublicKey(privateKey)!
return (privateKey, publicKey)
}
extension SecKey {
func exportBase64EncodedKey() -> String {
var error: Unmanaged<CFError>?
guard let data = SecKeyCopyExternalRepresentation(self, &error) else {
fatalError("Failed to export key: \(error!.takeRetainedValue())")
}
return (data as Data).base64EncodedString(options: [.lineLength64Characters])
}
}
func printPublicKey() {
let keyPair = try! generateKeys()
let encodedPublicKey = keyPair.publicKey.exportBase64EncodedKey()
var header = "-----BEGIN PUBLIC KEY-----"
var footer = "-----END PUBLIC KEY-----"
var pemKey = "\(header)\n\(encodedPublicKey)\n\(footer)\n"
print(pemKey)
}
printPublicKey()
I want to generate the same kind of key pair as the result of following openssl command:
openssl ecparam -genkey -name prime256v1 -noout -out ec256-key-pair.pem
openssl ec -in ec256-key-pair.pem -pubout > my-public-ec.pem
When I inspect the result:
openssl pkey -pubin -in my-public-ec.pem -text -noout
I get:
Public-Key: (256 bit)
pub:
04:fc:7a:1d:5a:2d:8b:c9:ff:47:cc:56:ae:66:37:
4b:5d:69:d9:d4:9a:10:72:30:e5:2d:2e:9d:86:19:
30:2a:44:4e:b2:04:09:8f:d3:89:3a:5d:5e:f2:32:
c7:70:12:bb:55:18:28:c1:a7:2d:d4:1c:e6:9b:12:
46:4d:98:07:1b
ASN1 OID: prime256v1
NIST CURVE: P-256
Now I want to do the same in Swift:
The code I use to do this is as follows:
func generateKeys() throws -> (privateKey: SecKey, publicKey: SecKey) {
let query: [String: Any] = [
kSecAttrKeyType as String: kSecAttrKeyTypeEC,
kSecAttrKeySizeInBits as String: 256,
kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave,
kSecAttrIsPermanent as String: false
]
var error: Unmanaged<CFError>?
guard let privateKey = SecKeyCreateRandomKey(query as CFDictionary, &error) else {
throw error as! any Error
}
let publicKey = SecKeyCopyPublicKey(privateKey)!
return (privateKey, publicKey)
}
This runs without errors.
Next I generate the key pair, and print the public key in PEM format:
extension SecKey {
func exportBase64EncodedKey() -> String {
var error: Unmanaged<CFError>?
guard let data = SecKeyCopyExternalRepresentation(self, &error) else {
fatalError("Failed to export key: \(error!.takeRetainedValue())")
}
return (data as Data).base64EncodedString(options: [.lineLength64Characters])
}
}
func printPublicKey() {
let keyPair = try! generateKeys()
let encodedPublicKey = keyPair.publicKey.exportBase64EncodedKey()
var header = "-----BEGIN PUBLIC KEY-----"
var footer = "-----END PUBLIC KEY-----"
var pemKey = "\(header)\n\(encodedPublicKey)\n\(footer)\n"
print(pemKey)
}
printPublicKey()
This prints something like:
-----BEGIN PUBLIC KEY-----
BJe2Tq7I1H6gbzcTW0Mq8c8FOhOakEbq6EPQXYSnlDF4IHHyzlERs6YUdcwy8KvT
fuNHfOQ7b3ITi5FFHcCXmps=
-----END PUBLIC KEY-----
If I copy this in a pem file and I run the same command:
openssl pkey -pubin -in new_public_key.pem -text -noout
I get the following error:
Could not find private key of Public Key from new_public_key.pem
404278EC01000000:error:1E08010C:DECODER routines:OSSL_DECODER_from_bio:unsupported:crypto/encode_decode/decoder_lib.c:102:No supported data to decode.
What am I doing wrong?
Running the above code with the following parameters:
kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
kSecAttrKeySizeInBits as String: 1024,
Results in a public key that Openssl can parse without problems.
For easy testing, here code you can copy-paste in a Swift Playground to run it:
import Foundation
import Security
import CryptoKit
func generateKeys() throws -> (privateKey: SecKey, publicKey: SecKey) {
let query: [String: Any] = [
kSecAttrKeyType as String: kSecAttrKeyTypeEC,
kSecAttrKeySizeInBits as String: 256,
kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave,
kSecAttrIsPermanent as String: false
]
var error: Unmanaged<CFError>?
guard let privateKey = SecKeyCreateRandomKey(query as CFDictionary, &error) else {
throw error as! any Error
}
let publicKey = SecKeyCopyPublicKey(privateKey)!
return (privateKey, publicKey)
}
extension SecKey {
func exportBase64EncodedKey() -> String {
var error: Unmanaged<CFError>?
guard let data = SecKeyCopyExternalRepresentation(self, &error) else {
fatalError("Failed to export key: \(error!.takeRetainedValue())")
}
return (data as Data).base64EncodedString(options: [.lineLength64Characters])
}
}
func printPublicKey() {
let keyPair = try! generateKeys()
let encodedPublicKey = keyPair.publicKey.exportBase64EncodedKey()
var header = "-----BEGIN PUBLIC KEY-----"
var footer = "-----END PUBLIC KEY-----"
var pemKey = "\(header)\n\(encodedPublicKey)\n\(footer)\n"
print(pemKey)
}
printPublicKey()
Share
Improve this question
edited 2 days ago
Joris
asked 2 days ago
JorisJoris
6,2847 gold badges44 silver badges72 bronze badges
1 Answer
Reset to default 1SecKeyCopyExternalRepresentation()
returns the public key for an EC curve in uncompressed format: 0x04|<x>|<y>
, where <x>
and <y>
are the x and y coordinates of the EC point and both of them are 32 bytes in size for P-256.
However, the PEM encoded public key requires the X.509/SPKI format. The X.509/SPKI format contains the uncompressed key at the very end. For keys of the same curve, the front part is constant.1)
So if the front part for a certain curve and an uncompressed key for this curve are concatenated, you get the key in X.509/SPKI format, e.g. for P-256 and your uncompressed key:
var spki = Data(base64Encoded: "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgA=")!
let raw = Data(base64Encoded: "BJe2Tq7I1H6gbzcTW0Mq8c8FOhOakEbq6EPQXYSnlDF4IHHyzlERs6YUdcwy8KvTfuNHfOQ7b3ITi5FFHcCXmps=")!
spki.append(raw)
let key = spki.base64EncodedString(options: [.lineLength64Characters])
let header = "-----BEGIN PUBLIC KEY-----"
let footer = "-----END PUBLIC KEY-----"
let pemKey = "\(header)\n\(key)\n\(footer)\n"
print(pemKey)
This code gives you the PEM encoded key in X.509/SPKI format, which can be processed with your OpenSSL statement:
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEl7ZOrsjUfqBvNxNbQyrxzwU6E5qQ
RuroQ9BdhKeUMXggcfLOURGzphR1zDLwq9N+40d85DtvchOLkUUdwJeamw==
-----END PUBLIC KEY-----
You can inspect this key in an ASN.1/DER parser, e.g. here.
1) As a side note: A public key in X.509/SPKI format can also contain a compressed key: <a>|<x>
with <a>
is <0x02>
for even <y>
and <0x03>
for odd <y>
. In this case, the front part differs (due to the length information it contains). However, this is not important here, as SecKeyCopyExternalRepresentation()
returns the uncompressed key.
In this answer you will find an alternative approach that uses CryptoExportImportManager
.
本文标签: Problem generating EC PEM keypair on iOS in Swiftusing Security frameworkStack Overflow
版权声明:本文标题:Problem generating EC PEM keypair on iOS in Swift, using Security framework - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736627490a1945705.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论