Search code examples
phpcryptographymcryptfips

Is PHP's mcrypt extension FIPS 197 compliant?


I'm using the following encryption code which works like a charm, but I have to validate that it's FIPS 197 compliant otherwise Legal will kill me.

mcrypt_encrypt(MCRYPT_RIJNDAEL_256, SALT, $plaintext, MCRYPT_MODE_ECB,
               mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),
                                MCRYPT_RAND))

and

mcrypt_decrypt(MCRYPT_RIJNDAEL_256, SALT, $plaintext, MCRYPT_MODE_ECB,
               mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),
                                MCRYPT_RAND))

Solution

  • Mcrypt's RIJNDAEL_256 algorithm is the version of the Rijndael algorithm with 256 bit block size. AES (which is what FIPS 197 defines) has only versions with 128-bit block size (and three different key sizes).

    So no, you are not using AES here. Use RIJNDAEL_128 instead, which is the same as AES.

    There are other things wrong with your code:

    • You should never use ECB if you are encrypting more than one block with the same key. So, never. Use a secure mode of operation instead, like CBC or CTR.

    • As CodeInChaos commented, you normally want to make sure you also have authenticity, not only confidentiality (and depending on your protocol, you might even need authentication for confidentiality). So, add a MAC to your message, or use a mode of operation which also gives authentication together with confidentiality (like CCM or GCM) - not sure which ones are included in mcrypt.

    • You generate a random initialization vector on encryption (good) and decryption (bad). This doesn't matter for ECB, since it doesn't use an initialization vector, but with any other mode you'll get a different initialization vector for both actions, meaning that decryption will get different results. With CBC only the first block will be garbage, while with CTR everything will be garbage (and CCM/GCM will simply report "fail").

      As the initialization vector doesn't need to be secret (just non-predictable or non-repeating, depending on the mode), it is custom to either send it together with the message (as a prefix), or to derive it (on both sides) from a common secret (like the first initialization vectors in SSL/TLS, which are derived from the master secret, just as the encryption keys and MAC keys).