Шифрование с использованием сертификата RSA в Swift - PullRequest
0 голосов
/ 02 апреля 2020

Я использовал следующий код на игровой площадке, чтобы зашифровать строку с помощью RSA. Мне нужно, чтобы шифрование выполнялось с использованием самого сертификата, путем извлечения ключа на go, а не для извлечения ключа отдельно и последующего шифрования.

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)

Однако выдается следующее исключение:

Необязательно (Swift.Unmanaged <__ C .CFErrorRef> (_ значение: Ошибка домена = NSOSStatusErrorDomain Code = -50 "RSA publi * c Не удалось создать ключ из данных" UserInfo = {NSDescription = RSA publi c создание ключа из данных не удалось}))

Как правильно сделать то же самое?

1 Ответ

0 голосов
/ 02 апреля 2020

Указанный код не извлекает ключ из сертификата. Вместо этого он пытается создать SecKey, используя саму строку сертификата. Правильный способ сделать то же самое - создать объект SecCertificate из данных сертификата, а затем создать SecTrust с использованием данных сертификата. Затем, используя доверие, скопируйте ключ publi c, чтобы создать 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? функция.

...