使用CommonCrypto的Swift 5 AES加密/解密

时间:2019-06-20 19:51:04

标签: objective-c swift aes commoncrypto

我一直在尝试使用iOS中的CommonCrypto对更大的Data对象进行逐块解密,但是我无法使其正常工作。我一直在阅读documentation,并查看了Objective-C中的几个示例-我都没有设法在Objective-C环境中工作。经过3天的编码后,我开始疲惫不堪,需要一些帮助。

我可以使用CCCrypto方法进行精细的解密和加密,但是由于我使用的文件很大,因此iOS占用了过多的内存,因此我无法使用此方法。因此,我需要更有效地执行此操作,因此我决定尝试一种方法,一次解密一个块,然后用生成的数据块替换解密的块。代码可以运行,除了我得到的数据不会解码回UTF8 String以外,它似乎可以正常工作。

使用CCCryptoCreate()和对称块解密(DataExtension)的代码

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

使用CCCrypto()进行加密的代码

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 ""

0 个答案:

没有答案