Description

Parameters

One of the MCRYPT_ciphername constants, or the name of the algorithm as string.

key

The key with which the data will be encrypted. If the provided key size is
not supported by the cipher, the function will emit a warning and return FALSE

data

The data that will be encrypted with the given cipher
and mode. If the size of the data is not n * blocksize,
the data will be padded with '\0'.

The returned crypttext can be larger than the size of the data that was
given by data.

mode

One of the MCRYPT_MODE_modename constants, or one of the following strings: "ecb", "cbc", "cfb", "ofb", "nofb" or "stream".

iv

Used for the initialization in CBC, CFB, OFB modes, and in some algorithms in STREAM mode. If the provided IV size is not supported by the chaining mode or no IV was provided, but the chaining mode requires one, the function will emit a warning and return FALSE.

Return Values

Returns the encrypted data as a string or FALSE on failure.

Changelog

Version

Description

5.6.0

Invalid key and iv sizes
are no longer accepted. mcrypt_encrypt() will now throw
a warning and return FALSE if the inputs are invalid. Previously keys and
IVs were padded with '\0' bytes to the next valid size.

Examples

Example #1 mcrypt_encrypt() Example

<?php# --- ENCRYPTION ---

# the key should be random binary, use scrypt, bcrypt or PBKDF2 to # convert a string into a key # key is specified using hexadecimal$key = pack('H*', "bcb04b7e103a0cd8b54763051cef08bc55abe029fdebae5e1d417e2ffb2a00a3");

User Contributed Notes 14 notes

mcrypt's 3DES only accepts 192 bit keys, but Microsoft's .NET and many other tools accept both 128 and 192 bit keys.If your key is too short, mcrypt will 'helpfully' pad null characters onto the end, but .NET refuses to use a key where the last third is all null (this is a Bad Key). This prevents you from emulating mcrypt's "short key" behaviour in .NET.

How to reconcile this? A little DES theory is in order3DES runs the DES algorithm three times, using each third of your 192 bit key as the 64 bit DES key

Encrypt Key1 -> Decrypt Key2 -> Encrypt Key3

and both .NET and PHP's mcrypt do this the same way.The problem arises in short key mode on .NET, since 128 bits is only two 64 bit DES keysThe algorithm that they use then is:

Encrypt Key1 -> Decrypt Key2 -> Encrypt Key1

mcrypt does not have this mode of operation natively.but before you go and start running DES three times yourself, here's a Quick Fix<?php$my_key = "12345678abcdefgh"; // a 128 bit (16 byte) key$my_key .= substr($my_key,0,8); // append the first 8 bytes onto the end$secret = mcrypt_encrypt(MCRYPT_3DES, $my_key, $data, MCRYPT_MODE_CBC, $iv); //CBC is the default mode in .NET?>

And, like magic, it works.

There's one more caveat: Data paddingmcrypt always pads data will the null characterbut .NET has two padding modes: "Zeros" and "PKCS7"Zeros is identical to the mcrypt scheme, but PKCS7 is the default.PKCS7 isn't much more complex, though:instead of nulls, it appends the total number of padding bytes (which means, for 3DES, it can be a value from 0x01 to 0x07)if your plaintext is "ABC", it will be padded into:0x41 0x42 0x43 0x05 0x05 0x05 0x05 0x05

You can remove these from a decrypted string in PHP by counting the number of times that last character appears, and if it matches it's ordinal value, truncating the string by that many characters:<?php $block = mcrypt_get_block_size('tripledes', 'cbc');$packing = ord($text{strlen($text) - 1}); if($packing and ($packing < $block)){ for($P = strlen($text) - 1; $P >= strlen($text) - $packing; $P--){ if(ord($text{$P}) != $packing){$packing = 0; } } }$text = substr($text,0,strlen($text) - $packing);?>

And to pad a string that you intend to decrypt with .NET, just add the chr() value of the number of padding bytes:<?php $block = mcrypt_get_block_size('tripledes', 'cbc');$len = strlen($dat);$padding = $block - ($len % $block);$dat .= str_repeat(chr($padding),$padding);?>

That's all there is to it.Knowing this, you can encrypt, decrypt, and duplicate exactly any .NET 3DES behaviour in PHP.

It is always better to use a standard encryption cipher's rather than to "roll your own", firstly the standard cipher has been tested by world class crypto-analysis's where as unless your a world class crypto-analysis (and if you are why are you even thinking of rolling your own?!?) you won't have the skills needed to even test it (for example if you just XOR each character with a key, it may look secure (the text will be different) but if you count the number of times a character is repeated you see whatever the letter "E" encrypts to occurs more often then the encrypted "Z" (assuming English language plain text)

Secondly, you may think that the hidden nature of your cipher makes it more secure, but the fact is that your cipher is likely *only* secure because it's secret, if someone what able to break-in to your site and steal your code (but not your key) they maybe able break you encrypted data, if someone broke in and found you where using Blowfish (for example) it wouldn't help them.

