我在使用SWIFT 3进行加密和解密时遇到了奇怪的行为 我正在使用以下方法来加密和解密一个字符串。虽然加密我生成一个随机盐并将其添加到加密数据的末尾,而在解密时我正从数据中读取IV数据来解密并执行解密操作
internal func cryptography(_ inputData: Data, key: String, operation: CCOperation) -> Data? {
//prepare the Key
let keyData: Data! = key.data(using: String.Encoding.utf8, allowLossyConversion: false)!
let keyBytes = keyData.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> UnsafePointer<UInt8> in
return bytes
}
let keyLength = size_t(kCCKeySizeAES128)
//Prepare the input data
//Check whether this is encryption , if so generate a random IV and append this to the encrypted data
let ivBuffer:UnsafePointer<UInt8>?
let dataBytes: UnsafePointer<UInt8>?
var dataLength :Int? = 0
var ivData :Data? = nil
if (operation == CCOperation(kCCEncrypt)){
ivData = self.generateIV()
ivBuffer = (ivData == nil) ? nil : ivData!.withUnsafeBytes({ (bytes: UnsafePointer<UInt8>) -> UnsafePointer<UInt8> in
return bytes
})
dataBytes = inputData.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> UnsafePointer<UInt8> in
return bytes
}
dataLength = Int(inputData.count)
}
else{
//for decryption the last 16 bytes will be the IV so extract it
var dataToProcess = inputData
let rangStart = inputData.count - kCCBlockSizeAES128
let rangeEnd = rangStart + kCCBlockSizeAES128
var range = Range(rangStart..<rangeEnd)
ivData = inputData.subdata(in:range)
ivBuffer = ivData?.withUnsafeBytes({ (bytes: UnsafePointer<UInt8>) -> UnsafePointer<UInt8> in
return bytes
})
range = Range(0..<rangStart)
dataToProcess = inputData.subdata(in: range)
dataBytes = dataToProcess.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> UnsafePointer<UInt8> in
return bytes
}
dataLength = Int(dataToProcess.count)
}
//Calculate buffer details
var bufferData = Data(count: Int(dataLength!) + kCCBlockSizeAES128)
let bufferPointer = bufferData.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer<UInt8>) -> UnsafeMutablePointer<UInt8> in
return bytes
}
let bufferLength = size_t(bufferData.count)
var bytesDecrypted = Int(0)
let tst = CCCryptorStatus()
let cryptStatus = CCCrypt(
operation, // Operation
CCAlgorithm(kCCAlgorithmAES128), // Algorithm is AES
CCOptions(kCCOptionPKCS7Padding), //options
keyBytes, // key data
keyLength, // key length
ivBuffer, // IV buffer
dataBytes, // input data
dataLength!, // input length
bufferPointer, // output buffer
bufferLength, // output buffer length
&bytesDecrypted) // output bytes decrypted real length
if Int32(cryptStatus) == Int32(kCCSuccess) {
bufferData.count = bytesDecrypted // Adjust buffer size to real bytes
if (operation == CCOperation(kCCEncrypt)){
bufferData.append(ivData!)
}
return bufferData as Data
} else {
print("Error in crypto operation: \(cryptStatus)")
return nil
}
}
现在出现了奇怪的行为。 我两次调用此方法,首先用于加密,第二次用于解密从前一次调用返回的加密字符串。
现在如果我运行此代码然后加密将成功发生,但解密返回无效数据 - 这里的cryptStatus成功但bytesDecrypted显示为16并且转换此tostring返回nil。
现在奇怪的是,如果我在加密的else部分放置一个断点(即从加密的String中提取IV的方法),即在下面的最后一行,那么如果使用po打印dataToProcess和ivData到console,然后解密正确发生。
//for decryption the last 16 bytes will be the IV so extract it
var dataToProcess = inputData
let rangStart = inputData.count - kCCBlockSizeAES128
let rangeEnd = rangStart + kCCBlockSizeAES128
var range = Range(rangStart..<rangeEnd)
ivData = inputData.subdata(in:range)
ivBuffer = ivData?.withUnsafeBytes({ (bytes: UnsafePointer<UInt8>) -> UnsafePointer<UInt8> in
return bytes
})
range = Range(0..<rangStart)
dataToProcess = inputData.subdata(in: range)
dataBytes = dataToProcess.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> UnsafePointer<UInt8> in
return bytes
}
dataLength = Int(dataToProcess.count)
对这种奇怪的行为有任何想法。我是否需要进行任何重置或延迟?
答案 0 :(得分:2)
您的代码中有什么不好用withUnsafeBytes
或withUnsafeMutableBytes
的所有这些用法:
let keyBytes = keyData.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> UnsafePointer<UInt8> in
return bytes
}
检查withUnsafeBytes
的参考:
警告
不应在闭包调用的生命周期之外存储和使用字节指针参数。
(您可以为withUnsafeMutableBytes
找到相同的警告。)
withUnsafeBytes
或withUnsafeMutableBytes
的所有用法都将指针参数置于闭包之外,这可能会导致任何意外行为,包括崩溃。
withUnsafeBytes
或withUnsafeMutableBytes
的正确用法是这样的:
func cryptography(_ inputData: Data, key: String, operation: CCOperation) -> Data? {
//prepare the Key
let keyData = key.data(using: .utf8, allowLossyConversion: false)!
let keyLength = kCCKeySizeAES128
//Prepare the input data
//Check whether this is encryption , if so generate a random IV and append this to the encrypted data
let ivData :Data
let data: Data
if operation == CCOperation(kCCEncrypt) {
ivData = self.generateIV()
data = inputData
} else {
//for decryption the last 16 bytes will be the IV so extract it
let rangStart = inputData.count - kCCBlockSizeAES128
let rangeEnd = inputData.count
ivData = inputData.subdata(in: rangStart..<rangeEnd)
data = inputData.subdata(in: 0..<rangStart)
}
let dataLength = data.count
//Calculate buffer details
var bufferData = Data(count: dataLength + kCCBlockSizeAES128)
let bufferLength = bufferData.count
var bytesDecrypted = 0
let cryptStatus = keyData.withUnsafeBytes {keyBytes in
ivData.withUnsafeBytes {ivBuffer in
data.withUnsafeBytes {dataBytes in
bufferData.withUnsafeMutableBytes {bufferPointer in
CCCrypt(
operation, // Operation
CCAlgorithm(kCCAlgorithmAES128), // Algorithm is AES
CCOptions(kCCOptionPKCS7Padding), //options
keyBytes, // key data
keyLength, // key length
ivBuffer, // IV buffer
dataBytes, // input data
dataLength, // input length
bufferPointer, // output buffer
bufferLength, // output buffer length
&bytesDecrypted) // output bytes decrypted real length
}
}
}
}
if cryptStatus == Int32(kCCSuccess) {
bufferData.count = bytesDecrypted // Adjust buffer size to real bytes
if operation == CCOperation(kCCEncrypt) {
bufferData.append(ivData)
}
return bufferData
} else {
print("Error in crypto operation: \(cryptStatus)")
return nil
}
}