AES encryption in fast

I am trying to implement AES encryption in fast. Decryption encryption for Android and C # works correctly. I need to implement this as soon as possible. This is the current code for Android and C # accompanied by this.

I tried to use

  1. CryptoSwift
  2. Cross-platform AES encryption

But none of this works. When I send an encrypted string to the server, it is not decrypted.

Any help would be appreciated

+22
source share
7 answers

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

PKCS # 5 padding and PKCS # 7 are essentially the same add-on, sometimes for historical reasons. PKCS # 5 gasket is indicated for use with AES but actual filling is PKCS # 7.

Verify that the key encodings, iv, and encrypted data match. Hex resets them on both platforms to make sure 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, iv must be a random byte and appended to the encrypted data for use during decryption.

AES Cross Platform encryption uses a 256-bit key, so it won’t work as it 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 type [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: 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 and 4 with type 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), 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)! 

An example from the hardened documentation section:

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

Document iv prefix for encrypted data

aesCBC128Encrypt will create a random IV and prefix for the encrypted code.
aesCBC128Decrypt will use the IV prefix during decryption.

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

The key must consist of 128-bit (16-byte), 192-bit (24 bytes) or 256-bit (32 bytes) in length. If a different key size is used, an error will be generated.

PKCS # 7 padding is installed by default.

This example requires Common Crypto. You must have a title header for the project:
#import <CommonCrypto/CommonCrypto.h>
Add Security.framework to the project.

This is an example, not a 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; } 

Usage example:

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

Result:

 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 an example CBC mode code is that it leaves the creation and sharing of a random IV to the user. This example includes creating an IV, prefixing the encrypted data, and using the IV prefix during decryption. This frees the casual user from the details that are necessary for CBC mode .

For security, the encrypted data must also be authenticated; this sample code does not provide for being small and providing better compatibility for other platforms.

There is also no key output of the key from the password; it is proposed to use PBKDF2 , since text passwords are used as material keys.

For a robust off-the-shelf multi-platform encryption code, see RNCryptor .

+35
source

Swift 5

I changed the @ingconti code.

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

Use like this

 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) 

results

enter image description here

+7
source

my two cents:

4 / xcode 9 quick extension for data:

 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 } 
+5
source

Based on @zaph's great answer, I am creating this playground for:

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

Output:

output

I also created the Swift Package based on it:

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

+4
source

I used CryptoSwift.

First I installed cryptoSwift in the pod file. Then in my controller view, I have a CryptoSwift import.

Here is the code I used:

 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) 

Then using the String extension:

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

In this, I did not use iv and encrypted.toBase64 () for encryption as result = encrypted.toBase64()! instead of result = encrypted.toStringHex()! in encryption

and similarly in the decryption let decrypted = try aes.decrypt(Array(base64: encrypted)) instead of let decrypted = try aes.decrypt(Array(Hex: encrypted))

+1
source

Found a beautiful library called RNCryptor , implemented in the fast language for encryption / decryption AES.

Installation can be done using Cocoapods or Carthage. Here is a sample code for encryption and decryption.

 // 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) } 
0
source

For those who cannot convert an array of bytes to a string

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

This is my string extension example.

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

All Articles