I wasn't too impressed with the suggested functions/classes for using mcrypt, so I wrote my own class. The encypted output is base64 encoded so it can be used in URLs, emails, etc. MCRYPT_RIJNDAEL_256 is probably too secure for most uses, using a less secure algorithm should mean that the encryption will be faster and the encrypted output shorter (make sure to update iv_size in mcrypt_create_iv() and key length to match the new algorithm). If you are going to use only 1 passphrase, you should define it inside __construct($this->securekey) instead of when creating the object. Keep the class in a separate include file which is only readable by your webserver (or whatever needs it) for added security.

I should mention that ECB mode ignores the IV, so it is misleading to show an example using both MCRYPT_MODE_ECB and an IV (the example in the manual shows the same thing). Also, it's important to know that ECB is useful for random data, but structured data should use a stronger mode like MCRYPT_MODE_CBC

Also, rtrim($decryptedtext, "\0") would be a better option to remove NULL padding than my lazy trim()...

In the other notes there are some misconceptions about crypto and the IV, especially for CBC mode.

The most important point: Encryption DOES NOT provide any proof of data integrity or authentication WHATSOEVER. If you need to be sure that the data is secret and not tampered with, you need to encrypt THEN use a keyed HMAC.

For CBC mode, the IV DOES NOT need to be secret. It can be sent along with the plaintext. It needs to be UNIQUE and RANDOM. So that every message is encrypted with a different IV.

// cut the output with substr(), NOT by using rtrim() as is suggested in some of // the mcrypt manual pages - this is binary data, not plaintextecho ( md5(substr($dec, 0, $size)) == $cksum ? 'ok' : 'bad' ) . PHP_EOL;}

I tried to implement the mcrypt with rijndael-128. For reference I took the code from example #1 and tried running that first, but on the decryption part came back with the error: "The IV parameter must be as long as the blocksize". After a while i figured out that the generated IV string will not have the same length every run, and is almost never the size of the result of mcrypt_get_iv_size. To work around that, before merging the IV and the encrypted text, I added null padding to match the IV size. When retrieving the IV, I then could use the IV size and rtrim null padding to get the matching IV back.

I was trying (and succeeded) to encrypt and decrypt in JAVA, pass it to php, and do it again,without corrupting data when I noticed something interesting. So, my code goes like this:$data = 'one';$key = '1234567890123456';

//In the beginning, I thought something's wrong, because I did '===' comparison between $decrypted and $data. It didn't work (but later started working, again, dont know why...) So, I dumped both:var_dump($data);var_dump($decrypted);//Results:string(16) "one" string(16) "one" //Clearly, the length of both is 3, not 16. Just wanted to let you know what could happen, and I really don't know if this is a bug... Thanks,S.

I've noticed some people using a-z, A-Z and 0-9 for keys and stating things like "16 characters is a 128-bit key". This isn't true. Using only these characters, you will get at most 6 bits of entropy per chartacter:

log2(26 + 26 + 10) = 5.954196310386876

So you're actually only getting 95 bits of entropy in 16 characters, which is 0.0000000117% of the keyspace you would get if you were using the full range.

In order to get the full entropy from a key using just a-z, A-Z and 0-9 you should multiply your key length by 1.3333 to account for the 2 bits of lost entropy per byte.

This is a solution for the 3DES algorithm's problem in his interaction with .NET TripleDESCryptoServiceProvider (System.Security.Cryptography), CBC mode, because the key is completed to 192bits and the text is padded.

So, we has two problems: - The key's completion was posted by "jesse at pctest dot com". - The text padding also posted by him, but the completion is a little different. The padding bytes are 0x01 to 0x08 because completed to 8 bytes blocks. If your text have a whole number of 8 bytes blocks, the algorithm add other block with padded bytes (0x08).

This is a function to encrypt a text in a equal form that the Dot NET algorithm:

Most of the user-written cipher examples here are badly broken, and there are a few cases where the manual says things that are outright incorrect, such as that it's "safe to transmit the initialization vector in plaintext" (this is incorrect: see Ciphers By Ritter, http://www.ciphersbyritter.com/GLOSSARY.HTM#IV , for details.)

mcrypt itself is perfectly safe, but correct and therefore safe usage is inobvious. It is important to use a cryptographic library correctly; a simple usage error, even when it produces results that can be unpacked at the other side, can render a strong algorithm completely useless.

The initialization vector must be permuted with a recoverable noise source (an arbitrary md5 hash is acceptable, since it's just a fake OTP and its origin contents are wholly unimportant.)

Passwords should be remade with a salted one-way hash (md5 is again acceptable even though it's been damaged, since the only thing you could recover from a cracked md5 hash is the source data to generate the password, which is useless.)

It's important to use a sane block mode (OFB is unsafe for almost all algorithms; never use it. Prefer CBC in all cases except where you need to deal with a degraded signal and cannot retransmit.)

A correct usage example is actually pretty long and needs a lot of explanation, so I developed a safe wrapper library which doesn't constrain usage and which comments itself very heavily. It's appropriate for use or for learning. Please see my blog for details on Stone PHP SafeCrypt: