快速的 AES 加密

Posted

技术标签:

【中文标题】快速的 AES 加密【英文标题】:AES encryption in swift 【发布时间】:2016-10-07 09:57:29 【问题描述】:

我正在尝试快速实现 AES 加密。 android 和 C# 的加密解密工作正常。我需要迅速实施它。 android 是current code,后面是C#。

我尝试使用

    CryptoSwift Cross platform AES encryption

但这些都不起作用。当我在服务器上发送加密字符串时,它没有被解密。

任何帮助将不胜感激

【问题讨论】:

只是比较工作实现的输出。提供各种操作模式下的 AES 标准测试向量。 @TruthSerum 我试图比较加密的值,但它不匹配。我无权访问android代码,所以我也无法调试它。我刚刚得到这个链接作为参考,我已经添加了问题 然后看输入参数。您将拥有一个 16 字节的明文块、一个 16-20 字节的密钥(取决于 AES-128、AES-256 等变体)和一个 IV 初始化向量。对于每个块,所有三个都需要匹配。您还需要确保版本之间的填充协议相同。 我只收到kCCOptionPKCS7Padding。如何使用 CBC 模式将其设置为 PKCS5 填充?检查过,但也没有找到任何解决方案 解密和加密需要使用相同的填充模式。如果您的 API 不支持它,您将不得不自己实现它。这可能涉及取消填充错误的格式,然后重新填充为正确的格式。同样,您会找到测试向量来验证它在每个阶段都能正常工作。 【参考方案1】:

请务必使用相同的参数,这些参数似乎是 AES 和 CBC 模式,带有 iv、PKCS5Padding(实际上是 PKCS#7)填充和 16 字节(128 位)密钥。

PKCS#5 填充和PKCS#7 填充基本相同,有时出于历史原因,PKCS#5 填充被指定用于 AES,但实际填充是 PKCS#7。

确保密钥、iv 和加密数据的编码全部匹配。十六进制将它们转储到两个平台上以确保它们相同。加密函数并不难用,只要输入参数正确,输出就正确。

为了使这更安全,iv 应该是随机字节,并添加到加密数据之前,以便在解密期间使用。

跨平台 AES 加密使用 256 位密钥,因此无法按原样工作。

例子:

斯威夫特 2

// operation: kCCEncrypt or kCCDecrypt
func testCrypt(data data:[UInt8], keyData:[UInt8], ivData:[UInt8], operation:Int) -> [UInt8]? 
    let cryptLength  = size_t(data.count+kCCBlockSizeAES128)
    var cryptData    = [UInt8](count:cryptLength, repeatedValue:0)

    let keyLength             = size_t(kCCKeySizeAES128)
    let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128)
    let options:  CCOptions   = UInt32(kCCOptionPKCS7Padding)

    var numBytesEncrypted :size_t = 0

    let cryptStatus = CCCrypt(CCOperation(operation),
                              algoritm,
                              options,
                              keyData, keyLength,
                              ivData,
                              data, data.count,
                              &cryptData, cryptLength,
                              &numBytesEncrypted)

    if UInt32(cryptStatus) == UInt32(kCCSuccess) 
        cryptData.removeRange(numBytesEncrypted..<cryptData.count)

     else 
        print("Error: \(cryptStatus)")
    

    return cryptData;


let message       = "Don´t try to read this text. Top Secret Stuff"
let messageData   = Array(message.utf8)
let keyData       = Array("12345678901234567890123456789012".utf8)
let ivData        = Array("abcdefghijklmnop".utf8)
let encryptedData = testCrypt(data:messageData,   keyData:keyData, ivData:ivData, operation:kCCEncrypt)!
let decryptedData = testCrypt(data:encryptedData, keyData:keyData, ivData:ivData, operation:kCCDecrypt)!
var decrypted     = String(bytes:decryptedData, encoding:NSUTF8StringEncoding)!

print("message:       \(message)");
print("messageData:   \(NSData(bytes:messageData,   length:messageData.count))");
print("keyData:       \(NSData(bytes:keyData,       length:keyData.count))");
print("ivData:        \(NSData(bytes:ivData,        length:ivData.count))");
print("encryptedData: \(NSData(bytes:encryptedData, length:encryptedData.count))");
print("decryptedData: \(NSData(bytes:decryptedData, length:decryptedData.count))");
print("decrypted:     \(String(bytes:decryptedData,encoding:NSUTF8StringEncoding)!)");

输出:

