Skip to content

Instantly share code, notes, and snippets.

@Kyle-Ye
Last active November 25, 2023 18:21
Show Gist options
  • Save Kyle-Ye/8c322f4dc3338de1b83b0762a37e8870 to your computer and use it in GitHub Desktop.
Save Kyle-Ye/8c322f4dc3338de1b83b0762a37e8870 to your computer and use it in GitHub Desktop.
RSA key generation and export in Swift
//
// 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()
@Kyle-Ye
Copy link
Author

Kyle-Ye commented Nov 25, 2023

Update: https://developer.apple.com/forums/thread/96278?answerId=293171022#293171022

Use BEGIN RSA PUBLIC KEY instead of BEGIN PUBLIC KEY to fix it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment