Search code examples
javaiosswiftencryptionaes

Not able to decrypt(AES) in iOS(Swift) from Java


I am unable to decrypt data on iOS(Swift) which I am getting from the Java server. But if I encrypt a data on iOS and then decrypt, it works well. There might be some variance on both side's AES code which I am not able to identify. Please help me.

Similar question asked here: https://github.com/krzyzanowskim/CryptoSwift/issues/458

iOS Decryptor

            let password = "SOME_ENCRYPTION_KEY"
            let iv = AES256Crypter.randomIv()
            let key = try AES256Crypter.createKey(password: password.data(using: .utf8)!, salt: salt)
            let aes = try AES256Crypter(key: key, iv: iv)
            let encryptedData = "encrypted_data".data(using: .utf8)
            let decryptedData = try aes.decrypt(encryptedData!)
            let decryptedString =  String(decoding: decryptedData, as: UTF8.self)
            print("Decrypted  string: \(decryptedString)")

Java Encryptor

SecretKeySpec secretKey;
        try {
            byte[] key = ENCRYPTION_KEY.getBytes("UTF-8");
            MessageDigest sha = MessageDigest.getInstance("SHA-1");
            key = sha.digest(key);
            key = Arrays.copyOf(key, 16);
            secretKey = new SecretKeySpec(key, "AES");

            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            return Base64.getEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes("UTF-8")));
        } catch (Exception e) {
            System.out.println("\nException while encrypting " + strToEncrypt + " \nerror: " + e.getMessage());
        }

Solution

  • Below is the code for Encryption in Java and Decryption for iOS(Swift and Android(Kotlin). This works well but I am still open for a better solution.

    Java Code

    import javax.crypto.Cipher;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    import java.util.Base64;
    
    public class EncryptionUtils {
    
        private static String ENCRYPTION_KEY = "1234512345123456";
    
        public static void main(String[] args) {
            String encyString = new EncryptionUtils().encrypted("HJUSER153");
            System.out.println("Encrypted String:" + encyString);
         }
    
        public String encrypted(String strToEncrypt) {
             try {
                IvParameterSpec ivspec = new IvParameterSpec(ENCRYPTION_KEY.getBytes());
    
                SecretKeySpec keyspec = new SecretKeySpec(ENCRYPTION_KEY.getBytes(), "AES");
    
                Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
                return Base64.getEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes("UTF-8")));
                //encrypted = cipher.doFinal(text.getBytes());
            } catch (Exception e) {
                System.out.println("\nException while encrypting " + strToEncrypt + " \nerror: " + e.getMessage());
            }
            return null;
        }
    
    }
    

    iOS Swift Code

    Add this in pod file - pod 'CryptoSwift'

    import CryptoSwift
    
    func decrypt(input:String)->String?{
            let key = "1234512345123456"
            do{
                let d=Data(base64Encoded: input)
                let decrypted = try AES(key: key, iv: key, padding: .pkcs5).decrypt(
                    d!.bytes)
                return String(data: Data(decrypted), encoding: .utf8)
            }catch{
    
            }
            return nil
        }
    

    Android

    import android.util.Base64
    import java.security.NoSuchAlgorithmException
    import javax.crypto.Cipher
    import javax.crypto.NoSuchPaddingException
    import javax.crypto.spec.IvParameterSpec
    import javax.crypto.spec.SecretKeySpec
    
    class CypherHelper {
    
        private var ivspec: IvParameterSpec? = null
        private var keyspec: SecretKeySpec? = null
        private var cipher: Cipher? = null
        private val ENCRYPTION_KEY: String = "1234567890123456"
    
        init {
            ivspec = IvParameterSpec(ENCRYPTION_KEY.toByteArray(Charsets.UTF_8))
            keyspec = SecretKeySpec(ENCRYPTION_KEY.toByteArray(), "AES")
            try {
                cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
            } catch (e: NoSuchAlgorithmException) {
                e.printStackTrace()
            } catch (e: NoSuchPaddingException) {
                e.printStackTrace()
            }
        }
    
        fun decrypt(valueToDecrypt: String): String {
            var decryptValue: String = ""
            val enc = CypherHelper()
            if (valueToDecrypt.isEmpty())
                decryptValue = String(enc.decryptInternal(valueToDecrypt)!!)
    
            return decryptValue
        }
    
        private fun decryptInternal(code: String?): ByteArray? {
            if (code == null || code.isEmpty()) {
                throw Exception("Empty string")
            }
    
            var decrypted: ByteArray? = null
            try {
                cipher?.init(Cipher.DECRYPT_MODE, keyspec, ivspec)
                decrypted = cipher?.doFinal(Base64.decode(code, Base64.DEFAULT))
            } catch (e: Exception) {
                throw Exception("[decrypt] " + e.message)
            }
            return decrypted
        }
    }