如何从PKCS8格式Base64编码字符串创建SecKey
If you're struggling to create an RSA private SecKey from a PKCS8 Base64 string, here's a step-by-step solution using the swift-asn1 package to extract the underlying key material, followed by creating the SecKey:
Step 1: Decode Base64 to Data
First convert the Base64 string to raw data:
guard let pkcs8Data = Data(base64Encoded: yourBase64String) else { // Handle invalid Base64 input return nil }
Step 2: Parse PKCS8 Structure with swift-asn1
PKCS8 wraps the RSA private key in an ASN.1 sequence. Define the necessary ASN.1 structures to parse it:
import SwiftASN1 // ASN.1 Algorithm Identifier (per PKCS8 spec) struct AlgorithmIdentifier: DERImplicitlyTaggable { static var defaultIdentifier: ASN1Identifier { .sequence } let algorithm: ASN1ObjectIdentifier let parameters: ASN1Any? init(derEncoded node: ASN1Node, withIdentifier identifier: ASN1Identifier) throws { let sequence = try ASN1Sequence(node: node, identifier: identifier) self.algorithm = try ASN1ObjectIdentifier(derEncoded: sequence[0]) self.parameters = sequence.count > 1 ? try ASN1Any(derEncoded: sequence[1]) : nil } } // PKCS8 PrivateKeyInfo structure struct PrivateKeyInfo: DERImplicitlyTaggable { static var defaultIdentifier: ASN1Identifier { .sequence } let version: ASN1Integer let algorithm: AlgorithmIdentifier let privateKey: ASN1OctetString init(derEncoded node: ASN1Node, withIdentifier identifier: ASN1Identifier) throws { let sequence = try ASN1Sequence(node: node, identifier: identifier) self.version = try ASN1Integer(derEncoded: sequence[0]) self.algorithm = try AlgorithmIdentifier(derEncoded: sequence[1]) self.privateKey = try ASN1OctetString(derEncoded: sequence[2]) } }
Now parse the PKCS8 data and extract the RSA private key bytes:
do { let pkcs8 = try DERDecoder.decode(PrivateKeyInfo.self, from: pkcs8Data) // Validate it's an RSA key guard pkcs8.algorithm.algorithm == .rsaEncryption else { // Not an RSA key, handle error return nil } // Extract PKCS#1 formatted RSA private key data let rsaPrivateKeyData = Data(pkcs8.privateKey.bytes) } catch { // Handle ASN.1 parsing errors return nil }
Step 3: Create SecKey from RSA Key Data
Use SecKeyCreateWithData with the correct attributes to generate the private key:
let keyAttributes: [CFString: Any] = [ kSecAttrKeyType: kSecAttrKeyTypeRSA, kSecAttrKeyClass: kSecAttrKeyClassPrivate, // Optional: Specify key size if known (e.g., 2048, 4096) // kSecAttrKeySizeInBits: 2048 ] var keyCreationError: Unmanaged<CFError>? guard let privateSecKey = SecKeyCreateWithData( rsaPrivateKeyData as CFData, keyAttributes as CFDictionary, &keyCreationError ) else { // Handle key creation error using keyCreationError?.takeRetainedValue() return nil }
Alternative: Use PKCS8 Data Directly
If you want to skip parsing with swift-asn1, ensure you include the PKCS8 format attribute in your key creation parameters:
let directAttributes: [CFString: Any] = [ kSecAttrKeyType: kSecAttrKeyTypeRSA, kSecAttrKeyClass: kSecAttrKeyClassPrivate, kSecAttrKeyFormat: kSecAttrKeyFormatPKCS8 ] var directError: Unmanaged<CFError>? guard let directSecKey = SecKeyCreateWithData( pkcs8Data as CFData, directAttributes as CFDictionary, &directError ) else { // Handle error return nil }
Make sure you've added the swift-asn1 package to your project via Swift Package Manager before using the parsing code.
内容的提问来源于stack exchange,提问作者cora

