我一直在尝试使用iOS中的CommonCrypto
对更大的Data
对象进行逐块解密,但是我无法使其正常工作。我一直在阅读documentation,并查看了Objective-C
中的几个示例-我都没有设法在Objective-C
环境中工作。经过3天的编码后,我开始疲惫不堪,需要一些帮助。
我可以使用CCCrypto
方法进行精细的解密和加密,但是由于我使用的文件很大,因此iOS占用了过多的内存,因此我无法使用此方法。因此,我需要更有效地执行此操作,因此我决定尝试一种方法,一次解密一个块,然后用生成的数据块替换解密的块。代码可以运行,除了我得到的数据不会解码回UTF8 String
以外,它似乎可以正常工作。
mutating func decryptUsingCCCryptoCreate() {
// Get the first 16 bytes as IV
let IV = self.prefix(kCCBlockSizeAES128)
// Get key as array of bytes
let key = "ABCDEFGHIJKLMNOPQRSABCDEFGHIJKLM".data(using: .utf8) ?? Data()
// Setup totalSize
let totalSize = self.count
let operation = kCCDecrypt
let algorithm = kCCAlgorithmAES
let options = kCCOptionPKCS7Padding
var cryptorRef: CCCryptorRef?
// Step one is to create the CCCryptor with correct parameters for AES128 decryption
var status = CCCryptorCreate(CCOperation(operation), CCAlgorithm(algorithm), CCOptions(options), key.withUnsafeBytes { $0.baseAddress }, key.count, IV.withUnsafeBytes { $0.baseAddress }, &cryptorRef)
if status != kCCSuccess {
print("Failed on create: \(status.description)")
return
}
var dataOutMoved: size_t = 0 // The actual data moved
var dataInLength: size_t = kCCBlockSizeAES128 // The in size will always be the size of a kCCBlockSizeAES128
var dataOutLength: size_t = CCCryptorGetOutputLength(cryptorRef, dataInLength, false) // DataOutLength is always less than or equal to the dataInLength
var totalLength: size_t = 0 // The actual length of the deciphered data
var filePtr: size_t = 0 // Keeps track of the current position in the deciphering process
var startByte: Int = 0 // Increments each time with the kCCBlockSizeAES128 until we are done
var dataIn = Data() // Buffer to store the encrypted block to be deciphered
var dataOut = Data() // Buffer to store the decrypted block result
// While startByte is less than totalSize we continue to decrypt the next block
while startByte <= totalSize {
if startByte + kCCBlockSizeAES128 > totalSize {
dataInLength = totalSize - startByte
} else {
dataInLength = kCCBlockSizeAES128
}
// Next block to decrypt
guard let rangeToDecrypt = Range(NSRange(location: startByte, length: dataInLength)) else { return }
dataIn = self.subdata(in: rangeToDecrypt)
// Decipher the block
status = CCCryptorUpdate(cryptorRef, dataIn.withUnsafeBytes { $0.baseAddress }, dataInLength, dataOut.withUnsafeMutableBytes { $0.baseAddress }, dataOutLength, &dataOutMoved)
if status != kCCSuccess {
print("Failed on Update: \(status.description)")
return
}
// Replace the encrypted block with the decrypted block
let rangeToReplace = Range(NSRange(location: filePtr, length: dataOutMoved))!
self.replaceSubrange(rangeToReplace, with: dataOut.withUnsafeBytes { $0.baseAddress! }, count: dataOutMoved)
totalLength += dataOutMoved
filePtr += dataOutMoved
startByte += kCCBlockSizeAES128
}
// Finalize the deciphering
status = CCCryptorFinal(cryptorRef, dataOut.withUnsafeMutableBytes { $0.baseAddress }, dataOutLength, &dataOutMoved)
totalLength += dataOutMoved
if status != kCCSuccess {
print("Failed on final: \(status.description)")
return
}
// We replace the final deciphered block
let decryptedRange = Range(NSRange(location: filePtr, length: dataOutMoved))!
self.replaceSubrange(decryptedRange, with: dataOut.withUnsafeBytes { $0.baseAddress! }, count: dataOut.count)
// Since we are using padding the CCCryptorFinal can contain padding which needs to be truncated.
self = self.prefix(totalLength)
// Finish the CCCryptor process
CCCryptorRelease(cryptorRef)
}
mutating func encryptUsingCCCrypto() {
let sa = String(data: self, encoding: .utf8) ?? ""
print("Before encryption: \(sa)")
let now = Date()
let key = "ABCDEFGHIJKLMNOPQRSABCDEFGHIJKLM".data(using: .utf8) ?? Data()
let ivRandomData = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
let blockSize = kCCBlockSizeAES128
let bufferSize = self.count + blockSize
var encryptedSize = 0
let cryptStatus = CCCrypt(UInt32(kCCEncrypt),
UInt32(kCCAlgorithmAES),
UInt32(kCCOptionPKCS7Padding),
key.withUnsafeBytes { $0.baseAddress },
key.count,
ivRandomData.withUnsafeBytes { $0.baseAddress },
self.withUnsafeBytes { $0.baseAddress },
self.count,
self.withUnsafeMutableBytes { $0.baseAddress },
bufferSize,
&encryptedSize)
self = self.prefix(encryptedSize)
let s = String(data: self, encoding: .utf8) ?? ""
print("Result: \(s)")
}
我使用如下代码:
let string = "1234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234"
var data = string.data(using: .utf8) ?? Data()
data.encryptUsingCCCrypto()
data.decryptUsingCCCryptoCreate() // I get a Data object with 112 bytes here
let s = String(data: data, encoding: .utf8) ?? "" // String is nil, and is provided ""