首页 > 解决方案 > CryptoSwift 未能部分解密

问题描述

我目前正在使用 AES-128 CBC 模式实现部分解密。我使用了 3 个不同的库和 2 个不同的本地方法来解密。到目前为止,所有这些都在我似乎无法修复的这一块上失败了。

请看一下代码 -

protocol AESDecrypting {
    var name: String { get }
    func decryptData(_ data: Data, withKey key: Data, startingBlock: Int,
                     numberOfBlocks: Int) -> Data?
    func decryptData(_ data: Data, withKey key: Data) -> Data?
}

protocol AESEncrypting {
    var name: String { get }
    func encryptData(_ data: Data, withKey key: Data) -> Data?
}

struct CryptoSwiftDecryption: AESDecrypting, AESEncrypting {
    
    let name = "CryptoSwiftDecryption"
    
    func decryptData(_ data: Data, withKey key: Data, startingBlock: Int,
                     numberOfBlocks: Int) -> Data? {
        
        guard numberOfBlocks > 0 && startingBlock >= 0 else {
            return nil
        }
        
        let startingPoint = (startingBlock * kCCBlockSizeAES128)
        guard startingPoint < data.count else {
            return nil
        }
        
        let endingPoint = min(
            startingPoint + (numberOfBlocks * kCCBlockSizeAES128) + kCCBlockSizeAES128,
            data.count)
        
        let dataToUse = data.subdata(in: startingPoint..<endingPoint)
        return decryptData(dataToUse, withKey: key)
    }
    
    func decryptData(_ data: Data, withKey key: Data) -> Data? {
        let keyBites: [UInt8] = key.bytes
        let iv = data.subdata(in: 0..<16).bytes
        let contentPortion = data.subdata(in: 16..<data.count)
        do {
            let aes = try AES(key: keyBites, blockMode: CBC(iv: iv), padding: .pkcs7)
            let decryptedBytes = try aes.decrypt(contentPortion.bytes)
            return Data(decryptedBytes)
        } catch {
            print(error)
            return nil
        }
    }
    
    func encryptData(_ data: Data, withKey key: Data) -> Data? {
        do {
            let keyBites: [UInt8] = key.bytes
            let iv: [UInt8] = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
            let aes = try AES(key: keyBites, blockMode: CBC(iv: iv), padding: .pkcs7)
            let encryptedBytes = try aes.encrypt(data.bytes)
            return Data(iv) + Data(encryptedBytes)
        } catch {
            print(error)
            return nil
        }
    }
    
}

现在这里是测试。到目前为止,它适用于除块号 22 之外的所有内容,同时在逐块解密后比较结果。

import XCTest
import CommonCrypto

class PartialAESDecryptionTests: XCTestCase {
  
  private let crypto = CryptoSwiftDecryption()
  
  lazy private var fullyDecryptedString: String = {
    return """
      <?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n<head>\n\t<title>CHAPTER I -- Metamorphosis </title>\n\t<meta http-equiv=\"Content-Type\" content=\"application/xhtml+xml; charset=utf-8\" />\n\t<meta name=\"EPB-UUID\" content=\"\" />\n\n\t<link rel=\"stylesheet\" href=\"jackson.css\" type=\"text/css\" />\n</head>\n<body>\n<div class=\"chapter introduction type-1\" id=\"chapter-i\"><div class=\"chapter-title-wrap\"><h3
      """
  }()
  
  lazy private var fullyDecryptedData: Data = {
    return fullyDecryptedString.data(using: .utf8)!
  }()
  
  lazy private var inputData: Data = {
    return crypto.encryptData(fullyDecryptedData, withKey: keyData)!
  }()
  
  lazy private var keyData: Data = {
    return "keyData890123456".data(using: .utf8)!
  }()
  
  override func setUp() {
    super.setUp()
    continueAfterFailure = true
  }
  
  func testDecryptingEntireFile() {
    
    let expected = fullyDecryptedString
    let actual = decrypt(inputData, keyData, crypto)
    
    XCTAssertEqual(expected, actual)
  }
  
  func testDecryptingOneBlockFromBeginning() {
    let startingBlock = 0
    let numberOfBlocks = 1

    let expected = usableBlockFromGivenDecryptedFile(startingBlock, numberOfBlocks)
    let result = decrypt(
      inputData, keyData, startingBlock: startingBlock, numberOfBlocks: numberOfBlocks, crypto)

    XCTAssertEqual(result, expected)
  }

