Swift 5 + kCCDecrypt(CommonCrypto):无法解密 [英] Swift 5 + kCCDecrypt (CommonCrypto): Failing to decrypt

查看:172
本文介绍了Swift 5 + kCCDecrypt(CommonCrypto):无法解密的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



我正在使用 CommonCrypto + CCCrypt 进行加密/解密(AES,256密钥,

withUnsafeBytes 相比,我更喜欢 NSData.bytes c $ c>(这只是 Swift 5 中太混乱了



我的加密函数如下:

  func crypto(_ string:字符串)抛出->数据{
卫队让dataToEncrypt:数据= string.data(使用:.utf8)否则{
抛出AESError.stringToDataFailed
}

//似乎最简单避免 withUnsafeBytes混乱的方法是使用NSData.bytes。
let dataToEncryptNSData = NSData(数据:dataToEncrypt)

let bufferSize:Int = ivSize + dataToEncryptNSData.length + kCCBlockSizeAES128
let buffer = UnsafeMutablePointer< NSData> .allocate(容量:bufferSize )
延迟{buffer.deallocate()}

let状态:Int32 = SecRandomCopyBytes(
kSecRandomDefault,
kCCBlockSizeAES128,
buffer

保护状态== 0否则{
抛出AESError.generateRandomIVFailed
}

var numberBytesEncrypted:Int = 0

让cryptStatus:CCCryptorStatus = CCCrypt(//无状态,一次性加密操作
CCOperation(kCCEncrypt),// op:CCOperation
CCAlgorithm(kCCAlgorithmAES),// alg:CCAlgorithm
选项,//选项: CCOptions
key.bytes,//密钥:密码
key.length, // // keyLength:密码大小
缓冲区,// iv:初始化矢量
dataToEncryptNSData.bytes,// dataIn:用于加密字节的数据
dataToEncryptNSData.length,// dataInLength:Data加密大小
缓冲区+ kCCBlockSizeAES128,// dataOut:加密的数据缓冲区
bufferSize,// dataOutAvailable:加密的数据缓冲区大小
& numberBytesEncrypted // dataOutMoved:写入的字节数


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

return Data(bytes:缓冲区,计数:numberBytesEncrypted + ivSize)
}

解密函数:

 函数解密(_ data:Data)抛出-> String {

// //似乎最简单的避免withWithUnsafeBytes混乱的方法是使用NSData.bytes。
let dataToDecryptNSData = NSData(数据:数据)

let bufferSize:整数= dataToDecryptNSData.length-ivSize
let buffer = UnsafeMutablePointer< NSData> .allocate(容量:bufferSize)
defer {buffer.deallocate()}

var numberBytesDecrypted:Int = 0

let cryptStatus:CCCryptorStatus = CCCrypt(//无状态,一次性加密操作
CCOperation(kCCDecrypt),// op:CCOperation
CCAlgorithm(kCCAlgorithmAES128),// alg:CCAlgorithm
选项,//选项:CCOptions
key.bytes,//键: 密码
key.length,// keyLength:密码大小
dataToDecryptNSData.bytes,// iv:初始化向量
dataToDecryptNSData.bytes + kCCBlockSizeAES128,// dataIn:Data解密字节
bufferSize,// dataInLength:要解密的数据
buffer,// dataOut:解密的数据缓冲区
bufferSize,// dataOutAvailable:解密的数据缓冲区
& numberBytesDecrypted // dataOutMoved:写入的字节数


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

letcryptedData =数据(字节(缓冲区:缓冲区,计数:numberBytesDecrypted))

保护let letcryptedString =字符串(数据:decryptedData,编码:.utf8),否则{
抛出AESError.dataToStringFailed
}

返回解密的字符串
}

是基于用户 @@的这个很棒的答案 zaph。



虽然加密似乎有效,但解密失败。



此行具体是:

 警卫让cryptedString =字符串(数据:decryptedData,编码:.utf8),否则{
抛出AESError.dataToStringFailed
}

所以我当然缺少了一些东西,但我不知道它是什么。



这是带有完整代码的粘贴框,您可以将其复制/粘贴到Playground中并进行播放。 Swift 5 是必需的: https://pastebin.com/ raw / h6gacaHX


更新

我现在关注@ OOper建议的方法。最终的代码可以在这里看到:

https://github.com/backslash -f / aescryptable



解决方案

实际上,使用 Data.withUnsafeBytes 在Swift 5中有点混乱,尽管 NSData.bytes 可能不是最简单的方法



您需要习惯使用 Data.withUnsafeBytes 如果要使用 Data 在Swift中编写始终有效的代码。

  struct AES {
private let key:Data //<-使用`Data`代替`NSData`

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

init(keyString:String)抛出{
保护keyString.count == kCCKeySizeAES256其他{
抛出AESError.invalidKeySize
}
保护让keyData:数据= keyString.data(使用:.utf8)否则{
抛出AESError.stringToDataFailed
}
自我。 key = keyData
}
}

扩展名AES:加密表{

func crypto(_ string:String)throws->数据{
保护let dataToEncrypt:数据= string.data(使用:.utf8)否则{
抛出AESError.stringToDataFailed
}

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

let status:Int32 = buffer.withUnsafeMutableBytes {
中的字节SecRandomCopyBytes(
kSecRandomDefault,
kCCBlockSizeAES128,
bytes.baseAddress!

}
保护状态== 0否则{
抛出AESError.generateRandomIVFailed
}

var numberBytesEncrypted:Int = 0

让cryptStatus:CCCryptorStatus = key.withUnsafeBytes {keybytes in
dataToEncrypt.withUnsafeBytes {dataBytes in
buffer.withUnsafeMutableBytes {bufferBytes in
CCCrypt(//无状态,一次加密ypt操作
CCOperation(kCCEncrypt),// op:CCOperation
CCAlgorithm(kCCAlgorithmAES),// alg:CCAlgorithm
选项,//选项:CCOptions
keyBytes.baseAddress,/ /键:密码
key.count,// keyLength:密码大小
bufferBytes.baseAddress,// iv:初始化向量
dataBytes.baseAddress,// dataIn:要加密的数据字节
dataToEncrypt.count,// dataInLength:要加密的数据大小
bufferBytes.baseAddress! + kCCBlockSizeAES128,// dataOut:加密的数据缓冲区
bufferSize,// dataOutAvailable:加密的数据缓冲区大小
& numberBytesEncrypted // dataOutMoved:写入的字节数

}
}
}

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

返回buffer [..<(numberBytesEncrypted + ivSize)]
}

func crypto(_ data:Data)抛出->字符串{

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

var numberBytesDecrypted:Int = 0

let cryptStatus:CCCryptorStatus = key.withUnsafeBytes {keybytes在
data.withUnsafeBytes {dataBytes在
buffer.withUnsafeMutableBytes {bufferBytes在
CCCrypt(//无状态,一次性加密操作
CCOperation(kCCDecrypt),// op:CCOperation
CCAlgorithm(kCCAlgorithmAES128),// alg:CCAlgorithm
选项,//选项:CCOptions
keyBytes.baseAddress,// key:密码
key.count,// keyLength:密码大小
dataBy tes.baseAddress,// iv:初始化向量
dataBytes.baseAddress! + kCCBlockSizeAES128,// dataIn:要解密的数据
bufferSize,// dataInLength:要解密的数据
bufferBytes.baseAddress,// dataOut:解密后的数据缓冲区
bufferSize,// dataOutAvailable:解密的数据缓冲区大小
& numberBytesDecrypted // dataOutMoved:写入的字节数

}
}
}

保护cryptStatus == CCCryptorStatus(kCCSuccess)否则{
抛出AESError.decryptDataFailed
}

letcryptedData = buffer [..< numberBytesDecrypted]

保护unlockedString =字符串(数据:decryptedData,编码:.utf8),否则{
抛出AESError.dataToStringFailed
}

返回解密字符串
}

}


Trying to write my own encrypt/decrypt functions in Swift 5, based on tons of other similar questions -- and failing miserably.

I'm using CommonCrypto + CCCrypt to encrypt/decrypt (AES, 256 key, random iv).

I'm favouring NSData.bytes over withUnsafeBytes (which is just too confusing in Swift 5).

My encrypt function goes like this:

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)
}

The decrypt function:

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
}

Those were based on this awesome answer from the user "@zaph".

Although encrypt seems to be working, decrypt fails.

This line specifically:

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

So of course I'm missing something, but I can't figure out what it is. Could you?

Here is the pastebin with the entire code, which you could copy/paste in a Playground and hit play. Swift 5 is required: https://pastebin.com/raw/h6gacaHX

Update
I'm now following @OOper's suggested approach. The final code can be seen here:
https://github.com/backslash-f/aescryptable

解决方案

In fact, using Data.withUnsafeBytes is sort of a mess in Swift 5, though NSData.bytes cannot be the easiest way, as using it would sometimes seemingly work, and sometimes not.

You need to be accustomed work with Data.withUnsafeBytes if you want to write an always-works code in Swift with 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
    }

}

这篇关于Swift 5 + kCCDecrypt(CommonCrypto):无法解密的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