Skip to content
Advertisement

AES encryption between iOS and Python

I have functions to encrypt/decrypt using AES (128 and 256) on both iOS (CCCrypt) and python (pycryptdome). All test cases working on each platform but… when I take an AES key and encrypted string from iOS to python the decryption fails. I have looked extensively and tried various use cases to no avail.

I’ve created a simple test case here with an iOS encryption and python decryption in the hopes that someone can tell me what i am doing differently on the platforms.

iOS code Test Case

JavaScript

The encryption and decryption in this code works fine and the output is:

JavaScript

When I take the encoded string and aes key to python to test with this code:

JavaScript

The decryption fails with output of

JavaScript

Both of the above routines work with locally encrypted data without issue, I have hacked the examples here (including not freeing the malloc’ed buffers :) for debugging purposes, so i apologize for the somewhat dirty code.

Note: I have tried changing the python mode to AES.MODE_CBC (and added padding code) when i saw notes iOS may use this rather than GCM, this failed as well… For now I have kept the nonce / iv as an array of 0 as I am told iOS will have used this as the default as the CCCrypt is not provided one, when this example works I will transition to specified iv.

I’d appreciate any direction.

EDIT: I went ahead and specified a null IV on the iOS side with

JavaScript

No change in behaviour at all…

EDIT: I set the IV to all char ‘1’ on both systems and got the same result. iOS added code:

JavaScript

Which produced

JavaScript

So on iOS it encrypts and decrypts properly with the byte 0 and char 1 IV….

And the python code works as well when encrypted and decrypted locally with either IV… But when the output from iOS encryption is used on python to decrypt it fails as shown here.

Moving the key and encrypted message to python for decryption as:

JavaScript

Resulted in:

JavaScript

So, still no joy…

It looks very much like the algorithm choice is the problem, but the options on iOS seems to only be GCM or CBC with GCM being the default… Most testing has been done on GCM. I attempted to use CBC in one test (with no IV as it does not need one) in case iOS was actually using this and not telling me, but as shown above, that also had no success.

I’m continuing to test approaches, but could really use some advice from someone who has made this work – i have not been able to find working examples. [as a side note, the RSA models work fine – this is how i am moving the AES key around – and that part of the solution is flawless at the moment, this is the last bit i need to get operational).

Advertisement

Answer

Edited to final answer with both ECB and CBC working between iOS and Python:

With credit to others who built the origional NSData_AESCrypt code at:

JavaScript

On iOS, encryption logic is modified from the original NSData+AESCrypt is modified as:

JavaScript

The resulting NSData element is then base64 encoded using some helper classes (used unmodified from the class) as:

JavaScript

The resulting base64 encoded string is then sent to the cloud where python pycryptodome can decrypt it as:

JavaScript

It is extremely important that the IV (aka nonce) is the same on iOS and Python when using CBC – it will not work otherwise. This is set in this case to a string of 16 ‘1’ characters terminated with a null. This is not really a secret key in itself, but it is likely worth changing it and securing it (possibly sending it as well with asymmetric, RSA in my case, encryption). The AES however is the critical key and should certainly be sent encrypted between the devices.

Finally, I’d recommend using the CBC even though the IV needs to be considered, as it is more secure. And when I have time I will look into integration of the Swift only Apple Crypto Kit library to support other forms as well…

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement