How to Decrypt a string using AES-256 CFB with PKCS5PADDING in swift?

918 Views Asked by At

I am looking to decrypt a string using AES, I tried multiple solution from SO but none of them helped and I was unable to get the solution. The android developer used Cipher to do it below is the code for that:-

    private static final byte[] initVector = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

    private static Cipher getAES_Cipher(int opmode) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
        InvalidAlgorithmParameterException {
    IvParameterSpec iv = new IvParameterSpec(initVector);
    SecretKeySpec skeySpec = new SecretKeySpec(Arrays.copyOfRange(getSHA(key), 0, 32), "AES");

    Cipher cipher = Cipher.getInstance("AES/CFB/PKCS5PADDING");
    cipher.init(opmode, skeySpec, iv);
    return cipher;
}

Similarly I tried using CryptoSwift to do it and below is the code I used to do it:-

extension String {


func aesEncrypt(key: String, iv: String) throws -> String {

    let data: Array<UInt8> = (self.data(using: .utf8)?.bytes)!
    var key: Array<UInt8> = (key.data(using: .utf8)?.bytes)!
    let iv: Array<UInt8> = (iv.data(using: .utf8)?.bytes)!

    do {
        let encrypted = try AES(key: key, blockMode: CFB(iv: iv), padding: .pkcs5).encrypt(data)
        let encryptedData = Data(encrypted)
        let decrypted = try AES(key: key, blockMode: CFB(iv: iv), padding: .pkcs5).decrypt(encrypted)
        let decryptedData = Data(decrypted)
        let str = String.init(data: decryptedData, encoding: .utf8)
        print(str ?? String())
        return encryptedData.base64EncodedString()

    } catch {
        print(error)
        return "error"
    }
}

func aesDecrypt(key: String, iv: String) throws -> String {

    let data: Array<UInt8> = (Data(base64Encoded: self)?.bytes)!
    let key: Array<UInt8> = (key.data(using: .utf8)?.bytes)!
    let iv: Array<UInt8> = (iv.data(using: .utf8)?.bytes)!



    do {
        let decrypted = try AES(key: key.sha256(), blockMode: CFB(iv: iv), padding: .pkcs5).decrypt(data)
        let decryptedData = Data(decrypted)
        guard let value = String.init(data: decryptedData, encoding: .utf8) else {
            return "error"
        }
        return value

    } catch {
        print(error)
        return "error"
    }
}

}

and In ViewDidLoad() I called it like this:-

    let message = "My Encrypted String From The Server"
    let test = try! message.aesDecrypt(key: "dfksjghlskjdfhglksjdfhglkjsdhfglkjhsfopweiurtypoweirutopiewrutgopiruegoijnsdeghsedrghesrerthigoererhehewthgewrhywertyweyweyewrtewrtyewihgoie", iv: "0000000000000000")

    print(test)

One more thing I want to highlight when I pass the same iv as android which is "{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }" I am getting the error from the CryptoSwift library as invalidInitializationVector but when I pass iv: "0000000000000000" I am getting an error -->

  guard let value = String.init(data: decryptedData, encoding: .utf8) else {
        return "error"
    }

I believe it is something related to the iv that I am passing there.

Guys any help would be greatly appreciated!!

Thank You

1

There are 1 best solutions below

0
On BEST ANSWER

Found that question when tried to decode some data using CryptoSwift. Tried the code and it didn't work for me too (did return "error").

The issue is in decrypt method and is related to key.

You have for encryption:

let encrypted = try AES(key: key, blockMode: CFB(iv: iv), padding: .pkcs5).encrypt(data)

But to decryption the code looks like this:

let decrypted = try AES(key: key.sha256(), blockMode: CFB(iv: iv), padding: .pkcs5).decrypt(data)

For me removing .sha256() fixed the issue.

So final decrypt method should be:

func aesDecrypt(key: String, iv: String) throws -> String {

    let data: Array<UInt8> = (Data(base64Encoded: self)?.bytes)!
    let key: Array<UInt8> = (key.data(using: .utf8)?.bytes)!
    let iv: Array<UInt8> = (iv.data(using: .utf8)?.bytes)!

    do {
        let decrypted = try AES(key: key, blockMode: CFB(iv: iv), padding: .pkcs5).decrypt(data)
        let decryptedData = Data(decrypted)
        guard let value = String.init(data: decryptedData, encoding: .utf8) else {
            return "error"
        }
        return value
    } catch {
        print(error)
        return "error"
    }
}

Maybe it will help someone and save some time.