PHP AES/Rijndael Encryption Confusion

AES is not exactly synonymous with “Rijndael”. AES is a (restricted) variant of Rijndael.

AES has a fixed block size of 128 bits and a key size of 128, 192, or 256 bits, whereas Rijndael is specified with block and key sizes in any multiple of 32 bits, both with a minimum of 128 and a maximum of 256 bits.

PHP provides a general implementation Rijndael algorithm. The PHP mcrypt API is unintentionally misleading because most users would think that specifying MCRYPT_RIJNDAEL_256 means that you’ll get 256-bit encryption. This is NOT the case.  The MCRYPT_RIJNDAEL_256 is actually settinig the block size of the algorithm (not the strength).

  • See this for detailed information about PHP encryption (mcrypt)
  • The AES encryption standard is defined as Rjindael encryption (128-bit, 192-bit, or 256-bit) using a block size of 16 bytes. Chilkat implements the AES encryption standard.
  • When you specify MCRYPT_RIJNDAEL_256 in PHP, you are *NOT* setting the encryption strength to 256-bits. You are setting the block size to 256 bits. This is NOT AES encryption. To properly produce 256-bit AES encryption in PHP, you must provide a 32-byte encryption key (which implicitly sets the encryption strength), but the block size must be set to MCRYPT_RIJNDAEL_128 (16 bytes).

Format of AES, Blowfish, Twofish, 3DES, etc. Symmetric Encrypted Data?

Question:

I know it isn’t listed in the documentation, but is there any method to test whether a file has been previously encrypted or not?  I would like to perform decryption on a file, but only if it is already encrypted.

Answer:

A symmetric encryption algorithm is simply a transformation of bytes such that the output has the properties of randomly generated byte data.  There is no file format, and each byte value from 0x00 to 0xFF is virtually equally probable.

There is no single test that can be performed to determine if a file is already encrypted.  There are two solutions:

  1. Create your own test based on the  type of file being encrypted.  For example, if XML files are encrypted, then test to see if “<xml” is found in the beginning.
  2. Create your own simple “encrytped file format”.  For example, it could be as easy as writing a 4-byte “marker” at the beginning of every file containing encrypted data.  The marker would be a constant value, such as 0x01020304.  Your application could read the 1st 4 bytes of a file, and if equal to 0x01, 0x02, 0x03, 0x04, then it discards the marker and knows the remainder is the encrypted file data..

Getting Started with AES Decryption

This is a common question: You receive encrypted data and a key and want to decrypt. The person providing the encrypted data has provided little information, perhaps only that the encryption algorithm is AES. Where to do you begin, and what additional information, if any, do you need?

Answer:

AES encryption comes in 3 key sizes: 128-bit, 192-bit, and 256-bit. Look at the key you received. Which of the following does it look like:

  1. zxcv1234abcdQWER
  2. 7A786376313233346162636451574552
  3. enhjdjEyMzRhYmNkUVdFUg==

The strings above are all the same key encoded differently.

#1 is a us-ascii string that is exactly 16 characters.  This is a clue that the person gave you a 128-bit key (16 bytes * 8 bits/byte = 128) and that the bytes used for the key are the ascii values of the characters in the string.

#2 is a hexidecimal representation of #1.  If you have a hexidecimal representation of the key, you’ll notice that only the characters 0-9 and A-F (or a-f) are used.  Each byte of the key is represented by 2 ascii bytes.  If your hex string is 32 characters, you have a 16-byte key (and therefore 128-bit encryption).

#3 is a base64 encoded representation of #1.  The tell-tale signs of Base64 are:  It is often a string ending in “=” or “==”, and it is not a multiple of 16 characters in length, and it uses characters not valid in a hex string.  A base64 string will be about 1/3rd longer than the binary bytes it represents.  Thus it is longer than our ascii representation, but shorter than the hex representation.  Therfore, if it’s between 16 and 32 bytes, you can guess 128-bit encryption.  if longer than 32-bytes, it’s 256-bit encryption.

So… once you understand the key, you can set the KeyLength and secret key:

cryptObject.KeyLength = 128;

// If the key is represented as an ascii string:
cryptObject.SetEncodedKey(keyStr, "ascii");

// If the key is represented as an hexidecimal string:
cryptObject.SetEncodedKey(keyStr, "hex");

// If the key is represented as an base64 string:
cryptObject.SetEncodedKey(keyStr, "base64");

OK, the KeyLength and the secret key are specified. What’s left?
You need to know the following:

  • CBC or ECB mode?
  • If CBC mode, what is the initialization vector (IV)
  • Padding scheme?
  • Format of your encrypted data?

Chances are more likely that it is CBC mode (which stands for cipher block chaining).  If so, you need an initialization vector.  This will always be 16 bytes long, regardless of the key length.  If no IV is provided, then it’s probable that it is assumed to be all NULL bytes, and this is the default w/ the Chilkat component.

If you have the IV, then examine it just like you did for the key, and call SetEncodedIV just like you called SetEncodedKey, passing the correct encoding (“ascii”, “hex”, or “base64”) for the 2nd argument.

If ECB mode is used, then set the CipherMode property = “ecb”

cryptObject.CipherMode = "ecb";

The PaddingScheme property may be initially left at the default value (which is the most commonly used).  My suggestion is to test with an amount of data that is more than 16 bytes.  The reason is that if everything is correct *except* the PaddingScheme, then your decrypted output will be correct except for the very last 16 bytes.  Once you know that all is correct except for the padding scheme, you can test with different PaddingScheme values.  If you only have a very short amount of data for testing, then it’s not possible to make this distinction.

Finally, look at the encrypted data itself.  Is it hex or base64?  If it is a “string” it must be one or the other.  You’ll want to set the EncodingMode property equal to the encoding of the encrypted data:

cryptObject.EncodingMode = "hex";

Assuming the decrypted result is a string, you’ll call DecryptStringENC.  The “ENC” in the function name indicates that the input is an encoded string and that the encoding is specified by the EncodingMode property.  It returns a string — your decrypted data.

string decryptedStr = cryptObject.DecryptStringENC(encryptedStr);