Swift 5 + kCCDecrypt(CommonCrypto):无法解密 [英] Swift 5 + kCCDecrypt (CommonCrypto): Failing to decrypt
问题描述
基于大量其他类似问题,尝试在 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屋!