Swift AES 通用加密 - AES 解密过程中的前 16 个字符被省略

Swift AES Common crypto - First 16 characters during AES decryption gets omitted

尝试在 swift 中使用 AES(普通密码)执行加密和解密,由于某些原因,解密前 16 个字符被删除。任何人都可以看看下面的游乐场代码并提出这里可能出了什么问题吗?。 decodedString 变量在解密过程中删除原始 payloadString 的前 16 个字符。

游乐场代码

import UIKit
import CommonCrypto

class AESNew {

    enum MyError: LocalizedError {
        case first(message: String)
        case second(message: String)

        var errorDescription: String? { return "Some description here!" }
    }
    
    func encrypt(plainText: String, keyData:Data, iv: Data, options:Int = kCCOptionPKCS7Padding) -> Result<Data, Error> {
        let plainData = Data(plainText.utf8)
            
        if let cryptData = NSMutableData(length: Int((plainData.count)) + kCCBlockSizeAES128) {

            let keyLength              = size_t(kCCKeySizeAES128)
            let operation: CCOperation = UInt32(kCCEncrypt)
            let algoritm:  CCAlgorithm = UInt32(kCCAlgorithmAES128)
            let options:   CCOptions   = UInt32(options)
            
            var numBytesEncrypted :size_t = 0
            
            //let value = iv.withUnsafeBytes { [=11=].load(as: UInt32.self) }
            
            let cryptResult = iv.withUnsafeBytes { (dataBytes : UnsafePointer<UInt8>) -> Result<Data, Error> in
                
                print(dataBytes)
                
                print(UnsafeRawPointer(dataBytes))
                
                let cryptStatus = CCCrypt(operation,
                                          algoritm,
                                          options,
                                          (keyData as NSData).bytes,
                                          keyLength,
                                          UnsafeRawPointer(dataBytes),
                                          (plainData as NSData).bytes, plainData.count,
                                          cryptData.mutableBytes, cryptData.length,
                                          &numBytesEncrypted)
                
                if UInt32(cryptStatus) == UInt32(kCCSuccess) {
                    cryptData.length = Int(numBytesEncrypted)
                    let base64cryptString = cryptData.base64EncodedString(options: .lineLength64Characters)
                    print("base64cryptString: \(base64cryptString)")
                    return .success(cryptData as Data)
                } else {
                    print("failure")
                    return .failure(MyError.first(message: "crypt failed"))
                }
            }
            
            return cryptResult
        
        }
        return .failure(MyError.second(message: "no value failure"))
    }

    // The iv is prefixed to the encrypted data
    func decrypt(data: Data, keyData: Data) throws -> Data? {
        let keyLength = keyData.count
        let validKeyLengths = [kCCKeySizeAES128, kCCKeySizeAES192, kCCKeySizeAES256]
        if validKeyLengths.contains(keyLength) == false {
            print("validKeyLengths does not match")
        }

        let ivSize = kCCBlockSizeAES128
        let clearLength = size_t(data.count - ivSize)
        var clearData = Data(count: clearLength)

        var numBytesDecrypted: size_t = 0
        let options   = CCOptions(kCCOptionPKCS7Padding)

        let cryptStatus = clearData.withUnsafeMutableBytes {cryptBytes in
            data.withUnsafeBytes {dataBytes in
                keyData.withUnsafeBytes {keyBytes in
                    CCCrypt(CCOperation(kCCDecrypt),
                            CCAlgorithm(kCCAlgorithmAES128),
                            options,
                            keyBytes,
                            keyLength,
                            dataBytes,
                            dataBytes+kCCBlockSizeAES128,
                            clearLength,
                            cryptBytes,
                            clearLength,
                            &numBytesDecrypted)
                }
            }
        }
        
        if UInt32(cryptStatus) == UInt32(kCCSuccess) {
            clearData.count = numBytesDecrypted
        } else {
            print("Decryption failed")
        }
        return clearData
    }
}

func randomGenerateBytes(count: Int) -> Data? {
    let bytes = UnsafeMutableRawPointer.allocate(byteCount: count, alignment: 1)
    defer { bytes.deallocate() }
    let status = CCRandomGenerateBytes(bytes, count)
    guard status == kCCSuccess else { return nil }
    return Data(bytes: bytes, count: count)
}

var ivBytesNew = Data()

if let ivBytes = randomGenerateBytes(count: 16) {
    ivBytesNew = ivBytes
} else {
    print("randomGenerateBytes failed")
}

let keyString   = "keyData890123456"
let keyData   = "keyData890123456".data(using:String.Encoding.utf8)!

let payloadString = "asdflkasfdkaslfd12345"

let aesObject = AESNew()

let encrytedObject = aesObject.encrypt(plainText: payloadString, keyData: keyData, iv: ivBytesNew, options: kCCOptionPKCS7Padding)

var encryptedData = Data()

switch encrytedObject {
case .success(let encData):
    print(encData)
    encryptedData = encData
case .failure(let error):
    print(error)
default:
    print("enc failed")
}

if let decrypedData = try? aesObject.decrypt(data: encryptedData, keyData: keyData) {
    if let decodedString = String(data: decrypedData, encoding: .utf8) {
        print(decodedString) // 1234, first 16 characters are omitted. 
    } else {
        print("conversion from data to string failed")
    }
} else {
    print("decryption failed")
}

看来你选择了两种不同的加密和解密。

您是否看到您的 decrypt 没有 AES 解密所需的参数 iv

您的 decrypt 期望 data 的前 16 个字节为 iv,其余为加密数据。但是你的encryptreturns只是加密数据。

请尝试按如下方式更改调用 decrypt 的线路:

if let decrypedData = try? aesObject.decrypt(data: ivBytesNew + encryptedData, keyData: keyData) {

通常,您的 encrypt 使用 NSMutableData 和处理 bytes 不当。这是脆弱的,它可能会在某些不同的上下文中崩溃。我强烈建议您不要使用当前的 encrypt.

无论如何,你应该使 encryptdecrypt 一致,或者说是对称的,目前它们不是。