信息:不要尝试阅读此文本。绝密的东西 消息数据:446f6ec2 b4742074 72792074 6f207265 61642074 68697320 74657874 2e20546f 70205365 63726574 20537475 6666 关键数据:31323334 35363738 39303132 33343536 37383930 31323334 35363738 39303132 ivData:61626364 65666768 696a6b6c 6d6e6f70 加密数据:b1b6dc17 62eaf3f8 baa1cb87 21ddc35c dee803ed fb320020 85794848 21206943 a85feb5b c8ee58fc d6fb664b 96b81114 解密数据:446f6ec2 b4742074 72792074 6f207265 61642074 68697320 74657874 2e20546f 70205365 63726574 20537475 6666 解密:不要尝试阅读此文本。绝密的东西

[UInt8] 类型的 Swift 3

func testCrypt(data:[UInt8], keyData:[UInt8], ivData:[UInt8], operation:Int) -> [UInt8]? 
    let cryptLength  = size_t(data.count+kCCBlockSizeAES128)
    var cryptData    = [UInt8](repeating:0, count:cryptLength)

    let keyLength             = size_t(kCCKeySizeAES128)
    let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128)
    let options:  CCOptions   = UInt32(kCCOptionPKCS7Padding)

    var numBytesEncrypted :size_t = 0

    let cryptStatus = CCCrypt(CCOperation(operation),
                              algoritm,
                              options,
                              keyData, keyLength,
                              ivData,
                              data, data.count,
                              &cryptData, cryptLength,
                              &numBytesEncrypted)

    if UInt32(cryptStatus) == UInt32(kCCSuccess) 
        cryptData.removeSubrange(numBytesEncrypted..<cryptData.count)

     else 
        print("Error: \(cryptStatus)")
    

    return cryptData;

Data 类型的 Swift 3 和 4

func testCrypt(data:Data, keyData:Data, ivData:Data, operation:Int) -> Data 
    let cryptLength  = size_t(data.count + kCCBlockSizeAES128)
    var cryptData = Data(count:cryptLength)

    let keyLength             = size_t(kCCKeySizeAES128)
    let options   = CCOptions(kCCOptionPKCS7Padding)


    var numBytesEncrypted :size_t = 0

    let cryptStatus = cryptData.withUnsafeMutableBytes cryptBytes in
        data.withUnsafeBytes dataBytes in
            ivData.withUnsafeBytes ivBytes in
                keyData.withUnsafeBytes keyBytes in
                    CCCrypt(CCOperation(operation),
                              CCAlgorithm(kCCAlgorithmAES),
                              options,
                              keyBytes, keyLength,
                              ivBytes,
                              dataBytes, data.count,
                              cryptBytes, cryptLength,
                              &numBytesEncrypted)
                
            
        
    

    if UInt32(cryptStatus) == UInt32(kCCSuccess) 
        cryptData.removeSubrange(numBytesEncrypted..<cryptData.count)

     else 
        print("Error: \(cryptStatus)")
    

    return cryptData;


let message     = "Don´t try to read this text. Top Secret Stuff"
let messageData = message.data(using:String.Encoding.utf8)!
let keyData     = "12345678901234567890123456789012".data(using:String.Encoding.utf8)!
let ivData      = "abcdefghijklmnop".data(using:String.Encoding.utf8)!

let encryptedData = testCrypt(data:messageData,   keyData:keyData, ivData:ivData, operation:kCCEncrypt)
let decryptedData = testCrypt(data:encryptedData, keyData:keyData, ivData:ivData, operation:kCCDecrypt)
var decrypted     = String(bytes:decryptedData, encoding:String.Encoding.utf8)!

日落文档部分的示例:

CBC 模式下的 AES 加密,带有随机 IV (Swift 3+)

iv 是加密数据的前缀

aesCBC128Encrypt 将创建一个随机 IV 并作为加密代码的前缀。aesCBC128Decrypt 将在解密期间使用前缀 IV。

输入是数据,键是数据对象。如果需要在调用方法中转换为和/或从编码形式(如 Base64)。

密钥的长度应为 128 位(16 字节)、192 位(24 字节)或 256 位(32 字节)。如果使用其他密钥大小,则会引发错误。

PKCS#7 padding是默认设置的。

此示例需要 Common Crypto 项目必须有桥接头:#import &lt;CommonCrypto/CommonCrypto.h&gt;Security.framework 添加到项目中。

这是示例,不是生产代码。

enum AESError: Error 
    case KeyError((String, Int))
    case IVError((String, Int))
    case CryptorError((String, Int))


