Swift 5 + kCCDecrypt(CommonCrypto):无法解密

问题描述 投票:0回答:1

试图在Swift 5中编写我自己的加密/解密函数,基于大量其他类似的问题 - 并且失败了。

我正在使用CommonCrypto + CCCrypt来加密/解密(AES,256键,随机iv)。

我赞成NSData.bytes而不是withUnsafeBytes(这只是too confusing中的Swift 5)。

我的encrypt函数是这样的:

func encrypt(_ string: String) throws -> Data {
    guard let dataToEncrypt: Data = string.data(using: .utf8) else {
        throw AESError.stringToDataFailed
    }

    // Seems like the easiest way to avoid the `withUnsafeBytes` mess is to use NSData.bytes.
    let dataToEncryptNSData = NSData(data: dataToEncrypt)

    let bufferSize: Int = ivSize + dataToEncryptNSData.length + kCCBlockSizeAES128
    let buffer = UnsafeMutablePointer<NSData>.allocate(capacity: bufferSize)
    defer { buffer.deallocate() }

    let status: Int32 = SecRandomCopyBytes(
        kSecRandomDefault,
        kCCBlockSizeAES128,
        buffer
    )
    guard status == 0 else {
        throw AESError.generateRandomIVFailed
    }

    var numberBytesEncrypted: Int = 0

    let cryptStatus: CCCryptorStatus = CCCrypt( // Stateless, one-shot encrypt operation
        CCOperation(kCCEncrypt),                // op: CCOperation
        CCAlgorithm(kCCAlgorithmAES),           // alg: CCAlgorithm
        options,                                // options: CCOptions
        key.bytes,                              // key: the "password"
        key.length,                             // keyLength: the "password" size
        buffer,                                 // iv: Initialization Vector
        dataToEncryptNSData.bytes,              // dataIn: Data to encrypt bytes
        dataToEncryptNSData.length,             // dataInLength: Data to encrypt size
        buffer + kCCBlockSizeAES128,            // dataOut: encrypted Data buffer
        bufferSize,                             // dataOutAvailable: encrypted Data buffer size
        &numberBytesEncrypted                   // dataOutMoved: the number of bytes written
    )

    guard cryptStatus == CCCryptorStatus(kCCSuccess) else {
        throw AESError.encryptDataFailed
    }

    return Data(bytes: buffer, count: numberBytesEncrypted + ivSize)
}

decrypt功能:

func decrypt(_ data: Data) throws -> String {

    // Seems like the easiest way to avoid the `withUnsafeBytes` mess is to use NSData.bytes.
    let dataToDecryptNSData = NSData(data: data)

    let bufferSize: Int = dataToDecryptNSData.length - ivSize
    let buffer = UnsafeMutablePointer<NSData>.allocate(capacity: bufferSize)
    defer { buffer.deallocate() }

    var numberBytesDecrypted: Int = 0

    let cryptStatus: CCCryptorStatus = CCCrypt(         // Stateless, one-shot encrypt operation
        CCOperation(kCCDecrypt),                        // op: CCOperation
        CCAlgorithm(kCCAlgorithmAES128),                // alg: CCAlgorithm
        options,                                        // options: CCOptions
        key.bytes,                                      // key: the "password"
        key.length,                                     // keyLength: the "password" size
        dataToDecryptNSData.bytes,                      // iv: Initialization Vector
        dataToDecryptNSData.bytes + kCCBlockSizeAES128, // dataIn: Data to decrypt bytes
        bufferSize,                                     // dataInLength: Data to decrypt size
        buffer,                                         // dataOut: decrypted Data buffer
        bufferSize,                                     // dataOutAvailable: decrypted Data buffer size
        &numberBytesDecrypted                           // dataOutMoved: the number of bytes written
    )

    guard cryptStatus == CCCryptorStatus(kCCSuccess) else {
        throw AESError.decryptDataFailed
    }

    let decryptedData = Data(bytes: buffer, count: numberBytesDecrypted)

    guard let decryptedString = String(data: decryptedData, encoding: .utf8) else {
        throw AESError.dataToStringFailed
    }

    return decryptedString
}

那些是基于用户“@zaph”的this awesome answer

虽然encrypt似乎正在运作,但decrypt失败了。

这条专线:

guard let decryptedString = String(data: decryptedData, encoding: .utf8) else {
    throw AESError.dataToStringFailed
}

所以当然我错过了什么,但我无法弄清楚它是什么。您可以...吗?

这是包含整个代码的pastebin,您可以在Playground中复制/粘贴并点击播放。 Swift 5是必需的:https://pastebin.com/raw/h6gacaHX

更新 我现在正在关注@ OOper的建议方法。最终的代码可以在这里看到: https://github.com/backslash-f/aescryptable

