在 Swift 中使用 RSA 证书加密

Encrypt using RSA Certificate in Swift

我在 playground 中使用以下代码使用 RSA 加密字符串。我需要使用证书本身进行加密,方法是随时随地提取密钥,而不是单独提取密钥然后加密。

import Foundation
import Security


struct RSA {

    static func encrypt(string: String, publicKey: String?) -> String? {
        guard let publicKey = publicKey else { return nil }

        let keyString = publicKey.replacingOccurrences(of: "-----BEGIN CERTIFICATE-----", with: "").replacingOccurrences(of: "-----END CERTIFICATE-----", with: "").replacingOccurrences(of: "\r", with: "").replacingOccurrences(of: "\n", with: "").replacingOccurrences(of: "\t", with: "").replacingOccurrences(of: " ", with: "")
        print(keyString)
        guard let data = Data(base64Encoded: keyString) else { return nil }
        print(data)
        var attributes: CFDictionary {
            return [kSecAttrKeyType : kSecAttrKeyTypeRSA,
                    kSecAttrKeyClass : kSecAttrKeyClassPublic,
                    kSecAttrKeySizeInBits : 2048,
                    kSecReturnPersistentRef : kCFBooleanTrue as Any] as CFDictionary
        }

        var error: Unmanaged<CFError>? = nil
        guard let secKey = SecKeyCreateWithData(data as CFData, attributes, &error) else {
            print(error.debugDescription)
            return nil
        }
        return encrypt(string: string, publicKey: secKey)
    }

    static func encrypt(string: String, publicKey: SecKey) -> String? {
        let buffer = [UInt8](string.utf8)

        var keySize = SecKeyGetBlockSize(publicKey)
        var keyBuffer = [UInt8](repeating: 0, count: keySize)

        // Encrypto should less than key length
        guard SecKeyEncrypt(publicKey, SecPadding.PKCS1, buffer, buffer.count, &keyBuffer, &keySize) == errSecSuccess else { return nil }
        return Data(bytes: keyBuffer, count: keySize).base64EncodedString()
    }
}


var pemString = "-----BEGIN CERTIFICATE-----##Base 64 encoded certificate string##-----END CERTIFICATE-----"


let password = "abcde"
let encryptedPassword = RSA.encrypt(string: password, publicKey: pemString)
print(encryptedPassword as Any)

但是它抛出以下异常:

Optional(Swift.Unmanaged<__C.CFErrorRef>(_value: Error Domain=NSOSStatusErrorDomain Code=-50 "RSA public key creation from data failed" UserInfo={NSDescription=RSA public key creation from data failed}))

如何正确地做同样的事情?

所提供的相关代码并未从证书中提取密钥。相反,它会尝试使用证书字符串本身来创建 SecKey。正确的做法是从证书数据创建一个 SecCertificate 对象,然后使用证书数据创建一个 SecTrust。然后使用信任,复制 public 密钥以创建 SecKey 对象。

最终代码将如下所示:

import Foundation
import Security


struct RSA {

    static func encrypt(string: String, certificate: String?) -> String? {
        guard let certificate = certificate else { return nil }

        let certificateString = certificate.replacingOccurrences(of: "-----BEGIN CERTIFICATE-----", with: "").replacingOccurrences(of: "-----END CERTIFICATE-----", with: "").replacingOccurrences(of: "\r", with: "").replacingOccurrences(of: "\n", with: "").replacingOccurrences(of: "\t", with: "").replacingOccurrences(of: " ", with: "")
        print(certificateString)

        // Convert the certificate string to Data
        guard let data = Data(base64Encoded: certificateString) else { return nil }
        print(data)

        // Create SecCertificate object using certificate data
        guard let cer = SecCertificateCreateWithData(nil, data as NSData) else { return nil }

        var trust: SecTrust?

        // Retrieve a SecTrust using the SecCertificate object. Provide X509 as policy
        let status = SecTrustCreateWithCertificates(cer, SecPolicyCreateBasicX509(), &trust)

        // Check if the trust generation is success
        guard status == errSecSuccess else { return nil }

        // Retrieve the SecKey using the trust hence generated
        guard let secKey = SecTrustCopyPublicKey(trust!) else { return nil }

        return encrypt(string: string, publicKey: secKey)
    }

    static func encrypt(string: String, publicKey: SecKey) -> String? {
        let buffer = [UInt8](string.utf8)

        var keySize = SecKeyGetBlockSize(publicKey)
        var keyBuffer = [UInt8](repeating: 0, count: keySize)

        // Encrypto should less than key length
        guard SecKeyEncrypt(publicKey, SecPadding.PKCS1, buffer, buffer.count, &keyBuffer, &keySize) == errSecSuccess else { return nil }
        return Data(bytes: keyBuffer, count: keySize).base64EncodedString()
    }
}


var pemString = "-----BEGIN CERTIFICATE-----##Base 64 encoded certificate string##-----END CERTIFICATE-----"


let password = "abcde"
let encryptedPassword = RSA.encrypt(string: password, certificate: pemString)
print(encryptedPassword as Any)

唯一的变化是 static func encrypt(string: String, certificate: String?) -> String? 函数。