1

I am building a swift application where I need to have AES/CBC/PKCS5PADDING Encryption type. To encrypt API params and decrypt API response.

I have successfully added in android java and that works fine. Now I am trying to implement the same formate type of encryption 'AES/CBC/PKCS5PADDING' cipher size 16 in swift.

Problem: I am getting different encryption result for both android and iOS

Example: String: Hi how are u

Encrypted String for android: +A3p093WWrXU3Ey9i/Lv1Q==

Encrypted String for swift(iOS): Bp23PQX6yaCghvKFTieJDw==

Swift Implementation

import Foundation
import CommonCrypto

func aesEncrypt(key: String, iv: String, message: String) throws -> String{
    let data = message.data(using: .utf8)!
    // let enc = try AES(key: key, iv: iv, padding: .pkcs5).encrypt([UInt8](data))
    let enc = try AES(key: Array(key.utf8), blockMode: CBC(iv: Array(iv.utf8)), padding: .pkcs5).encrypt([UInt8](data))
    let encryptedData = Data(enc)
    return encryptedData.base64EncodedString()
}

func aesDecrypt(key: String, iv: String, message: String) throws -> String {
    let data = NSData(base64Encoded: message, options: NSData.Base64DecodingOptions(rawValue: 0))!
    let dec = try AES(key: key, iv: iv, padding: .pkcs5).decrypt([UInt8](data))
    let decryptedData = Data(dec)
    return String(bytes: decryptedData.bytes, encoding: .utf8) ?? "Could not decrypt"
}

Android Implementation

package com.example.uribanew.utils;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class EncrytData {

private static String CIPHER_NAME = "AES/CBC/PKCS5PADDING";

private static int CIPHER_KEY_LEN = 16; //128 bits

private static String KEY   = ""; // key to use should be 16 bytes long (128 bits)
private static String IV    = ""; // initialization vector

/**
 * Encrypt data using AES Cipher (CBC) with 128 bit key
 *
 * @param data - data to encrypt
 * @return encryptedData data in base64 encoding with iv attached at end after a :
 */
public static String encrypt(String data) {

    try {
        IvParameterSpec ivSpec = new IvParameterSpec(IV.getBytes("UTF-8"));
        SecretKeySpec secretKey = new SecretKeySpec(fixKey(KEY).getBytes("UTF-8"), "AES");

        Cipher cipher = Cipher.getInstance(EncrytData.CIPHER_NAME);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);

        byte[] encryptedData = cipher.doFinal((data.getBytes()));

        String encryptedDataInBase64 = android.util.Base64.encodeToString(encryptedData, android.util.Base64.DEFAULT); //Base64.getEncoder().encodeToString(encryptedData);

        return encryptedDataInBase64;

    } catch (Exception ex) {
        throw new RuntimeException(ex);
    }
}

private static String fixKey(String key) {

    if (key.length() < EncrytData.CIPHER_KEY_LEN) {
        int numPad = EncrytData.CIPHER_KEY_LEN - key.length();

        for (int i = 0; i < numPad; i++) {
            key += "0"; //0 pad to len 16 bytes
        }

        return key;

    }

    if (key.length() > EncrytData.CIPHER_KEY_LEN) {
        return key.substring(0, CIPHER_KEY_LEN); //truncate to 16 bytes
    }

    return key;
}

/**
 * Decrypt data using AES Cipher (CBC) with 128 bit key
 *
 * @param data - encrypted data with iv at the end separate by :
 * @return decrypted data string
 */

public static String decrypt(String data) {

    try {
        IvParameterSpec ivSpec = new IvParameterSpec(IV.getBytes("UTF-8"));
        // SecretKeySpec secretKey = new SecretKeySpec(KEY.getBytes("UTF-8"), "AES");
        SecretKeySpec secretKey = new SecretKeySpec(fixKey(KEY).getBytes("UTF-8"), "AES");

        Cipher cipher = Cipher.getInstance(EncrytData.CIPHER_NAME);
        cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);

        byte[] decodedEncryptedData = android.util.Base64.decode(data, android.util.Base64.DEFAULT); //Base64.getDecoder().decode(parts[0]);

        byte[] original = cipher.doFinal(decodedEncryptedData);

        return new String(original);
    } catch (Exception ex) {
        throw new RuntimeException(ex);
    }
}
}

Please let me know why with the same encryption type I am getting different encrypted string for both android and iOS. Let me know what I am doing wrong

Hitesh Matnani
  • 533
  • 2
  • 8
  • 26
  • @Sulthan Is there a deeper point to your question that's not obvious? (PKCS5 and PKCS7 padding *are* the same.) – Rob Napier Oct 05 '20 at 19:24
  • What do you mean by "I am not getting proper response type but not working perfectly result." What result are you getting? Do you receive an error? Does your encrypted data not decrypt properly? Does a Swift encryption support Swift decryption, but not Android decryption? Vice versa? What problem are you seeing, and how do you know it's a problem? – Rob Napier Oct 05 '20 at 19:26
  • Your Swift and Android code handle their IVs very differently, and the encoding is different (Android is Base64 encoded, Swift is not). And your Android code seems to be using a 128-bit key, while your Swift code seems to be using a 256-bit key. These don't seem the same at all. I'm not certain why you would expect these to work. You will need to write the Swift code to match the Android code if you consider the Android code to be correct. The Swift looks more like it was randomly copied from somewhere unrelated to the Android code. – Rob Napier Oct 05 '20 at 19:31
  • Maybe this question? https://stackoverflow.com/questions/55484384/swift-5-kccdecrypt-commoncrypto-failing-to-decrypt You can't just copy cryptography code without ensuring that every piece of the encryptor and decryptor match. Start with the Android code, and write Swift code to reverse each step in reverse order. – Rob Napier Oct 05 '20 at 19:32
  • @RobNapier pls share me a reference where I can found the same process as android. – Hitesh Matnani Oct 05 '20 at 19:48
  • There is no reference. Your Android code is an ad hoc, custom format (with some security problems in how it handles the IV and Key). You'll need to implement the same format in Swift. I only develop ad hoc formats on a consulting basis because SO answers won't help anyone else. Someone here may be willing to write this code for you. If you want to do it yourself, walk through each line of the Android code and translate it to Swift. Use a debugger or print statements to make sure that the output of each step is precisely the same on both sides. The Android code is very deterministic. – Rob Napier Oct 05 '20 at 20:08
  • @RobNapier please check my update question and correct me – Hitesh Matnani Oct 06 '20 at 05:56
  • 1
    @RobNapier thanks I have solved this – Hitesh Matnani Oct 06 '20 at 08:38
  • @HiteshMatnani Can you share your solution to help others with that problem? – André Nov 10 '20 at 13:54
  • @HiteshMatnaniCan you share the solution, I too have to encrypt any String. – Anand Gautam Apr 28 '22 at 09:39
  • 1
    @AnandGautam I have done a long back I will try to find the solution that I had implemented and will be sharing soon here thanks for waiting. – Hitesh Matnani May 03 '22 at 03:01

0 Answers0