aes commoncrypto swift5
1个回答
2
投票

事实上,使用Data.withUnsafeBytes在Swift 5中有点乱,虽然NSData.bytes不是最简单的方法,因为使用它有时看起来有效,有时候不行。

如果你想在swift中使用Data.withUnsafeBytes编写一个始终有效的代码,你需要习惯使用Data

struct AES {
    private let key: Data //<- Use `Data` instead of `NSData`

    private let ivSize: Int                     = kCCBlockSizeAES128
    private let options: CCOptions              = CCOptions(kCCOptionPKCS7Padding)

    init(keyString: String) throws {
        guard keyString.count == kCCKeySizeAES256 else {
            throw AESError.invalidKeySize
        }
        guard let keyData: Data = keyString.data(using: .utf8) else {
            throw AESError.stringToDataFailed
        }
        self.key = keyData
    }
}

extension AES: Cryptable {

    func encrypt(_ string: String) throws -> Data {
        guard let dataToEncrypt: Data = string.data(using: .utf8) else {
            throw AESError.stringToDataFailed
        }

        let bufferSize: Int = ivSize + dataToEncrypt.count + kCCBlockSizeAES128
        var buffer = Data(count: bufferSize)

        let status: Int32 = buffer.withUnsafeMutableBytes {bytes in
            SecRandomCopyBytes(
                kSecRandomDefault,
                kCCBlockSizeAES128,
                bytes.baseAddress!
            )
        }
        guard status == 0 else {
            throw AESError.generateRandomIVFailed
        }

        var numberBytesEncrypted: Int = 0

        let cryptStatus: CCCryptorStatus = key.withUnsafeBytes {keyBytes in
            dataToEncrypt.withUnsafeBytes {dataBytes in
                buffer.withUnsafeMutableBytes {bufferBytes in
                    CCCrypt( // Stateless, one-shot encrypt operation
                        CCOperation(kCCEncrypt),                // op: CCOperation
                        CCAlgorithm(kCCAlgorithmAES),           // alg: CCAlgorithm
                        options,                                // options: CCOptions
                        keyBytes.baseAddress,                   // key: the "password"
                        key.count,                              // keyLength: the "password" size
                        bufferBytes.baseAddress,                // iv: Initialization Vector
                        dataBytes.baseAddress,                  // dataIn: Data to encrypt bytes
                        dataToEncrypt.count,                    // dataInLength: Data to encrypt size
                        bufferBytes.baseAddress! + kCCBlockSizeAES128, // dataOut: encrypted Data buffer
                        bufferSize,                             // dataOutAvailable: encrypted Data buffer size
                        &numberBytesEncrypted                   // dataOutMoved: the number of bytes written
                    )
                }
            }
        }

        guard cryptStatus == CCCryptorStatus(kCCSuccess) else {
            throw AESError.encryptDataFailed
        }

        return buffer[..<(numberBytesEncrypted + ivSize)]
    }

    func decrypt(_ data: Data) throws -> String {

        let bufferSize: Int = data.count - ivSize
        var buffer = Data(count: bufferSize)

        var numberBytesDecrypted: Int = 0

        let cryptStatus: CCCryptorStatus = key.withUnsafeBytes {keyBytes in
            data.withUnsafeBytes {dataBytes in
                buffer.withUnsafeMutableBytes {bufferBytes in
                    CCCrypt(         // Stateless, one-shot encrypt operation
                        CCOperation(kCCDecrypt),                        // op: CCOperation
                        CCAlgorithm(kCCAlgorithmAES128),                // alg: CCAlgorithm
                        options,                                        // options: CCOptions
                        keyBytes.baseAddress,                           // key: the "password"
                        key.count,                                      // keyLength: the "password" size
                        dataBytes.baseAddress,                          // iv: Initialization Vector
                        dataBytes.baseAddress! + kCCBlockSizeAES128,    // dataIn: Data to decrypt bytes
                        bufferSize,                                     // dataInLength: Data to decrypt size
                        bufferBytes.baseAddress,                        // dataOut: decrypted Data buffer
                        bufferSize,                                     // dataOutAvailable: decrypted Data buffer size
                        &numberBytesDecrypted                           // dataOutMoved: the number of bytes written
                    )
                }
            }
        }

        guard cryptStatus == CCCryptorStatus(kCCSuccess) else {
            throw AESError.decryptDataFailed
        }

        let decryptedData = buffer[..<numberBytesDecrypted]

        guard let decryptedString = String(data: decryptedData, encoding: .utf8) else {
            throw AESError.dataToStringFailed
        }

        return decryptedString
    }

}
© www.soinside.com 2019 - 2024. All rights reserved.