// The iv is prefixed to the encrypted data
func aesCBCEncrypt(data:Data, keyData:Data) throws -> Data 
    let keyLength = keyData.count
    let validKeyLengths = [kCCKeySizeAES128, kCCKeySizeAES192, kCCKeySizeAES256]
    if (validKeyLengths.contains(keyLength) == false) 
        throw AESError.KeyError(("Invalid key length", keyLength))
    

    let ivSize = kCCBlockSizeAES128;
    let cryptLength = size_t(ivSize + data.count + kCCBlockSizeAES128)
    var cryptData = Data(count:cryptLength)

    let status = cryptData.withUnsafeMutableBytes ivBytes in
        SecRandomCopyBytes(kSecRandomDefault, kCCBlockSizeAES128, ivBytes)
    
    if (status != 0) 
        throw AESError.IVError(("IV generation failed", Int(status)))
    

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

    let cryptStatus = cryptData.withUnsafeMutableBytes cryptBytes in
        data.withUnsafeBytes dataBytes in
            keyData.withUnsafeBytes keyBytes in
                CCCrypt(CCOperation(kCCEncrypt),
                        CCAlgorithm(kCCAlgorithmAES),
                        options,
                        keyBytes, keyLength,
                        cryptBytes,
                        dataBytes, data.count,
                        cryptBytes+kCCBlockSizeAES128, cryptLength,
                        &numBytesEncrypted)
            
        
    

    if UInt32(cryptStatus) == UInt32(kCCSuccess) 
        cryptData.count = numBytesEncrypted + ivSize
    
    else 
        throw AESError.CryptorError(("Encryption failed", Int(cryptStatus)))
    

    return cryptData;


// The iv is prefixed to the encrypted data
func aesCBCDecrypt(data:Data, keyData:Data) throws -> Data? 
    let keyLength = keyData.count
    let validKeyLengths = [kCCKeySizeAES128, kCCKeySizeAES192, kCCKeySizeAES256]
    if (validKeyLengths.contains(keyLength) == false) 
        throw AESError.KeyError(("Invalid key length", keyLength))
    

    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 
        throw AESError.CryptorError(("Decryption failed", Int(cryptStatus)))
    

    return clearData;

示例用法:

let clearData = "clearData0123456".data(using:String.Encoding.utf8)!
let keyData   = "keyData890123456".data(using:String.Encoding.utf8)!
print("clearData:   \(clearData as NSData)")
print("keyData:     \(keyData as NSData)")

var cryptData :Data?
do 
    cryptData = try aesCBCEncrypt(data:clearData, keyData:keyData)
    print("cryptData:   \(cryptData! as NSData)")

catch (let status) 
    print("Error aesCBCEncrypt: \(status)")


let decryptData :Data?
do 
    let decryptData = try aesCBCDecrypt(data:cryptData!, keyData:keyData)
    print("decryptData: \(decryptData! as NSData)")

catch (let status) 
    print("Error aesCBCDecrypt: \(status)")

示例输出:

clearData:   <636c6561 72446174 61303132 33343536>
keyData:     <6b657944 61746138 39303132 33343536>
cryptData:   <92c57393 f454d959 5a4d158f 6e1cd3e7 77986ee9 b2970f49 2bafcf1a 8ee9d51a bde49c31 d7780256 71837a61 60fa4be0>
decryptData: <636c6561 72446174 61303132 33343536>

注意事项: CBC 模式示例代码的一个典型问题是,它将随机 IV 的创建和共享留给用户。此示例包括生成 IV、为加密数据添加前缀并在解密期间使用前缀 IV。这将临时用户从CBC mode 所需的详细信息中解放出来。

为了安全起见,加密数据也应该具有身份验证功能,此示例代码不提供此功能,以便更小并允许与其他平台更好的互操作性。

还缺少从密码中导出密钥的密钥,建议使用PBKDF2,将文本密码用作密钥材料。

有关强大的生产就绪多平台加密代码,请参阅RNCryptor。

【讨论】:

实现包含 ECB 模式。如何设置CBC模式? 连例子都包含ECB模式。 let options: CCOptions = UInt32(kCCOptionECBMode + kCCOptionPKCS7Padding),代码块不适用于我的情况 看答案中的例子,没有ECB。 请帮忙。我想要字符串中的加密。我试图将 [UInt8] 转换为 String,但它返回 nil。请帮忙。如何获取加密字符串值 并非所有字节都可以表示为可打印字符,并且大多数字节不能表示为 unicode 字符。加密是一种数据操作,输出本质上是随机的 8 位字节,因此不能直接表示为字符串字符。答案是将加密的输出转换为不同的编码,Base64 和十六进制是常用的编码,在解密时将字符串表示转换回[Uint8]【参考方案2】:

斯威夫特 5

我重构了 @ingconti 的代码。

import Foundation
import CommonCrypto

struct AES 

    // MARK: - Value
    // MARK: Private
    private let key: Data
    private let iv: Data


    // MARK: - Initialzier
    init?(key: String, iv: String) 
        guard key.count == kCCKeySizeAES128 || key.count == kCCKeySizeAES256, let keyData = key.data(using: .utf8) else 
            debugPrint("Error: Failed to set a key.")
            return nil
        

        guard iv.count == kCCBlockSizeAES128, let ivData = iv.data(using: .utf8) else 
            debugPrint("Error: Failed to set an initial vector.")
            return nil
        


        self.key = keyData
        self.iv  = ivData
    


    // MARK: - Function
    // MARK: Public
    func encrypt(string: String) -> Data? 
        return crypt(data: string.data(using: .utf8), option: CCOperation(kCCEncrypt))
    

    func decrypt(data: Data?) -> String? 
        guard let decryptedData = crypt(data: data, option: CCOperation(kCCDecrypt)) else  return nil 
        return String(bytes: decryptedData, encoding: .utf8)
    

    func crypt(data: Data?, option: CCOperation) -> Data? 
        guard let data = data else  return nil 

        let cryptLength = data.count + kCCBlockSizeAES128
        var cryptData   = Data(count: cryptLength)

        let keyLength = key.count
        let options   = CCOptions(kCCOptionPKCS7Padding)

        var bytesLength = Int(0)

        let status = cryptData.withUnsafeMutableBytes  cryptBytes in
            data.withUnsafeBytes  dataBytes in
                iv.withUnsafeBytes  ivBytes in
                    key.withUnsafeBytes  keyBytes in
                    CCCrypt(option, CCAlgorithm(kCCAlgorithmAES), options, keyBytes.baseAddress, keyLength, ivBytes.baseAddress, dataBytes.baseAddress, data.count, cryptBytes.baseAddress, cryptLength, &bytesLength)
                    
                
            
        

        guard UInt32(status) == UInt32(kCCSuccess) else 
            debugPrint("Error: Failed to crypt data. Status \(status)")
            return nil
        

        cryptData.removeSubrange(bytesLength..<cryptData.count)
        return cryptData
    


这样使用

let password = "UserPassword1!"
let key128   = "1234567890123456"                   // 16 bytes for AES128
let key256   = "12345678901234561234567890123456"   // 32 bytes for AES256
let iv       = "abcdefghijklmnop"                   // 16 bytes for AES128

let aes128 = AES(key: key128, iv: iv)
let aes256 = AES(key: key256, iv: iv)

let encryptedPassword128 = aes128?.encrypt(string: password)
aes128?.decrypt(data: encryptedPassword128)

let encryptedPassword256 = aes256?.encrypt(string: password)
aes256?.decrypt(data: encryptedPassword256)

结果

【讨论】:

key(key128/key256)iv有什么区别 我需要用一些唯一的密钥加密一些信息并将其发送回服务器,在服务器端可以使用相同的密钥对其进行解密,但我无法从此代码中获取加密字符串- 'let encryptedPassword128 = aes128?.encrypt(string: password)' @Den 但是在迁移到 Swift 5.0 后,它显示警告为.. withUnsafeBytes' 已弃用:使用 withUnsafeBytes (_: (UnsafeRawBufferPointer) throws -> R) rethrows -> R 代替 嗨,我用 C# 创建了 key256 和 iv。我得到 c9 d7 eb c0 0f 77 ca 56 56 69 83 64 6b 19 86 cb 86 54 c7 d3 03 da e2 20 58 c4 04 b2 67 78 f2 82 作为 aes256 的字节。如何在您的代码中使用这些字节? :)【参考方案3】:

根据 @zaph 的好答案,我创建了这个 Playground 用于:

斯威夫特 5

import Foundation
import CommonCrypto

protocol Cryptable 
    func encrypt(_ string: String) throws -> Data
    func decrypt(_ data: Data) throws -> String


struct AES 
    private let key: Data
    private let ivSize: Int         = kCCBlockSizeAES128
    private let options: CCOptions  = CCOptions(kCCOptionPKCS7Padding)

    init(keyString: String) throws 
        guard keyString.count == kCCKeySizeAES256 else 
            throw Error.invalidKeySize
        
        self.key = Data(keyString.utf8)
    


