Шифрование / дешифрование Swift 5 AES с использованием CommonCrypto - PullRequest
1 голос
/ 20 июня 2019

Я пытался использовать CommonCrypto в iOS, чтобы выполнить блочную расшифровку более крупного Data объекта, но я не могу заставить его работать.Я читал документацию и посмотрел несколько примеров из 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 ""
...