CCCrypt iOS Swift 3中的奇怪行为

时间:2017-04-20 05:42:53

标签: ios iphone swift

我在使用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)

对这种奇怪的行为有任何想法。我是否需要进行任何重置或延迟?

1 个答案:

答案 0 :(得分:2)

您的代码中有什么不好用withUnsafeByteswithUnsafeMutableBytes的所有这些用法:

    let keyBytes          = keyData.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> UnsafePointer<UInt8> in
        return bytes
    }

检查withUnsafeBytes的参考:

withUnsafeBytes(_:)

  

警告

     

不应在闭包调用的生命周期之外存储和使用字节指针参数。

(您可以为withUnsafeMutableBytes找到相同的警告。)

withUnsafeByteswithUnsafeMutableBytes的所有用法都将指针参数置于闭包之外,这可能会导致任何意外行为,包括崩溃。

withUnsafeByteswithUnsafeMutableBytes的正确用法是这样的:

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