  func testDecryptingThreeBlocksFromBeginning() {
    let startingBlock = 0
    let numberOfBlocks = 3

    let expected = usableBlockFromGivenDecryptedFile(startingBlock, numberOfBlocks)
    let result = decrypt(
      inputData, keyData, startingBlock: startingBlock, numberOfBlocks: numberOfBlocks, crypto)

    XCTAssertEqual(result, expected)
  }

  func testDecryptingSecondThirdForthBlock() {
    let startingBlock = 1
    let numberOfBlocks = 3

    let expected = usableBlockFromGivenDecryptedFile(startingBlock, numberOfBlocks)
    let result = decrypt(
      inputData, keyData, startingBlock: startingBlock, numberOfBlocks: numberOfBlocks, crypto)

    XCTAssertEqual(result, expected)
  }

  func testDecryptingOneBlockInMiddle() {
    let startingBlock = 10
    let numberOfBlocks = 1

    let expected = usableBlockFromGivenDecryptedFile(startingBlock, numberOfBlocks)
    let result = decrypt(
      inputData, keyData, startingBlock: startingBlock, numberOfBlocks: numberOfBlocks, crypto)

    XCTAssertEqual(result, expected)
  }

  func testDecryptingThreeBlocksInMiddle() {
    let startingBlock = 10
    let numberOfBlocks = 3

    let expected = usableBlockFromGivenDecryptedFile(startingBlock, numberOfBlocks)
    let result = decrypt(
      inputData, keyData, startingBlock: startingBlock, numberOfBlocks: numberOfBlocks, crypto)

    XCTAssertEqual(result, expected)
  }

  func testComparingBlockByBlock() {
    let totalBlocks = Int(inputData.count/kCCBlockSizeAES128) + 1
    let numberOfBlocks = 1
    
    for startingBlock in 0..<totalBlocks {
      let expected = usableBlockFromGivenDecryptedFile(startingBlock, numberOfBlocks)
      let result = decrypt(
        inputData, keyData, startingBlock: startingBlock, numberOfBlocks: numberOfBlocks, crypto)
      XCTAssertEqual(expected, result, "\(startingBlock)")
    }
  }

//  // MARK: - Helper Methods
  private func decrypt(_ data: Data, _ key: Data, _ decryptor: AESDecrypting) -> String? {
    guard
      let decrypted = decryptor.decryptData(data, withKey: key) else {
      print("\(decryptor.name) failed to decrypt")
      return nil
    }

    guard let result = String(data: decrypted, encoding: .utf8) else {
      print("\(decryptor.name) failed to convert to string")
      return nil
    }
    return result
  }

  private func decrypt(_ data: Data, _ key: Data, startingBlock: Int, numberOfBlocks: Int, _ decryptor: AESDecrypting) -> String? {
    guard
      let decrypted = decryptor
        .decryptData(data, withKey: keyData,
                     startingBlock: startingBlock,
                     numberOfBlocks: numberOfBlocks)
    else {
      print("\(decryptor.name) failed to decrypt")
      return nil
    }

    guard let result = String(data: decrypted, encoding: .utf8) else {
      print("\(decryptor.name) failed to convert to string")
      return nil
    }
    return result
  }

  private func usableBlockFromGivenDecryptedFile(_ startingBlock: Int, _ numberOfBlocks: Int) -> String? {
    let blockSize = kCCBlockSizeAES128
    let startingPoint = (startingBlock * blockSize)
    guard startingPoint < fullyDecryptedData.count else {
      return nil
    }
    let endingPoint = min(startingPoint + (numberOfBlocks * blockSize), fullyDecryptedData.count)
    let dataToUse = fullyDecryptedData.subdata(in: startingPoint..<endingPoint)
    return String(data: dataToUse, encoding: .utf8) ?? nil
  }
  
}

所有其他测试均通过。唯一失败的测试是testComparingBlockByBlock在第 22 块。在我失去理智之前,请告诉我我做错了什么。

我在测试中看到了这个

  • XCTAssertEqual 失败:("Optional(" content="" />\n\n")") 不等于 ("Optional(" conte")") - 22

标签: swiftaes

解决方案


推荐阅读