Last active
November 25, 2023 18:21
-
-
Save Kyle-Ye/8c322f4dc3338de1b83b0762a37e8870 to your computer and use it in GitHub Desktop.
RSA key generation and export in Swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// APIKeyManager.swift | |
// Demo | |
// | |
// Created by Kyle on 2023/11/25. | |
// | |
import Foundation | |
import Security | |
enum APIKeyManager { | |
private static let tag = "keys.user_api_key".data(using: .utf8)! | |
private static var createAttributes: CFDictionary { | |
[ | |
kSecAttrType: kSecAttrKeyTypeRSA, | |
kSecAttrKeySizeInBits: 2048 as CFNumber, | |
kSecPrivateKeyAttrs: [ | |
kSecAttrIsPermanent: true as CFBoolean, | |
kSecAttrApplicationTag: tag as CFData, | |
], | |
] as CFDictionary | |
} | |
private static var queryAttributes: CFDictionary { | |
[ | |
kSecAttrApplicationTag: tag as CFData, | |
kSecClass: kSecClassKey, | |
kSecAttrKeyClass: kSecAttrKeyClassPrivate, | |
kSecReturnRef: true as CFBoolean, | |
] as CFDictionary | |
} | |
private static func createPrivateKey() throws -> SecKey { | |
var error: Unmanaged<CFError>? | |
guard let privateKey = SecKeyCreateRandomKey(createAttributes, &error) else { | |
throw error!.takeRetainedValue() as Error | |
} | |
return privateKey | |
} | |
private static func getPrivateKey() throws -> SecKey { | |
var item: CFTypeRef? | |
let res = SecItemCopyMatching(queryAttributes, &item) | |
if res == errSecSuccess { | |
return item as! SecKey | |
} else { | |
return try createPrivateKey() | |
} | |
} | |
@discardableResult | |
private static func deletePrivateKey() -> Bool { | |
let res = SecItemDelete(queryAttributes) | |
return res == errSecSuccess | |
} | |
private static func getPublicKey() throws -> SecKey? { | |
let privateKey = try getPrivateKey() | |
let publicKey = SecKeyCopyPublicKey(privateKey) | |
return publicKey | |
} | |
static func getPublicKeyString() throws -> String? { | |
guard let publicKey = try getPublicKey() else { | |
return nil | |
} | |
var error: Unmanaged<CFError>? | |
guard let publicKeyData = SecKeyCopyExternalRepresentation(publicKey, &error) else { | |
throw error!.takeRetainedValue() as Error | |
} | |
let publicKeyString = (publicKeyData as Data).base64EncodedString(options: [.lineLength64Characters]) | |
let publicKeyResult = #""" | |
-----BEGIN RSA PUBLIC KEY----- | |
\#(publicKeyString) | |
-----END RSA PUBLIC KEY----- | |
"""# | |
return publicKeyResult | |
} | |
} | |
try APIKeyManager.getPublicKeyString() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Update: https://developer.apple.com/forums/thread/96278?answerId=293171022#293171022
Use
BEGIN RSA PUBLIC KEY
instead ofBEGIN PUBLIC KEY
to fix it