3

I’ve an issue with AES-128 encryption. The encrypted string in iOS is different as compared to Android.

Below is android code :

public class Encryption {
    private static final String ALGORITHM = "AES";
    private static final String UNICODE_FORMAT = "UTF8";

    public static String encryptValue(String valueToEnc) {
        try {
            Key key = generateKey();
            Cipher c = Cipher.getInstance(ALGORITHM);
            c.init(Cipher.ENCRYPT_MODE, key);
            byte[] encValue = c.doFinal(valueToEnc.getBytes());
            String encryptedValue = new Base64().encode(encValue);
            String urlEncodeddata = URLEncoder.encode(encryptedValue, "UTF-8");
            return urlEncodeddata;
        } catch (Exception e) {

        }
        return valueToEnc;
    }

    private static Key generateKey() throws Exception {
        byte[] keyAsBytes;
        keyAsBytes = "MySixteenCharKey".getBytes(UNICODE_FORMAT);
        Key key = new SecretKeySpec(keyAsBytes, ALGORITHM);
        return key;
    }
}
Rengers
  • 14,911
  • 1
  • 36
  • 54
Jayprakash Dubey
  • 35,723
  • 18
  • 170
  • 177
  • 1
    http://stackoverflow.com/a/39101905/6203030 take a look, you are not doing anything wrong, it is just 'cause the encoding data in native Android is different to the enconding data native in iOS – Aitor Pagán Apr 10 '17 at 11:52
  • 1
    `Cipher ecipher = Cipher.getInstance("AES");` The correct form of a cipher transformation is "alg/mode/padding". By leaving off the mode and padding you get platform defaults. *Never* use platform defaults in cryptography, they are not portable. Always specify the full cipher transform to `Cipher.getInstance()`. – President James K. Polk Apr 10 '17 at 12:05
  • @JamesKPolk : I'm iOS developer..not aware of Android stufffs..I just have the code and want to implement in iOS too. – Jayprakash Dubey Apr 10 '17 at 12:17
  • Can you please share an example text of both unencrypted and encrypted? – Emre Önder Nov 20 '18 at 11:40
  • Are you tried this: https://stackoverflow.com/questions/37680361/aes-encryption-in-swift – Faysal Ahmed Nov 20 '18 at 12:58
  • @FaysalAhmed Yes, I have searched almost everywhere. The android code does not have any iVar. The link you provided needs iVar. – jeet.chanchawat Nov 21 '18 at 05:45
  • Thanks for your time guys... posting solution. – jeet.chanchawat Nov 21 '18 at 06:18

3 Answers3

10

Create string extension and use library CryptoSwift

//  String+Addition.swift
import CryptoSwift
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
}

}

and to use

@IBAction func onBtnClicked(_ sender: Any) { 
        let value = "My value to be encrypted"
        let key = "MySixteenCharKey"
        
        print(key!)
        let encryptedValue = try! value.aesEncrypt(key: key!)

        print(encryptedValue)
        
    }

For citation of this particular encryption code:

  1. The 16 char length key implies AES-128
  2. The code is without iVector, This implies ECB mode
  3. Using padding as pkcs5 or pkcs7 did not made any difference in my case
jeet.chanchawat
  • 5,842
  • 5
  • 38
  • 59
  • 1
    Do not use ECB mode in new work and update legacy work ASAP, it is not secure, see [ECB mode](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_Codebook_.28ECB.29), scroll down to the Penguin. Do not use ECB mode in new work and update legacy work ASAP, it is not secure, see [ECB mode](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_Codebook_.28ECB.29), scroll down to the Penguin. Instead use CBC mode with a random IV, just prefix the encrypted data with the IV for use in decryption, it does not need to be secret. – zaph Nov 22 '18 at 11:51
  • 1
    It is best to avoid using CryptoSwift, among other things it is 500 to 1000 times slower than Common Crypto based implementations. Apple's Common Crypto is FIPS certified and as such has been well vetted, using CryptoSwift is taking a chance on correctness, possible timing attacks and security such as timing and power attacks. – zaph Nov 22 '18 at 11:51
  • Hi Zaph, Thanks for spending your time for guiding me. Will definitely ask them to update the legacy server code. Hope they agree... – jeet.chanchawat Nov 22 '18 at 21:17
  • If you add decryption answer in the above answer it will be so good to user. – user3182143 Dec 25 '19 at 10:02
  • @jeet.chanchawat this is working fine can you please share decryption code ? – Dilip Mishra Jan 23 '21 at 04:42
  • Hi, @DilipMishra updated my answer for adding decryption code. – jeet.chanchawat Jan 25 '21 at 13:08
  • 1
    Thanks @jeet.chanchawat – Dilip Mishra Jan 25 '21 at 15:04
  • 1
    Worked ! @jeet.chanchawat – Prasann Jan 28 '22 at 06:32
0

Try this:

func encryptValue(stringToEncrypt:String) -> String{

    var encryptedString: String = ""

    let value = "MySixteenCharKey"
    let input: Array<UInt8> = Array(stringToEncrypt.utf8)
    let key: Array<UInt8> = Array("MySixteenCharKey".utf8)

    do {
        let encrypted = try AES(key: key, blockMode: .ECB, padding: PKCS7()).encrypt(input)
        let base64 = encrypted.toBase64()
        encryptedString = base64
    } catch {
        print(error)
    }

    return encryptedString
}
Shezad
  • 756
  • 7
  • 14
0

Create an extension of String and use this below function for encrypting and decrypting.

extension String {

//MARK: - Encrypt AES Method
/// This method will encrypt and return Cipher string

func aesEncrypt(key: String = "fqJfdzGDvfwbedsKSUGty3VZ9taXxMVw", iv: String = "1234567890123456") -> String {
    if let data = self.data(using: String.Encoding.utf8) {
        do {
            let enc = try AES(key: key, iv: iv, blockMode: .CBC, padding: PKCS7()).encrypt(data.bytes)
            let encData = Data(bytes: enc, count: Int(enc.count))
            let base64String: String = encData.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0));
            return base64String
        }
        catch let error {
            print(error.localizedDescription)
            return ""
        }
    }
    return ""
}

//MARK: - Decrypt AES Method
/// This method will decrypt the Cipher string

func aesDecrypt(key: String = "fqJfdzGDvfwbedsKSUGty3VZ9taXxMVw", iv: String = "1234567890123456") -> String {
    if let data = Data(base64Encoded: self, options: Data.Base64DecodingOptions.init(rawValue: 0)) {
        do {
            let dec = try AES(key: key, iv: iv, blockMode: .CBC, padding: PKCS7()).decrypt(data.bytes)
            let decData = Data(bytes: dec, count: Int(dec.count))
            let result = String(data: decData, encoding: .utf8)
            return result ?? ""
        }
        catch let error {
            print(error.localizedDescription)
            return ""
        }
    }

    return ""
    }
}
Sanjay Shah
  • 502
  • 2
  • 13