我正在try 在swift中实现AES加密.Android和C#的加密解密工作正常.我需要用swift实现它.android是current code,C#之后是这个.

我试着用

  1. CryptoSwift
  2. Cross platform AES encryption

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

任何帮助都将不胜感激

推荐答案

确保使用与CBC模式下的AES相同的参数,使用iv、PKCS5Padding(实际上是PKCS#7)填充和16字节(128位)密钥.

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

确保密钥、iv和加密数据的编码都匹配.Hex将它们转储到两个平台上,以确保它们完全相同.加密功能不难使用,如果所有的输入参数都正确,那么输出就会正确.

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

Cross platform AES加密使用256位密钥,因此无法正常工作.

例子:

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: CC算法rithm = UInt32(kCC算法rithmAES128)
    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)!)");

输出:

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和[UInt8]

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: CC算法rithm = UInt32(kCC算法rithmAES128)
    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个Data

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),
                              CC算法rithm(kCC算法rithmAES),
                              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+)

iv是加密数据的前缀

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

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

密钥的长度应该正好是128位(16字节)、192位(24字节)或256位(32字节).如果使用了另一个密钥大小,将抛出一个错误.

默认设置为PKCS#7 padding.

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.

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

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

// iv是加密数据的前缀
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),
                        CC算法rithm(kCC算法rithmAES),
                        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;
}

// iv是加密数据的前缀
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),
                        CC算法rithm(kCC算法rithmAES128),
                        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)")
}

Example 输出:

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>

注:

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

同样缺失的是密钥从密码中派生出来的密钥,建议使用PBKDF2个文本密码作为密钥material .

有关可靠的可用于生产的多平台加密代码,请参阅RNCryptor.

Swift相关问答推荐

计算Vision OS相机与Vision OS中3D模型之间的距离

如何让CTFontCreateUIFontForLanguage与汉字和表情包协同工作?

如何使泡泡上的箭头直达封闭矩形

将变量设置为 @Published 会 destruct 代码而不会出现任何错误

如何通过 Enum 属性使用新的 #Predicate 宏获取

OSX 中的 Popover 无法确定透明度

在Swift中如何将NSUrl转换为本地路径URL

Swift String.firstIndex(of: "\n") 返回 nil,即使字符串有 \n

从 Obj-C 函数返回 swift 类的不兼容指针类型

将弱引用作为类函数引用传递时,弱引用无法按预期工作

PassthroughSubject 的 AsyncPublisher 值属性未生成所有值

使用 RxSwift 围绕 async/await 方法创建 Observable

闭包 - deinit self 对象的时间

如何使用 Date.ParseStrategy 在 Swift 5.6 中将字符串解析为日期?

为什么swiftui中的导航视图栏那么大?

Swift 2 或 3 中的 Google Analytics 问题

快速的 AES 加密

如何从 Swift 中的字符串生成条形码?

Swift - 要求实现协议的类是某个类的子类

iPhone 纵向和 iPad 横向的通用应用程序