extension AES 
    enum Error: Swift.Error 
        case invalidKeySize
        case generateRandomIVFailed
        case encryptionFailed
        case decryptionFailed
        case dataToStringFailed
    


private extension AES 

    func generateRandomIV(for data: inout Data) throws 

        try data.withUnsafeMutableBytes  dataBytes in

            guard let dataBytesBaseAddress = dataBytes.baseAddress else 
                throw Error.generateRandomIVFailed
            

            let status: Int32 = SecRandomCopyBytes(
                kSecRandomDefault,
                kCCBlockSizeAES128,
                dataBytesBaseAddress
            )

            guard status == 0 else 
                throw Error.generateRandomIVFailed
            
        
    


extension AES: Cryptable 

    func encrypt(_ string: String) throws -> Data 
        let dataToEncrypt = Data(string.utf8)

        let bufferSize: Int = ivSize + dataToEncrypt.count + kCCBlockSizeAES128
        var buffer = Data(count: bufferSize)
        try generateRandomIV(for: &buffer)

        var numberBytesEncrypted: Int = 0

        do 
            try key.withUnsafeBytes  keyBytes in
                try dataToEncrypt.withUnsafeBytes  dataToEncryptBytes in
                    try buffer.withUnsafeMutableBytes  bufferBytes in

                        guard let keyBytesBaseAddress = keyBytes.baseAddress,
                            let dataToEncryptBytesBaseAddress = dataToEncryptBytes.baseAddress,
                            let bufferBytesBaseAddress = bufferBytes.baseAddress else 
                                throw Error.encryptionFailed
                        

                        let cryptStatus: CCCryptorStatus = CCCrypt( // Stateless, one-shot encrypt operation
                            CCOperation(kCCEncrypt),                // op: CCOperation
                            CCAlgorithm(kCCAlgorithmAES),           // alg: CCAlgorithm
                            options,                                // options: CCOptions
                            keyBytesBaseAddress,                    // key: the "password"
                            key.count,                              // keyLength: the "password" size
                            bufferBytesBaseAddress,                 // iv: Initialization Vector
                            dataToEncryptBytesBaseAddress,          // dataIn: Data to encrypt bytes
                            dataToEncryptBytes.count,               // dataInLength: Data to encrypt size
                            bufferBytesBaseAddress + ivSize,        // dataOut: encrypted Data buffer
                            bufferSize,                             // dataOutAvailable: encrypted Data buffer size
                            &numberBytesEncrypted                   // dataOutMoved: the number of bytes written
                        )

                        guard cryptStatus == CCCryptorStatus(kCCSuccess) else 
                            throw Error.encryptionFailed
                        
                    
                
            

         catch 
            throw Error.encryptionFailed
        

        let encryptedData: Data = buffer[..<(numberBytesEncrypted + ivSize)]
        return encryptedData
    

    func decrypt(_ data: Data) throws -> String 

        let bufferSize: Int = data.count - ivSize
        var buffer = Data(count: bufferSize)

        var numberBytesDecrypted: Int = 0

        do 
            try key.withUnsafeBytes  keyBytes in
                try data.withUnsafeBytes  dataToDecryptBytes in
                    try buffer.withUnsafeMutableBytes  bufferBytes in

                        guard let keyBytesBaseAddress = keyBytes.baseAddress,
                            let dataToDecryptBytesBaseAddress = dataToDecryptBytes.baseAddress,
                            let bufferBytesBaseAddress = bufferBytes.baseAddress else 
                                throw Error.encryptionFailed
                        

                        let cryptStatus: CCCryptorStatus = CCCrypt( // Stateless, one-shot encrypt operation
                            CCOperation(kCCDecrypt),                // op: CCOperation
                            CCAlgorithm(kCCAlgorithmAES128),        // alg: CCAlgorithm
                            options,                                // options: CCOptions
                            keyBytesBaseAddress,                    // key: the "password"
                            key.count,                              // keyLength: the "password" size
                            dataToDecryptBytesBaseAddress,          // iv: Initialization Vector
                            dataToDecryptBytesBaseAddress + ivSize, // dataIn: Data to decrypt bytes
                            bufferSize,                             // dataInLength: Data to decrypt size
                            bufferBytesBaseAddress,                 // dataOut: decrypted Data buffer
                            bufferSize,                             // dataOutAvailable: decrypted Data buffer size
                            &numberBytesDecrypted                   // dataOutMoved: the number of bytes written
                        )

                        guard cryptStatus == CCCryptorStatus(kCCSuccess) else 
                            throw Error.decryptionFailed
                        
                    
                
            
         catch 
            throw Error.encryptionFailed
        

        let decryptedData: Data = buffer[..<numberBytesDecrypted]

        guard let decryptedString = String(data: decryptedData, encoding: .utf8) else 
            throw Error.dataToStringFailed
        

        return decryptedString
    


