简体   繁体   中英

How to decrypt data with Security.framework on macOS?

I need to decrypt data with a RSA public key on macOS , by googling I know we can use method SecKeyCreateDecryptedData of Security.framework to achieve that, but it leads to two problems:

  1. SecKeyCreateDecryptedData accepts a private key to execute decryption, but in my situation, the data is encrypted with private key in the server-end, and needs to be decrypted with public key in the client-end.

  2. I tried to create SecKey from a RSA public key string, but failed.

My code:

import Foundation
 
func getPublicKey(from data: Data) throws -> SecKey {
    var error: Unmanaged<CFError>? = nil
    let publicKeyMaybe = SecKeyCreateWithData(
        data as NSData,
        [
            kSecAttrKeyType: kSecAttrKeyTypeRSA,
            kSecAttrKeyClass: kSecAttrKeyClassPublic
        ] as NSDictionary,
        &error)
    guard let publicKey = publicKeyMaybe else {
        throw error!.takeRetainedValue() as Error
    }
    return publicKey
}

func decrypt(key: SecKey, data cipherTextData: Data) -> Data? {
    let algorithm: SecKeyAlgorithm = .eciesEncryptionCofactorVariableIVX963SHA256AESGCM
    guard SecKeyIsAlgorithmSupported(key, .decrypt, algorithm) else {
        print("Can't decrypt. Algorithm not supported.")
        return nil
    }

    var error: Unmanaged<CFError>? = nil
    let clearTextData = SecKeyCreateDecryptedData(key,
                                                  algorithm,
                                                  cipherTextData as CFData,
                                                  &error) as Data?
    if let error = error {
        print("Can't decrypt. %@", (error.takeRetainedValue() as Error).localizedDescription)
        return nil
    }
    guard clearTextData != nil else {
        print("Can't decrypt. No resulting cleartextData.")
        return nil
    }
    print("Decrypted data.")
    return clearTextData
}

func testDecrypt() {
    let rawString = "0ed3a2c57f5dEJgqXT9760269b8cc5cd76f3afcf"
    let decodedData = Data.init(base64Encoded: rawString, options: [])!

    let pubKey = try! getPublicKey(from: kPubKey.data(using: .utf8)!) // Error: RSA public key creation from data failed
    let decryptedData = decrypt(key: pubKey, data: decodedData)!
    let decrypted = String.init(data: decryptedData, encoding: .utf8)!

    print(">>>>>>> decrypted string: \(decrypted)")
}

testDecrypt()

With method of Kazunori Takaishi , I tested all the algorithm, none of them is supported:

func decrypt(key: SecKey, data cipherTextData: Data) -> Data? {
        let algorithms: [SecKeyAlgorithm] = [
            .rsaSignatureRaw,
            .rsaSignatureDigestPKCS1v15Raw,
            .rsaSignatureDigestPKCS1v15SHA1,
            .rsaSignatureDigestPKCS1v15SHA224,
            .rsaSignatureDigestPKCS1v15SHA256,
            .rsaSignatureDigestPKCS1v15SHA384,
            .rsaSignatureDigestPKCS1v15SHA512,
            .rsaSignatureMessagePKCS1v15SHA1,
            .rsaSignatureMessagePKCS1v15SHA224,
            .rsaSignatureMessagePKCS1v15SHA256,
            .rsaSignatureMessagePKCS1v15SHA384,
            .rsaSignatureMessagePKCS1v15SHA512,
            .rsaSignatureDigestPSSSHA1,
            .rsaSignatureDigestPSSSHA224,
            .rsaSignatureDigestPSSSHA256,
            .rsaSignatureDigestPSSSHA384,
            .rsaSignatureDigestPSSSHA512,
            .rsaSignatureMessagePSSSHA1,
            .rsaSignatureMessagePSSSHA224,
            .rsaSignatureMessagePSSSHA256,
            .rsaSignatureMessagePSSSHA384,
            .rsaSignatureMessagePSSSHA512,
            .ecdsaSignatureRFC4754,
            .ecdsaSignatureDigestX962,
            .ecdsaSignatureDigestX962SHA1,
            .ecdsaSignatureDigestX962SHA224,
            .ecdsaSignatureDigestX962SHA256,
            .ecdsaSignatureDigestX962SHA384,
            .ecdsaSignatureDigestX962SHA512,
            .ecdsaSignatureMessageX962SHA1,
            .ecdsaSignatureMessageX962SHA224,
            .ecdsaSignatureMessageX962SHA256,
            .ecdsaSignatureMessageX962SHA384,
            .ecdsaSignatureMessageX962SHA512,
            .rsaEncryptionRaw,
            .rsaEncryptionPKCS1,
            .rsaEncryptionOAEPSHA1,
            .rsaEncryptionOAEPSHA224,
            .rsaEncryptionOAEPSHA256,
            .rsaEncryptionOAEPSHA384,
            .rsaEncryptionOAEPSHA512,
            .rsaEncryptionOAEPSHA1AESGCM,
            .rsaEncryptionOAEPSHA224AESGCM,
            .rsaEncryptionOAEPSHA256AESGCM,
            .rsaEncryptionOAEPSHA384AESGCM,
            .rsaEncryptionOAEPSHA512AESGCM,
            .eciesEncryptionStandardX963SHA1AESGCM,
            .eciesEncryptionStandardX963SHA224AESGCM,
            .eciesEncryptionStandardX963SHA256AESGCM,
            .eciesEncryptionStandardX963SHA384AESGCM,
            .eciesEncryptionStandardX963SHA512AESGCM,
            .eciesEncryptionCofactorX963SHA1AESGCM,
            .eciesEncryptionCofactorX963SHA224AESGCM,
            .eciesEncryptionCofactorX963SHA256AESGCM,
            .eciesEncryptionCofactorX963SHA384AESGCM,
            .eciesEncryptionCofactorX963SHA512AESGCM,
            .eciesEncryptionStandardVariableIVX963SHA224AESGCM,
            .eciesEncryptionStandardVariableIVX963SHA256AESGCM,
            .eciesEncryptionStandardVariableIVX963SHA384AESGCM,
            .eciesEncryptionStandardVariableIVX963SHA512AESGCM,
            .eciesEncryptionCofactorVariableIVX963SHA224AESGCM,
            .eciesEncryptionCofactorVariableIVX963SHA256AESGCM,
            .eciesEncryptionCofactorVariableIVX963SHA384AESGCM,
            .eciesEncryptionCofactorVariableIVX963SHA512AESGCM,
            .ecdhKeyExchangeStandard,
            .ecdhKeyExchangeStandardX963SHA1,
            .ecdhKeyExchangeStandardX963SHA224,
            .ecdhKeyExchangeStandardX963SHA256,
            .ecdhKeyExchangeStandardX963SHA384,
            .ecdhKeyExchangeStandardX963SHA512,
            .ecdhKeyExchangeCofactor,
            .ecdhKeyExchangeCofactorX963SHA1,
            .ecdhKeyExchangeCofactorX963SHA224,
            .ecdhKeyExchangeCofactorX963SHA256,
            .ecdhKeyExchangeCofactorX963SHA384,
            .ecdhKeyExchangeCofactorX963SHA512
        ]
        
        for a in algorithms {
            if SecKeyIsAlgorithmSupported(key, .decrypt, a) {
                print(">>>>>>>>>>>>> supported algorithm: \(a)")
            }
        }
        
        //==================
        
        let algorithm: SecKeyAlgorithm = .rsaEncryptionPKCS1 // .rsaSignatureMessagePKCS1v15SHA256 // .rsaSignatureDigestPKCS1v15SHA1 // .rsaSignatureDigestPKCS1v15Raw // .rsaSignatureDigestPKCS1v15SHA256 //.rsaEncryptionPKCS1
        
//        guard SecKeyIsAlgorithmSupported(key, .decrypt, algorithm) else {
//            print("Can't decrypt. Algorithm not supported.")
//            return nil
//        }

        var error: Unmanaged<CFError>? = nil
        let clearTextData = SecKeyCreateDecryptedData(key,
                                                      algorithm,
                                                      cipherTextData as CFData,
                                                      &error) as Data?
        if let error = error {
            print("Can't decrypt. \((error.takeRetainedValue() as Error).localizedDescription)")
            return nil
        }
        guard clearTextData != nil else {
            print("Can't decrypt. No resulting cleartextData.")
            return nil
        }
        print("Decrypted data.")
        return clearTextData
    }

If your code only works on Mac OS, you may be able to create a Seckey by using the SecKeyCreateFromData method instead of the SecKeyCreateWithData method.

Here is Sample Code:

    func getPublicKey(from data: Data?) throws -> SecKey {
        var error: Unmanaged<CFError>? = nil
        guard let data = data else { throw error!.takeRetainedValue() as Error }
        let publicKeyMaybe = SecKeyCreateFromData([:] as CFDictionary, data as NSData, &error)
        guard let publicKey = publicKeyMaybe else {
            throw error!.takeRetainedValue() as Error
        }
        return publicKey
    }

And You should convert RSA public key string to data using ASCII encoding.

let pubKey = try! getPublicKey(from: kPubKey.data(using: .ascii))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM