How to Do a Cross Platform Encryption Method Working in Both iOS and Android (Aes Encryption Only..)

How do I do a cross platform encryption method working in both IOS and android (AES encryption only..)?

I did this by using crypto swift. You can add this pod through CocoaPods. It's been recommended that you find a native way to solve this issue as crypto swift may affect ur app Performance. Anyway, I couldn't figure a way out other than it.

I was using swift 2.3 . So, Please convert the code if you are using the latest versions of swift

Step 1 : pod 'CryptoSwift', '0.5.2' (0.5.2 is for swift 2.3 only.)

Step 2 : create a string extension

//Crypto Swift

func AES_EncryptionKey() -> String {
let date = NSDate()
let calender = NSCalendar.currentCalendar()
let components = calender.components([.Day,.Month,.Year], fromDate: NSDate())
let year = components.year
var day = String(components.day)
var month = String(components.month)
if day.characters.count == 1 {
day = "0\(String(day))"
}
if month.characters.count == 1 {
month = "0\(String(month))"
}
//Mark: Please change the key as per your requirment! I am using a dynamic key now rather the one specified in question . i.e It changes everday
let secretKey = "\(String(day))20\(month)u\(String(year))e"
return secretKey

}

func AESencrypt() throws -> String {

//Mark: You have to do the same thing in Android too. If u skip this here skip in android too
let secretKeyTest = AES_EncryptionKey().toBase64()!

let inputBytes: [UInt8] = Array(self.utf8)
let key: [UInt8] = Array(secretKeyTest.utf8) //16
let iv: [UInt8] = Array("0000000000000000".utf8) //16

var encryptedBase64 = ""
do
{
let encrypted: [UInt8] = try AES(key: key, iv: iv, blockMode: .ECB).encrypt(inputBytes)
let encryptedNSData = NSData(bytes: encrypted, length: encrypted.count)
encryptedBase64 = encryptedNSData.base64EncodedStringWithOptions([])

//Mark: You have to do the same thing in Android too. If u skip this here skip in android too
encryptedBase64=encryptedBase64.toBase64()!

//Mark: Follow the same blockMode in both platform. ECB Mode is not recommended. I did it in ECB cuz it was already done in other platform
let decrypted: [UInt8] = try AES(key: key, iv: iv, blockMode: .ECB).decrypt(encrypted)
let result = String(bytes: decrypted, encoding: NSUTF8StringEncoding)!
print("result\t\(result )")
}
catch
{
print("FAIL ENCRYPT")
}
print("encryptedBase64: \(encryptedBase64)")

return encryptedBase64

}

func AESdecrypt() throws -> String {
var decryptedString = "NIL"
let secretKeyTest = AES_EncryptionKey().toBase64()!

let key: [UInt8] = Array(secretKeyTest.utf8) //16
let iv: [UInt8] = Array("0000000000000000".utf8) //16

//Step1
let encryptedData = self.dataUsingEncoding(NSUTF8StringEncoding)!
if let base64Decoded_ = NSData(base64EncodedData: encryptedData, options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters)
{

if var stringBase64 = String(data:base64Decoded_, encoding: NSUTF8StringEncoding)
{
//Step2
let encryptedDataSecond = stringBase64.dataUsingEncoding(NSUTF8StringEncoding)!
let base64DecodedSecond_ = NSData(base64EncodedData: encryptedDataSecond, options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters)
//Step3
let encrypted = Array(UnsafeBufferPointer(start: UnsafePointer<UInt8>(base64DecodedSecond_!.bytes), count: base64DecodedSecond_!.length))
do
{
let decryptedData = try AES(key: key, iv: iv, blockMode: .ECB).decrypt(encrypted)
decryptedString = String(bytes: decryptedData, encoding: NSUTF8StringEncoding)!
print("decryptedString: \(decryptedString)")
print("ALL DECRYPTED")

}
catch
{
print("FAIL DECRYPT")
}
}
}

return decryptedString

}

func fromBase64() -> String? {
guard let data = NSData(base64EncodedString: self, options: NSDataBase64DecodingOptions(rawValue: 0)) else {
return nil
}

return String(data: data, encoding: NSUTF8StringEncoding)
}

func toBase64() -> String? {
guard let data = self.dataUsingEncoding(NSUTF8StringEncoding) else {
return nil
}

return data.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
}}

Step 3 : The most important thing is cross checking the way of all your methods in both platforms. Do follow all the steps done in one platform in the other too..

AES Encryption done on both Iphone and Android

AES encryption/decryption will produce the same results on it it is provided the same parameters. Of particular interest are

  1. encryption key value and size
  2. mode: CBC, ECB, etc. (you should probably be using CBC)
  3. initialization vector (iv) is needed for most modes
  4. padding method: PKCS7, etc. (AES is a block cypher and needs input
    in a multiple of block size)

As a start chose simple test data, get that working and move into more complex situations. Ex: initially choose an iv of all 0, CBC, data of exactly one block size with no padding. When that is working start adding in more complexity.

Security is not easy, the encryption part is the easy part.

Or use SSL.

For reference and learning basically everything one needs to know is in the Handbook of Applied Cryptography it is a free (and legal) pdf download, a hardcover version can also be purchased. Pros use this book, even my wife in her work.

Cross platform AES Encryption between iOS and Kotlin/Java using Apples CryptoKit

could you try this (or something like it) with your setup. From what I undestand
you need to prefix data with nonce, because data from kotlin/java contains the cipher text plus the tag at the end. CryptoKit needs nonce || ciphertext || tag.

func decrypt(data: Data) -> String {
// need to prefix data with nonce, because data from kotlin/java contains the cipher text plus the tag at the end.
// we want nonce || ciphertext || tag for CryptoKit to be happy
let combine = nonce + data
if let myNewSealedBox = try? AES.GCM.SealedBox(combined: combine),
let res = try? AES.GCM.open(myNewSealedBox, using: mykey),
let myText = try? String(decoding: res, as: UTF8.self) {
return myText
}
return ""
}

Decrypt android AES example on iOS

First of all AES is symmetric cipher algorithm which needs to use exactly the same key for message encryption and also for message decryption.

I have examined your example codes and these are the things that really bother me:

  • different keys: Android example does not provide any getter or setter for AES key that should be used. Without that you are unable to use the same AES key on Android and iOS.
  • different key sizes: Android example seems to be using AES-128 but iOS example seems to be using AES-256
  • different cipher modes: iOS example uses CBC cipher mode so you will need to exchange also IV (initialization vector) between your devices. However I don't see any interface to provide/acquire IV in Android example.

I believe these are the main reasons why you are unable to get it working. If you want to use AES then you will need to modify your code to use the same key on both devices, use the same cipher mode on both devices and also use the same padding on both devices.

Android AES 128 encryption

in addition to encoding difficulties with your plaintext (as vcsjones pointed out in the comments), make sure that the encoding is the same for the key string (note that using a raw string, like a password, directly as an crypto key is bad news bears, use a key derivation function like PBKDF2 on the password to get derive a key).

Also, the encoding string for Java for ASCII is US-ASCII, not just ASCII, so make sure to use that in your getBytes calls.

EDIT: found your problem: the iOS string is being encrypted with an extra null charcter (0x00) at the end, while the java was not. So encrypting "hello world\0" in java will give you the same output as "hello world" does in iOS



Related Topics



Leave a reply



Submit