【发布时间】:2019-08-24 08:19:26
【问题描述】:
基于大量其他类似问题,尝试在Swift 5 中编写我自己的加密/解密函数——结果惨遭失败。
我正在使用CommonCrypto + CCCrypt 来加密/解密(AES,256 密钥,随机 iv)。
我更喜欢NSData.bytes 而不是withUnsafeBytes(这只是Swift 5 中的too confusing)。
我的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
【问题讨论】:
-
NSData.bytes可能无法满足您的期望。如果你想编写在 Swift 中稳定运行的代码,千万不要使用它。
标签: aes commoncrypto swift5