1

I have few questions about this code:

<?php 
   $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB); 
   $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND); 
   $key = "This is a very secret key"; 
   $text = file_get_contents('path/to/your/file'); 
   echo strlen($text) . "\n"; 

   $crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_ECB, $iv); 
   file_put_contents('path/to/your/file', $crypttext);    
?> 

It encrypts the file just fine, however it adds additional nulls at the end, so if I encrypt:

 a test string is this one
    and here is a new line 

once decrypted becomes:

a test string is this one
    and here is a new line 000000000000000

What's going on?

Second, is MCRYPT_RIJNDAEL_256 compatible with AES-128?

Finally, how would I let another party decrypt a file I've encrypted? They would need to know which encryption was used and I am not sure what to tell them.

Sergiu Dumitriu
  • 11,455
  • 3
  • 39
  • 62
Asim Zaidi
  • 27,016
  • 49
  • 132
  • 221

3 Answers3

7

Much of what I'm about to explain can be gleaned from @ircmaxwell's excellent slidedeck: Cryptography For The Average Developer which you should check out immediately. I'll reiterate one of his main points: Avoid writing code that deals with encryption/decryption. Unless you understand all the factors you will probably flub it.


MCRYPT_RIJNDAEL_128 closely matches AES

The Advanced Encryption Standard was created by The National Institute of Standards and Technology. NIST chose the Rijandael cipher from a competitive pool of cryptographic experts.

Common confusion: the numbers in AES and Mycrpt refer to different things

  • AES-128 refers to 128 bit key size
  • AES-256 refers to 256 bit key size
  • MCRYPT_RIJNDAEL_128 refers to a 128 bit cipher block size
  • MCRYPT_RIJNDAEL_256 refers to a 256 bit cipher block size

Key size and block size

Key Size refers to the length of the secret used to encrypt/decrypt. A 256 bit key is 32 bytes, roughly 32 characters.

Block Size is a property of block ciphers (i.e. all AES candidates) which chunk out the data to a specific size during the cipher process.

  • AES specifies a 128 bit cipher block
  • Mcrypt's Rijndaels all accept 256 bit keys
  • based on key/block size MCRYPT_RIJNDAEL_128 seems to conform closest to AES-256
    • there are other factors to consider — like how many transformation rounds occur? — it's hard to verify this aspect without digging into the source code

Mode of Operation

The mode is an important element.

Both ECB and CBC mode pad your plaintext into the block size. If you're encrypting 1 byte of data with a 128 bit block size you will get 15 null bytes. Padding opens up the possibility for a padding oracle attack.

Beyond padding ECB does not make use of an Initialization Vector (IV) which leaves you open to a potential vulnerability: prefer CBC or CFB mode.

You can avoid both problems by using CFB mode which does not need padding and therefore does not require post-decryption trimming.

Initialization Vector (IV)

When creating your IV you need a crypto-strong random source: MCRYPT_RAND is not random enough — MCRYPT_DEV_RANDOM or MCRYPT_DEV_URANDOM are preferred.

$iv_size = mcrypt_get_iv_size(
    MCRYPT_RIJNDAEL_128,
    MCRYPT_MODE_CFB
);

$iv = mcrypt_create_iv(
    $iv_size,
    MCRYPT_DEV_URANDOM
);

Finally, for your friends

In order to decrypt your friend will need to know:

  • the cipher — MCRYPT_RIJNDAEL_128
  • the block mode — MCRYPT_MODE_CFB
  • the IV — each element you encrypt should get a unique IV, so you'll want to append the IV to the encrypted data
  • the key — this is secret, and should stay the same for all encryptions; if your key gets compromised rotate it out

Only the key needs to stay secret. Depending on your transport method you should consider implementing a data integrity check to ensure the ciphertext data wasn't tampered with. Again, see @ircmaxwell's excellent slidedeck: Cryptography For The Average Developer for an example of creating an HMAC fingerprint using hash_hmac().

It should be obvious that the maintenance all of these moving parts is rife with complexity. Tread carefully.

Other ciphers

Mcrypt gives you other cipher options. Some, like DES, are not recommended. Others were candidates for AES, like Blowfish, TwoFish, and Serpent. Rijandael is a vetted, proven cipher, and is recommended.

Community
  • 1
  • 1
Mark Fox
  • 8,694
  • 9
  • 53
  • 75
1

MCRYPT_RIJNDAEL_128 is AES-128, MCRYPT_RIJNDAEL_256 is AES-256 - just another name:

[...]The standard comprises three block ciphers, AES-128, AES-192 and AES-256, adopted from a larger collection originally published as Rijndael.originally published as Rijndael.[...]

[...]The Rijndael cipher was developed by two Belgian cryptographers, Joan Daemen and Vincent Rijmen, and submitted by them to the AES selection process. Rijndael (pronounced "Rhine dall") is a wordplay with the names of the two inventors.[...]

The \x00 characters you encounter at the end of the decrypted string are the padding required for some block ciphers (with ECB being such a block cipher). Mcyrpt uses NULL-padding internally if the input data needs to be padded to the required block length. There are other padding modes available (which have to be user-coded when using Mcyrpt), namely PKCS7, ANSI X.923 or ISO 10126. NULL-padding is problematic when encrypting binary data that may end with one or more \x00 characters because you can't detect where the data ends and the padding starts - the other padding modes mentioned solve this kind of problem. If you're encrypting character data (strings) you can easily trim off the trailing \x00 by using $data = trim($data, "\x00");.

To decrypt the data you sent to a consumer, the consumer would need to know the IV (initialization vector) ($iv), the algorithm used (MCRYPT_RIJNDAEL_256/AES-256), the encryption mode (ECB), the secret encryption key ($key) and the padding mode used (NULL-padding). The IV can be transmitted with the encrypted data as it does not need to be kept secret:

The IV must be known to the recipient of the encrypted information to be able to decrypt it. This can be ensured in a number of ways: by transmitting the IV along with the ciphertext, by agreeing on it beforehand during the key exchange or the handshake, by calculating it (usually incrementally), or by measuring such parameters as current time (used in hardware authentication tokens such as RSA SecurID, VASCO Digipass, etc.), IDs such as sender's and/or recipient's address or ID, file ID, the packet, sector or cluster number, etc. A number of variables can be combined or hashed together, depending on the protocol.depending on the protocol.

Stefan Gehrig
  • 82,642
  • 24
  • 155
  • 189
  • 1
    MCRYPT_RIJNDAEL_256 is not AES-256, see my answer for details. – Mark Fox Nov 02 '13 at 00:50
  • *Furthermore* ECB is not a block cipher, the description of how to use an IV for ECB is incorrect as well. And it is called zero padding. So every part of this answer has major issues. – Maarten Bodewes Sep 08 '15 at 21:29
  • @MaartenBodewes: Instead of just criticizing, it'd surely be helpful to share your knowledge either in a separate answer or as an edit to this one. – Stefan Gehrig Sep 10 '15 at 09:47
  • @StefanGehrig I'm sharing my knowledge here in a daily basis. I've upvoted the [other answer](http://stackoverflow.com/a/19737721/589259) already; there seemed little need to do anything else. – Maarten Bodewes Sep 10 '15 at 09:50
0

MCRYPT_RIJNDAEL_128 is equivalent to AES-128 in mcrypt. This is documented under MCRYPT_RIJNDAEL_128 here: http://mcrypt.sourceforge.net/

Alan Geleynse
  • 24,821
  • 5
  • 46
  • 55