do 
    let aes = try AES(keyString: "FiugQTgPNwCWUY,VhfmM4cKXTLVFvHFe")

    let stringToEncrypt: String = "please encrypt meeee"
    print("String to encrypt:\t\t\t\(stringToEncrypt)")

    let encryptedData: Data = try aes.encrypt(stringToEncrypt)
    print("String encrypted (base64):\t\(encryptedData.base64EncodedString())")

    let decryptedData: String = try aes.decrypt(encryptedData)
    print("String decrypted:\t\t\t\(decryptedData)")

 catch 
    print("Something went wrong: \(error)")

输出:

我还基于它创建了一个Swift Package

https://github.com/backslash-f/aescryptable✌?

【讨论】:

stringToDataFailed 毫无意义。字符串转换为 utf8 数据永远不会失败。 self.key = Data(keyString.utf8)let dataToEncrypt = Data(string.utf8)。顺便说一句,我会在您的 AES 结构中声明 AES 错误枚举,然后将其重命名为 Error。然后,当SelfAES 时,您可以将其称为AES.Error.whatever 或简称为Error.whateverextension AES enum Error: Swift.Error case invalidKeySize, generateRandomIVFailed, encryptionFailed, decryptionFailed, dataToStringFailed 这些都是很好的建议。我相应地更改了代码。谢谢。 @backslash-f 在上面的代码中使用时出现“dataToStringFailed”错误。请帮助我在过去 4 天被卡住了。 @Vasu 我刚刚在 Playground 中运行了上面的代码,它似乎工作正常。您尝试加密/解密的确切字符串是什么? @backslash-f 解密不起作用,来自服务器的加密字符串我正在使用您的解密方法解密但收到此错误“dataToStringFailed”。【参考方案4】:

我的两分钱:

数据的 swift 4 / xcode 9 扩展:

extension Data

    func aesEncrypt( keyData: Data, ivData: Data, operation: Int) -> Data 
        let dataLength = self.count
        let cryptLength  = size_t(dataLength + kCCBlockSizeAES128)
        var cryptData = Data(count:cryptLength)

        let keyLength = size_t(kCCKeySizeAES128)
        let options = CCOptions(kCCOptionPKCS7Padding)


        var numBytesEncrypted :size_t = 0

        let cryptStatus = cryptData.withUnsafeMutableBytes cryptBytes in
            self.withUnsafeBytes dataBytes in
                ivData.withUnsafeBytes ivBytes in
                    keyData.withUnsafeBytes keyBytes in
                        CCCrypt(CCOperation(operation),
                                CCAlgorithm(kCCAlgorithmAES),
                                options,
                                keyBytes, keyLength,
                                ivBytes,
                                dataBytes, dataLength,
                                cryptBytes, cryptLength,
                                &numBytesEncrypted)
                    
                
            
        

        if UInt32(cryptStatus) == UInt32(kCCSuccess) 
            cryptData.removeSubrange(numBytesEncrypted..<cryptData.count)

         else 
            print("Error: \(cryptStatus)")
        

        return cryptData;
    






    func testAES() -> Bool 

        let message     = "secret message"
        let key         = "key890123456"
        let ivString     = "abcdefghijklmnop"   // 16 bytes for AES128

        let messageData = message.data(using:String.Encoding.utf8)!
        let keyData     = key.data(using: .utf8)!
        let ivData      = ivString.data(using: .utf8)!

        let encryptedData = messageData.aesEncrypt( keyData:keyData, ivData:ivData, operation:kCCEncrypt)
        let decryptedData = encryptedData.aesEncrypt( keyData:keyData, ivData:ivData, operation:kCCDecrypt)
        let decrypted     = String(bytes:decryptedData, encoding:String.Encoding.utf8)!

        return message == decrypted

    

【讨论】:

1.密钥应该是正确的长度,在代码中给出kCCKeySizeAES128 的 16 字节。不应依赖未记录的密钥扩展。 2. 这是一个被接受的答案的例子,它包含在一个没有归属的扩展中。但很高兴@ingconti 认为适合使用我的代码。 ? key(key128/key256)iv有什么区别【参考方案5】:

