快速的 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 <CommonCrypto/CommonCrypto.h>
将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。然后,当Self
是AES
时,您可以将其称为AES.Error.whatever
或简称为Error.whatever
。 extension 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 加密的主要内容,如果未能解决你的问题,请参考以下文章