快速的 AES 加密 [英] AES encryption in swift

查看:25
本文介绍了快速的 AES 加密的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试快速实现 AES 加密.Android 和 C# 的加密解密工作正常.我需要迅速实施它.这是 当前代码 用于 android 和 C# 之后.

我尝试使用

  1. CryptoSwift
  2. 跨平台AES加密

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

任何帮助将不胜感激

解决方案

确保使用相同的参数,看起来是 AES with CBC mode with iv, PKCS5Padding (实际上是 PKCS#7) padding和一个 16 字节(128 位)的密钥.

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

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

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

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

例子:

<块引用>

斯威夫特 2

//操作:kCCEncrypt 或 kCCDecryptfunc testCrypt(数据数据:[UInt8],keyData:[UInt8],ivData:[UInt8],操作:Int)->[UInt8]?{让 cryptLength = size_t(data.count+kCCBlockSizeAES128)var cryptData = [UInt8](计数:加密长度,重复值:0)让 keyLength = size_t(kCCKeySizeAES128)让算法:CCAlgorithm = UInt32(kCCAlgorithmAES128)让选项:CCOptions = UInt32(kCCOptionPKCS7Padding)var numBytesEncrypted :size_t = 0让 cryptStatus = CCCrypt(CCOperation(操作),算法,选项,密钥数据,密钥长度,iv数据,数据,data.count,&cryptData, cryptLength,&numBytesEncrypted)如果 UInt32(cryptStatus) == UInt32(kCCSuccess) {cryptData.removeRange(numBytesEncrypted..

输出:

<上一页>信息:不要尝试阅读此文本.绝密的东西消息数据:446f6ec2 b4742074 72792074 6f207265 61642074 68697320 74657874 2e20546f 70205365 63726574 20537475 6666关键数据:31323334 35363738 39303132 33343536 37383930 31323334 35363738 39303132ivData: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]?{让 cryptLength = size_t(data.count+kCCBlockSizeAES128)var cryptData = [UInt8](重复:0,计数:cryptLength)让 keyLength = size_t(kCCKeySizeAES128)让算法:CCAlgorithm = UInt32(kCCAlgorithmAES128)让选项:CCOptions = UInt32(kCCOptionPKCS7Padding)var numBytesEncrypted :size_t = 0让 cryptStatus = CCCrypt(CCOperation(操作),算法,选项,密钥数据,密钥长度,iv数据,数据,data.count,&cryptData, cryptLength,&numBytesEncrypted)如果 UInt32(cryptStatus) == UInt32(kCCSuccess) {cryptData.removeSubrange(numBytesEncrypted..

<块引用>

斯威夫特 3 &4 带 Data 类型

func testCrypt(data:Data, keyData:Data, ivData:Data, operation:Int) ->数据 {让 cryptLength = size_t(data.count + kCCBlockSizeAES128)var cryptData = 数据(计数:cryptLength)让 keyLength = size_t(kCCKeySizeAES128)让选项 = CCOptions(kCCOptionPKCS7Padding)var numBytesEncrypted :size_t = 0让 cryptStatus = cryptData.withUnsafeMutableBytes {cryptBytes indata.withUnsafeBytes {dataBytes inivData.withUnsafeBytes {ivBytes inkeyData.withUnsafeBytes {keyBytes inCCCrypt(CCOperation(操作),CCAlgorithm(kCCAlgorithmAES),选项,密钥字节,密钥长度,ivBytes,数据字节,数据计数,cryptBytes, cryptLength,&numBytesEncrypted)}}}}如果 UInt32(cryptStatus) == UInt32(kCCSuccess) {cryptData.removeSubrange(numBytesEncrypted..

日落文档部分的示例:

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

iv 是加密数据的前缀

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

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

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

PKCS#7 填充默认设置.

此示例需要 Common Crypto
项目必须有一个桥接头:
#import <CommonCrypto/CommonCrypto.h>
Security.framework 添加到项目中.

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

枚举 AESError: Error {案例 KeyError((String, Int))案例 IVError((String, Int))案例 CryptorError((String, Int))}//iv 是加密数据的前缀func aesCBCEncrypt(data:Data, keyData:Data) 抛出 ->数据 {让 keyLength = keyData.count让 validKeyLengths = [kCCKeySizeAES128,kCCKeySizeAES192,kCCKeySizeAES256]if (validKeyLengths.contains(keyLength) == false) {throw AESError.KeyError(("无效的密钥长度", keyLength))}让 ivSize = kCCBlockSizeAES128;让 cryptLength = size_t(ivSize + data.count + kCCBlockSizeAES128)var cryptData = 数据(计数:cryptLength)让状态 = cryptData.withUnsafeMutableBytes {ivBytes inSecRandomCopyBytes(kSecRandomDefault, kCCBlockSizeAES128, ivBytes)}如果(状态!= 0){throw AESError.IVError(("IV 生成失败", Int(status)))}var numBytesEncrypted :size_t = 0让选项 = CCOptions(kCCOptionPKCS7Padding)让 cryptStatus = cryptData.withUnsafeMutableBytes {cryptBytes indata.withUnsafeBytes {dataBytes inkeyData.withUnsafeBytes {keyBytes inCCCrypt(CCOperation(kCCEncrypt),CCAlgorithm(kCCAlgorithmAES),选项,密钥字节,密钥长度,加密字节,数据字节,数据计数,cryptBytes+kCCBlockSizeAES128, cryptLength,&numBytesEncrypted)}}}如果 UInt32(cryptStatus) == UInt32(kCCSuccess) {cryptData.count = numBytesEncrypted + ivSize}别的 {throw AESError.CryptorError(("加密失败", Int(cryptStatus)))}返回加密数据;}//iv 是加密数据的前缀func aesCBCDecrypt(data:Data, keyData:Data) 抛出 ->数据?{让 keyLength = keyData.count让 validKeyLengths = [kCCKeySizeAES128,kCCKeySizeAES192,kCCKeySizeAES256]if (validKeyLengths.contains(keyLength) == false) {throw AESError.KeyError(("无效的密钥长度", keyLength))}让 ivSize = kCCBlockSizeAES128;让 clearLength = size_t(data.count - ivSize)var clearData = 数据(计数:clearLength)var numBytesDecrypted :size_t = 0让选项 = CCOptions(kCCOptionPKCS7Padding)让 cryptStatus = clearData.withUnsafeMutableBytes {cryptBytes indata.withUnsafeBytes {dataBytes inkeyData.withUnsafeBytes {keyBytes inCCCrypt(CCOperation(kCCDecrypt),CCAlgorithm(kCCAlgorithmAES128),选项,密钥字节,密钥长度,数据字节,dataBytes+kCCBlockSizeAES128, clearLength,cryptBytes,清除长度,&numBytesDecrypted)}}}如果 UInt32(cryptStatus) == UInt32(kCCSuccess) {clearData.count = numBytesDecrypted}别的 {throw AESError.CryptorError(("解密失败", Int(cryptStatus)))}返回清除数据;}

示例用法:

让 clearData = "clearData0123456".data(使用:String.Encoding.utf8)!让 keyData = "keyData890123456".data(使用:String.Encoding.utf8)!print("clearData: (clearData as NSData)")print("keyData: (keyData as NSData)")var cryptData:数据?做 {cryptData = 尝试 aesCBCEncrypt(data:clearData, keyData:keyData)print("cryptData: (cryptData! as NSData)")}捕捉(让状态){print("错误 aesCBCEncrypt: (status)")}让解密数据:数据?做 {让 decryptData = 尝试 aesCBCDecrypt(data:cryptData!, keyData:keyData)print("decryptData: (decryptData! as NSData)")}捕捉(让状态){print("错误 aesCBCDecrypt: (status)")}

示例输出:

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

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

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

还缺少从密码中导出密钥的密钥,建议 PBKDF2used is text 密码用作密钥材料.

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

I'm trying to implement AES encryption in swift. The encryption decryption for Android and C# is working properly. I need to implement it in swift. It's current code for android and C# is followed by this.

I tried to use

  1. CryptoSwift
  2. Cross platform AES encryption

But none of it work. When I send the encrypted string on server it's not been decrypted.

Any help will be appreciated

解决方案

Be sure to use the same parameters which seem to be AES with CBC mode with iv, PKCS5Padding (actually PKCS#7) padding and a 16-byte (128-bit) key.

PKCS#5 padding and PKCS#7 padding are essentially the same, sometimes for historic reasons PKCS#5 padding is specified for use with AES but the actual padding is PKCS#7.

Make sure the encodings of the key, iv and encrypted data all match. Hex dump them on both platforms to ensure they are identical. Encryption functions are not difficult to use, if all the input parameters are correct the output will be correct.

To make this more secure the iv should be random bytes and prepended to the encrypted data for use during decryption.

The Cross platform AES encryption uses a 256-bit key so will not work as-is.

Example:

Swift 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)!)");

Output:

message:       Don´t try to read this text. Top Secret Stuff  
messageData:   446f6ec2 b4742074 72792074 6f207265 61642074 68697320 74657874 2e20546f 70205365 63726574 20537475 6666  
keyData:       31323334 35363738 39303132 33343536 37383930 31323334 35363738 39303132  
ivData:        61626364 65666768 696a6b6c 6d6e6f70  
encryptedData: b1b6dc17 62eaf3f8 baa1cb87 21ddc35c dee803ed fb320020 85794848 21206943 a85feb5b c8ee58fc d6fb664b 96b81114  
decryptedData: 446f6ec2 b4742074 72792074 6f207265 61642074 68697320 74657874 2e20546f 70205365 63726574 20537475 6666  
decrypted:     Don´t try to read this text. Top Secret Stuff  

Swift 3 with [UInt8] type

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;
}

Swift 3 & 4 with Data type

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)!

Example from sunsetted documentation section:

AES encryption in CBC mode with a random IV (Swift 3+)

The iv is prefixed to the encrypted data

aesCBC128Encrypt will create a random IV and prefixed to the encrypted code.
aesCBC128Decrypt will use the prefixed IV during decryption.

Inputs are the data and key are Data objects. If an encoded form such as Base64 if required convert to and/or from in the calling method.

The key should be exactly 128-bits (16-bytes), 192-bits (24-bytes) or 256-bits (32-bytes) in length. If another key size is used an error will be thrown.

PKCS#7 padding is set by default.

This example requires Common Crypto
It is necessary to have a bridging header to the project:
#import <CommonCrypto/CommonCrypto.h>
Add the Security.framework to the project.

This is example, not production code.

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;
}

Example usage:

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)")
}

Example Output:

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>

Notes:
One typical problem with CBC mode example code is that it leaves the creation and sharing of the random IV to the user. This example includes generation of the IV, prefixed the encrypted data and uses the prefixed IV during decryption. This frees the casual user from the details that are necessary for CBC mode.

For security the encrypted data also should have authentication, this example code does not provide that in order to be small and allow better interoperability for other platforms.

Also missing is key derivation of the key from a password, it is suggested that PBKDF2 be used is text passwords are used as keying material.

For robust production ready multi-platform encryption code see RNCryptor.

这篇关于快速的 AES 加密的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