我用过 CryptoSwift。

首先我在 pod 文件中安装了 cryptoSwift。然后在我的视图控制器中,我导入了 CryptoSwift。

这是我使用的代码:

let value = "xyzzy".  // This is the value that we want to encrypt
let key = "abc".      // This is the key 

let EncryptedValue = try! value.aesEncrypt(key: key)
let DecryptedValue = try! EncryptedValue.aesDecrypt(key: key)

然后,使用字符串扩展:

extension String 

    func aesEncrypt(key: String) throws -> String 

        var result = ""

        do 

            let key: [UInt8] = Array(key.utf8) as [UInt8]
            let aes = try! AES(key: key, blockMode: .ECB, padding: .pkcs5) // AES128 .ECB pkcs7
            let encrypted = try aes.encrypt(Array(self.utf8))

            result = encrypted.toBase64()!

            print("AES Encryption Result: \(result)")

         catch 

            print("Error: \(error)")
        

        return result
    

    func aesDecrypt(key: String) throws -> String 

        var result = ""

        do 

            let encrypted = self
            let key: [UInt8] = Array(key.utf8) as [UInt8]
            let aes = try! AES(key: key, blockMode: .ECB, padding: .pkcs5) // AES128 .ECB pkcs7
            let decrypted = try aes.decrypt(Array(base64: encrypted))

            result = String(data: Data(decrypted), encoding: .utf8) ?? ""

            print("AES Decryption Result: \(result)")

         catch 

            print("Error: \(error)")
        

        return result
    

在此我没有使用 iv 和 encrypted.toBase64() 像 result = encrypted.toBase64()! 那样在加密中代替 result = encrypted.toStringHex()! 进行加密

和类似的解密let decrypted = try aes.decrypt(Array(base64: encrypted))代替let decrypted = try aes.decrypt(Array(Hex: encrypted))

【讨论】:

您使用的是哪个版本? 出现错误:“类型‘BlockMode’没有成员‘ECB’” 让 aes = 试试看! AES(key: key, blockMode: .ECB, padding: .pkcs5) 在这种情况下不需要 iv。并检查您是否在您的 pod 中安装了 pod 'CryptoSwift'。如果你这样做了,那么在你的文件中导入 CryptoSwift。这东西对我有用.. 我不明白为什么在 30 行完成工作时添加 Pod(通常是 Pod 会弄乱项目添加工作区..)。 :) @mahen3d 尝试使用ECB() 而不是.ECB【参考方案6】:

我知道这是一个老问题。

自 2019 年起,您可以使用 Apple 的 CryptoKit。它介绍了AES.GCM

import CryptoKit

let key = SymmetricKey(size: .bits256)
let data = Data(...)
do 
    let enc = try AES.GCM.seal(data, using: key).combined!
    let dec = try AES.GCM.open(try AES.GCM.SealedBox(combined: data), using: key))
 catch ...

我还制作了一个有用的 swift 包,扩展 CryptoKit 以允许 AES.CBC 加密 (https://github.com/gal-yedidovich/CryptoExtensions)

那么,import CBC

import CryptoKit
import CBC

let data: Data = ... //some data to encrypt
let iv: Data = ... //an initial vector
let key: SymmetricKey = ... //encryption key

//one shot crypto operation
do 
    let encrypted = try AES.CBC.encrypt(data, using: key, iv: iv)
    let decrypted = try AES.CBC.decrypt(encrypted, using: key, iv: iv)
 catch ...

//using cipher
do 
    let cipher = try AES.CBC.Cipher(.encrypt, using: key, iv: iv)
    var enc = Data()
    enc += try cipher.update(...)
    enc += try cipher.update(...)
    enc += try cipher.finalize()
 catch ...

【讨论】:

如何在 AES.GCM 中添加 IV 值? 我不是专家,但据我所知,您在 GCM 中没有 IV。相反,您使用身份验证 + 随机数【参考方案7】:

找到了一个名为 RNCryptor 的不错的库,用 Swift 语言实现,用于 AES 加密/解密。

可以使用 Cocoapods 或 Carthage 进行安装。 这是加密和解密的示例代码。

// Encryption
let data = "sample data string".data(using: String.Encoding.utf8)
let password = "Secret password"
let encryptedData = RNCryptor.encrypt(data: data, withPassword: password)

// Decryption
do 
    let originalData = try RNCryptor.decrypt(data: encryptedData, withPassword: password)
    // ...
 catch 
    print(error)

【讨论】:

不错的库,但为什么要为简单的工作添加大量文件.. :)【参考方案8】:

对于无法将字节数组转换为字符串的任何人

String(data: Data(decrypted), encoding: .utf8)

这是我的示例字符串扩展

extension String 

    func decryptAES(key: String, iv: String) -> String 
        do 
            let encrypted = self
            let key = Array(key.utf8)
            let iv = Array(iv.utf8)
            let aes = try AES(key: key, blockMode: CTR(iv: iv), padding: .noPadding)
            let decrypted = try aes.decrypt(Array(hex: encrypted))
            return String(data: Data(decrypted), encoding: .utf8) ?? ""
         catch 
            return "Error: \(error)"
        
    

【讨论】:

【参考方案9】:

我正在寻找带有 PKC5 填充的 AES 加密 ECB 模式,而不使用任何 pod。通过收集不同的信息,我找到了解决问题的正确方法。也许它可以对其他人有所帮助。

注意:PKCS5 和 PKCS7 填充之间没有区别。

import CommonCrypto
 
func encryptionAESModeECB(messageData data: Data, key: String) -> Data? 
    guard let keyData = key.data(using: String.Encoding.utf8) else  return nil 
    guard let cryptData = NSMutableData(length: Int((data.count)) + kCCBlockSizeAES128) else  return nil 
    
    let keyLength               = size_t(kCCKeySizeAES128)
    let operation:  CCOperation = UInt32(kCCEncrypt)
    let algoritm:   CCAlgorithm = UInt32(kCCAlgorithmAES)
    let options:    CCOptions   = UInt32(kCCOptionECBMode + kCCOptionPKCS7Padding)
    let iv:         String      = ""
    
    var numBytesEncrypted: size_t = 0
    
    let cryptStatus = CCCrypt(operation,
                              algoritm,
                              options,
                              (keyData as NSData).bytes, keyLength,
                              iv,
                              (data as NSData).bytes, data.count,
                              cryptData.mutableBytes, cryptData.length,
                              &numBytesEncrypted)
    
    if UInt32(cryptStatus) == UInt32(kCCSuccess) 
        cryptData.length = Int(numBytesEncrypted)
        let encryptedString = cryptData.base64EncodedString(options: .lineLength64Characters)
        return encryptedString.data(using: .utf8)
     else 
        return nil
    


func decryptionAESModeECB(messageData: Data, key: String) -> Data? 
    guard let messageString = String(data: messageData, encoding: .utf8) else  return nil 
    guard let data = Data(base64Encoded: messageString, options: .ignoreUnknownCharacters) else  return nil 
    guard let keyData = key.data(using: String.Encoding.utf8) else  return nil 
    guard let cryptData = NSMutableData(length: Int((data.count)) + kCCBlockSizeAES128) else  return nil 
    
    let keyLength               = size_t(kCCKeySizeAES128)
    let operation:  CCOperation = UInt32(kCCDecrypt)
    let algoritm:   CCAlgorithm = UInt32(kCCAlgorithmAES)
    let options:    CCOptions   = UInt32(kCCOptionECBMode + kCCOptionPKCS7Padding)
    let iv:         String      = ""
    
    var numBytesEncrypted: size_t = 0
    
    let cryptStatus = CCCrypt(operation,
                              algoritm,
                              options,
                              (keyData as NSData).bytes, keyLength,
                              iv,
                              (data as NSData).bytes, data.count,
                              cryptData.mutableBytes, cryptData.length,
                              &numBytesEncrypted)
    
    if UInt32(cryptStatus) == UInt32(kCCSuccess) 
        cryptData.length = Int(numBytesEncrypted)
        return cryptData as Data
     else 
        return nil
    

像这样使用它:

let encryptedData = encryptionAESModeECB(messageData: data, key: "keyString")

let decryptedData = decryptionAESModeECB(messageData: data, key: "keyString")

【讨论】:

这个怎么吃?有示例代码吗? 我在帖子中添加了示例代码。我希望它对你有帮助。如果您需要更多帮助,请随时提出。

以上是关于快速的 AES 加密的主要内容,如果未能解决你的问题,请参考以下文章

Java AES 128 加密方式与 openssl 不同

对称加密及AES加密算法

IOS AES加密

什么是AES加密?详解AES加密算法原理流程

干货分享 | 对称加密及AES加密算法

加密算法之AES