3

.Net Code :

public string AESEncrypt(string clearText,string key) { string EncryptionKey = key; // "MAKV2SPBNI99212"; byte[] clearBytes = Encoding.Unicode.GetBytes(clearText); using (Aes encryptor = Aes.Create()) { int iterations = 1024; Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 }, iterations); encryptor.Key = pdb.GetBytes(32); encryptor.IV = pdb.GetBytes(16); using (MemoryStream ms = new MemoryStream()) { using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write)) { cs.Write(clearBytes, 0, clearBytes.Length); cs.Close(); } clearText = Convert.ToBase64String(ms.ToArray()); } } return clearText; } 

Swift Code :

 // "MAKV2SPBNI99212" Key func AESEncryptedString( withKey key : String) -> String? { let salt : Array <UInt8> = [0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76] let saltData = NSData(bytes: salt, length: 13) let myPassData : NSData = key.data(using: String.Encoding.utf8)! as NSData var key = [UInt8](repeating: 0, count: 48) var initialVector = [UInt8](repeating: 0, count: 16) let ptrData = myPassData.bytes.assumingMemoryBound(to: Int8.self) let ptrSalt = saltData.bytes.assumingMemoryBound(to: UInt8.self) let keyPtr = UnsafeMutablePointer<UInt8>(mutating: key) CCKeyDerivationPBKDF(CCPBKDFAlgorithm(kCCPBKDF2), ptrData, myPassData.length, ptrSalt, saltData.length, CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA1), 1024, keyPtr, 48) initialVector = Array(key[32..<48]) key = Array(key[0..<32]) let keyD = Data(bytes: key) let ivD = Data(bytes:initialVector) let rawData = self.data(using: String.Encoding.unicode) let encryptedData = testCrypt(data:rawData!, keyData:keyD, ivData:ivD, operation:kCCEncrypt) let decryptedData = testDeCrypt(data:encryptedData, keyData:keyD, ivData:ivD, operation:kCCDecrypt) let decrypted = String(bytes:decryptedData, encoding:String.Encoding.utf16)! print("Encrypted Data: \(encryptedData.base64EncodedString()) \n with count: \(encryptedData.base64EncodedString().characters.count)") print("Decrypted: \(decrypted)") let encryptedString = encryptedData.base64EncodedString() return encryptedString } func testCrypt(data:Data, keyData:Data, ivData:Data, operation:Int) -> Data { let buffer_size : size_t = (data as NSData).length + kCCBlockSizeAES128 let buffer = UnsafeMutablePointer<NSData>.allocate(capacity: buffer_size) var num_bytes_encrypted : size_t = 0 let operation = CCOperation(operation) let algoritm = CCAlgorithm(kCCAlgorithmAES) let options = CCOptions( kCCOptionPKCS7Padding) let keyLength = size_t(kCCKeySizeAES256) let Crypto_status: CCCryptorStatus = CCCrypt(operation, algoritm, options, (keyData as NSData).bytes, keyLength, (ivData as NSData).bytes, (data as NSData).bytes, (data as NSData).length, buffer, buffer_size, &num_bytes_encrypted) if UInt32(Crypto_status) == UInt32(kCCSuccess){ let myResult: NSData = NSData(bytes: buffer, length: num_bytes_encrypted) free(buffer) let keyData: NSData = myResult let hexString = (keyData as Data).base64EncodedString() print(hexString) return myResult as Data }else{ free(buffer) return Data() } } func testDeCrypt(data:Data, keyData:Data, ivData:Data, operation:Int) -> Data { let decryptedData = NSMutableData(length: (data as NSData).length) var num_bytes_decrypted: size_t = 0 let operation = CCOperation(operation) let algoritm = CCAlgorithm(kCCAlgorithmAES) let options = CCOptions(kCCOptionPKCS7Padding) let keyLength = size_t(kCCKeySizeAES256) let Crypto_status: CCCryptorStatus = CCCrypt(operation, algoritm, options, (keyData as NSData).bytes, keyLength, (ivData as NSData).bytes, (data as NSData).bytes, (data as NSData).length, decryptedData?.mutableBytes, (decryptedData?.length)!, &num_bytes_decrypted) if UInt32(Crypto_status) == UInt32(kCCSuccess){ decryptedData?.length = num_bytes_decrypted return decryptedData! as Data } else { return Data() } } 

We are able to Encrypt and Decrypt data in Swift but Encrypted data of .Net code is not getting decrypted in Swift.Please let me know if anything wrong with the code.We tried decrypting Encrypted data of swift in .net its working fine but we are not able to decrypt the .net data. please help us with that. I have tried almost every solution available.

3
  • Only thing I can see is you are decrypting with 128 key size while both swift and .Net code is encrypting with a 256 key size. Commented May 1, 2017 at 8:05
  • I tried with 256 key size it is also not working Commented May 1, 2017 at 9:51
  • "I tried with 256 key size it is also not working" is not a valid response, the key size and key must be the same to get the same result. Commented May 1, 2017 at 14:52

2 Answers 2

3

As far as I tested both your codes, C# and Swift, the main difference causing your issue is string encoding.


But before going there, I need to note that your code is full of bad practices about using Data and NSData, passing the address of Data or [UInt8] etc, etc. Some of them are critical.

The one super-ciritical is this line:

let buffer = UnsafeMutablePointer<NSData>.allocate(capacity: buffer_size) 

You need to allocate a buffer_size-byte memory region, you do not want buffer_size references to NSData.

Some other fragile lines:

let ptrData = myPassData.bytes.assumingMemoryBound(to: Int8.self) let ptrSalt = saltData.bytes.assumingMemoryBound(to: UInt8.self) let keyPtr = UnsafeMutablePointer<UInt8>(mutating: key) 

These lines are strongly dependent on the code generation of the current implementation of Swift and on your current settings.

Simply saying, it is astonishing that your code seems to work without crashing.


So, I started with re-writing your Swift code as follows:

func testCrypt(data: Data, keyData: Data, ivData: Data, operation:Int) -> Data { assert(keyData.count == Int(kCCKeySizeAES128) || keyData.count == Int(kCCKeySizeAES192) || keyData.count == Int(kCCKeySizeAES256)) let buffer_size = data.count + kCCBlockSizeAES128 var buffer: [UInt8] = Array(repeating: 0, count: buffer_size) var num_bytes_encrypted : size_t = 0 let operation = CCOperation(operation) let algoritm = CCAlgorithm(kCCAlgorithmAES) let options = CCOptions(kCCOptionPKCS7Padding) let cryptoStatus = keyData.withUnsafeBytes {keyDataBytes in ivData.withUnsafeBytes {ivDataBytes in data.withUnsafeBytes {dataBytes in CCCrypt(operation, algoritm, options, keyDataBytes, keyData.count, ivDataBytes, dataBytes, data.count, &buffer, buffer_size, &num_bytes_encrypted) } } } if cryptoStatus == CCCryptorStatus(kCCSuccess){ let myResult = Data(bytes: buffer, count: num_bytes_encrypted) return myResult } else { return Data() } } func testDeCrypt(data: Data, keyData: Data, ivData: Data, operation: Int) -> Data { assert(keyData.count == Int(kCCKeySizeAES128) || keyData.count == Int(kCCKeySizeAES192) || keyData.count == Int(kCCKeySizeAES256)) var decryptedData = Data(count: data.count) var num_bytes_decrypted: size_t = 0 let operation = CCOperation(operation) let algoritm = CCAlgorithm(kCCAlgorithmAES) let options = CCOptions(kCCOptionPKCS7Padding) let cryptoStatus = keyData.withUnsafeBytes {keyDataBytes in ivData.withUnsafeBytes {ivDataBytes in data.withUnsafeBytes {dataBytes in decryptedData.withUnsafeMutableBytes {decryptedDataBytes in CCCrypt(operation, algoritm, options, keyDataBytes, keyData.count, ivDataBytes, dataBytes, data.count, decryptedDataBytes, decryptedData.count, &num_bytes_decrypted) } } } } if cryptoStatus == CCCryptorStatus(kCCSuccess) { decryptedData.count = num_bytes_decrypted return decryptedData } else { return Data() } } extension String { func AESEncryptedString(withKey keyString: String) -> String? { let salt: [UInt8] = [0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76] var key = [UInt8](repeating: 0, count: 48) CCKeyDerivationPBKDF(CCPBKDFAlgorithm(kCCPBKDF2), keyString, keyString.utf8.count, salt, salt.count, CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA1), 1024, &key, 48) let initialVector = Array(key[32..<48]) key = Array(key[0..<32]) let keyData = Data(bytes: key) let ivData = Data(bytes: initialVector) let rawData = self.data(using: .unicode)! let encryptedData = testCrypt(data: rawData, keyData: keyData, ivData: ivData, operation: kCCEncrypt) let decryptedData = testDeCrypt(data: encryptedData, keyData: keyData, ivData: ivData, operation: kCCDecrypt) let decrypted = String(bytes: decryptedData, encoding: .unicode)! print("Encrypted Data: \(encryptedData.base64EncodedString()) \n with count: \(encryptedData.base64EncodedString().characters.count)") print("Decrypted: \(decrypted)") let encryptedString = encryptedData.base64EncodedString() return encryptedString } } 

(String.Encoding.utf16 is just an alias of String.Encoding.unicode, so I replaced the line using .utf16 to .unicode.)

The part your C# code converts string to byte array:

byte[] clearBytes = Encoding.Unicode.GetBytes(clearText); 

And the part generating Data in Swift:

let rawData = self.data(using: .unicode)! 

Those two lines generate different byte sequences, as .unicode conforms to canonical UTF-16 representation, which contains a BOM at the top of the result, but System.Text.Encoding.Unicode does not add a BOM.


So, change the two lines including .unicode to .utf16LittleEndian:

let rawData = self.data(using: .utf16LittleEndian)! let decrypted = String(bytes: decryptedData, encoding: .utf16LittleEndian)! 

Try and see what you get with these changes.

Sign up to request clarification or add additional context in comments.

4 Comments

Many very valid points! Why use var buffer: [UInt8] in (badly named) testCrypt and var decryptedData in testDeCrypt? Why not use Data in both? As another example: AES encryption in CBC mode with a random IV in the Documentation section.
@zaph, not many reasons. Just that this answer is written for the OP, so I kept the basic structure of the original functions to make it easy to find how and where I touched. You can use Data for testCrypt and it may be a better choice as it returns Data.
@OOPer Thanks for the Answer it's working like charm. And we are new to the AES Encryption so we were just trying to convert the .Net code and thats why there were lot of fragile code and its not the production code. We will keep your points while working with NSdata.
@OOPer can you guys help converting this java code to swift
0

Java Code:

public static String Encrypt(String PlainText) throws Exception { try { _aesCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); byte[] keyBytes = "jywseolkdiwpkqse".getBytes(); SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES"); byte[] iv = "jywseolkdiwpkqse".getBytes(); IvParameterSpec ivSpec = new IvParameterSpec(iv); _aesCipher.init(1, (java.security.Key) keySpec, ivSpec); byte[] plainText = PlainText.getBytes(); byte[] result = _aesCipher.doFinal(plainText); return Base64.encode(result); } catch (Exception ex1) { System.out.println("Exception setting up cipher: " + ex1.getMessage() + "\r\n"); ex1.printStackTrace(); return ""; } } 

7 Comments

Specify the encoding for getBytes: .getBytes( "UTF-8" ). It is always best to specify parameters, in this case UTF-16 might be returned and that would produce byte arrays twice as long. From the documents: Encodes this String into a sequence of bytes using the platform's default charset, storing the result into a new byte array.
@zaph i want to convert above java code to swift can you help me with that
@zaph which class will be used in iOS for SecretKeySpec and IVParameter Spec generation?
Just specify the ksy and IV to the Common Crypto call, see an example: AES encryption in CBC mode with a random IV in the Documentation section.
@zaph i don't want a random iv. iv has to be generated from key
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.