swift - 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
解决方案
推荐阅读
- python - Plotly Dash 中的堆积条形图
- heroku - 提出动画师heroku部署问题
- firebase - 如何在上传文件 Firebase 存储之前选择最接近用户位置的存储桶?(扑)
- amazon-web-services - 我们应该如何在 AWS 无服务器框架中配置 apigateway--> step function proxy?
- python - 使用从 URL 获取的数据填写 Django 表单
- go - 用 go 实现冒泡排序
- php - OpenCart:请求的数据库数据未显示,但行数是否正确?
- python - 如何通过第二维拆分二维数组?(Python)
- angularjs - AngularJS 禁用默认表单提交钩子
- python - Python API 和 sql,没有按预期工作,sqlite 中的数据错误