5

I have been able to successfully encrypt and decrypt AES-256 in both php and objective-c code. I won't post any code here since I have tried many varieties and none work. I have no idea how these encryption functions work... AES is a standardized algorithm, so why it doesn't work in my thinking boils down to

a) the iv
b) some encoding error
or
c) differences in padding (should be irrelevant for decryption).

If someone has AES functions that work in both php and objective-c that would be wonderful, but if not, any help in understanding what is causing these varied results would be appreciated.

If you want a more narrow question, it is about encodings, iv, and block size of this AES cipher.

1) Does it matter what encoding is used in terms of the key and the plaintext/ciphertext? Basically I'm guessing it is not a problem with the plain text since all the characters that I would use (at least during testing) are standard ASCII symbols. But lets say php strings are ASCII and I am using UTF8 in objective-c... I don't know enough to say if php uses ASCII or if the bytes ie. the key would be different between the two.

2) To my knowledge the ECB mode uses no iv (correct if wrong). CBC mode uses an iv. In this case, the iv must be recorded along with the cipher text. Now this key is 16 or 32 chars long in php (depending on 128 vs 256 block size). This means 16 or 32 bytes? And will the string 1234567890123456789012 be the same in ASCII and UTF8 when converted to bytes?

3) What is the difference between block size and key size in terms of the alogrithm? (again correct if wrong) Basically they are all the same algorithm just different parameters? And using a 256 bit key vs a 128 bit key is just a matter of which key is passed

(Also, note that I have been using base64 encoding to transfer strings between the applications for testing)

Thanks, Elijah

user1122069
  • 1,767
  • 1
  • 24
  • 52
  • 2
    `... I could not get openssl to work on the Mac with an error` Well, than why don't you ask a question about that specific error? – phihag Dec 29 '11 at 23:38
  • because at this point I do not even think that that would work. I used a category on NSData AES256EncryptWithKey and this also works for decoding on the mac. The 'particular error' that I am getting is that the code, once encrypted in objective-c and printed to the console in base-64 does not decrypt using php. – user1122069 Dec 30 '11 at 01:07
  • sorry, that last sentence wasn't releant – user1122069 Dec 30 '11 at 03:31

2 Answers2

6

For decryption to work correctly, everything must be exactly the same. Same key, same IV, same mode. In particular the key must be the same. Byte for byte the same. Bit for bit the same. AES is designed to fail to decrypt correctly if even one bit of the key is incorrect.

Reading your question, I suspect that your problem lies with the key. Your real key is not characters, it is bytes. There are a number of different ways to translate between characters and bytes, which can cause decryption to fail. You need to be certain that the two keys match byte for byte, not character for character. At the very least you need to be explicit about what mapping is used. Don't rely on system defaults as they can differ across systems.

Looking at your three questions:

1) For plaintext encoding you will get back exactly what you put in: UTF-8 in, UTF-8 out. If you want to convert to a different encoding then you will have to do it after decryption.

2) You are right that ECB doesn't need an IV, but ECB mode leaks information and should be avoided. Use CBC or CTR mode instead, the same mode at both ends. The IV is tied to the block size, so for AES the IV is always 16 bytes or 128 bits. You cannot guarantee that ASCII and UTF-8 will be the same. UTF might have a BOM at the start. ASCII might have a C-style zero byte at the end. Don't think in terms of characters, think in terms of bytes. Everything has to match at the byte level. In CBC mode a faulty IV will munge up the first block but decrypt subsequent blocks OK.

3) Block size is fixed at 128 bits for AES and cannot be changed. Key sizes are less constrained, and can be 128, 192, or 256 bits. In practice most people seem to use 128 or 256 bits. A block is a conveniently sized processing unit that is built into the cypher at a very low level. The key determines what is done to the block in the course of the processing. That allows more flexibility for the key. The key you enter is used to build some internal structures, the "round keys". This process is called "key expansion". It is the round keys which interact with the block being processed. Because the key is used indirectly there is more flexibility about how large it can be.

rossum
  • 15,344
  • 1
  • 24
  • 38
  • thank you. I will dump the hex values and try to match them. As for #3, however, what you said makes sense, but please explain the last post marked -2 on this page (http://stackoverflow.com/questions/8276833/aes-rijndael-on-php-server-and-ios-generates-sometimes-different-ciphers). The negation of this post means that in MCRYPT_RIJNDAEL_128 refres to the block side... but php also has MCRYPT_RIJNDAEL_256. Thus this user uses MCRYPT_RIJNDAEL_128 in php and AES256DecryptWithKey in objective-c. This would imply either the existance of a 256 bit block side (the 256 php constant). – user1122069 Dec 30 '11 at 20:16
  • Rijndael is a superset of AES. Rijndael can have block sizes from 128 bits upwards, in multiples of 32 bits. AES is restricted to 128 bit blocks only. It is more commonly the case that people mean AES when they say 'Rijndael' and the -128 or -256 are key sizes, not block sizes. Jonathan's comment there is likely correct. – rossum Dec 30 '11 at 22:43
  • that makes sense about the superset. However it looks like you are incorrect about the -128 -256 being the key sizes. The author uses a 32-bit key with Rijndael-128 and matches the php algorithm with a AES256... function in objective-c. I will spend some more time on this project and see how it goes. – user1122069 Dec 31 '11 at 02:42
  • Good news: I was able to decode in php code encrypted in objective-c (AES256DecryptWithKey) The bad news, not really bad news is that I had been only counting to 22 (two full number sequences +12) for my test key. What I found was that ASCII and UT8 were both exactly the same bitwise. When converted to hex, both were composed of 32 8 char sections, and ASCII is backward compatible. – user1122069 Dec 31 '11 at 20:18
  • For anyone's reference, I found that AES256DecryptWithKey and CCCrypt with null IV both work in CBC mode with a 16bit / 16 char length iv. PHP code to create this iv: $iv2 = ''; for($i=0;$i<16;$i++){ $iv2 .= "\0"; } // and decrypt $plain_text_EBC = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $encrypted_text, MCRYPT_MODE_CBC, $iv2); Not that I plan on using one in general. – user1122069 Dec 31 '11 at 20:21
  • I would also recommend reviewing this question: http://stackoverflow.com/questions/6461419/aescrypt-decryption-between-ios-and-php-fixed – Tails Jan 07 '12 at 21:16
0

In terms of encoding of the key, IV, plaintext, and ciphertext, AES encryption does not use encoding. AES encryption uses binary data -- a sequence of 8-bit bytes.

You need the same binary key, binary IV, and binary ciphertext on the decrypting platform, to produce the original binary plaintext.

When you are converting between character encodings and binary, you are not always guaranteed a round-trip conversion. That is, not all sequences of bytes can be converted to strings of UTF-8 characters.

However, if you treat UTF-8 plaintext as binary data, and encrypt it, and then transport the ciphertext as binary, for example, by encoding it as base64 to preserve the binary representation of the data, then when you base64-decode to reconstitute the binary ciphertext on the decrypting platform, and decrypt, the resulting binary plaintext will be the original UTF-8 character data.

Always treat the key, IV, plaintext, and ciphertext as binary data in terms of encryption and decryption. The plaintext is binary data that just might happen to be UTF-8, or some variant of ASCII, or UTF-16BE, etc. The ciphertext will probably be none of those, or, happen to be one of those purely by chance.

Jim Flood
  • 8,144
  • 3
  • 36
  • 48