mcrypt_create_iv

(PHP 3 >= 3.0.8, PHP 4, PHP 5)

mcrypt_create_iv --  Create an initialization vector (IV) from a random source

Description

string mcrypt_create_iv ( int size [, int source] )

mcrypt_create_iv() is used to create an IV.

Parameter size determines the size of the IV, parameter source (defaults to random value) specifies the source of the IV.

The source can be MCRYPT_RAND (system random number generator), MCRYPT_DEV_RANDOM (read data from /dev/random) and MCRYPT_DEV_URANDOM (read data from /dev/urandom). MCRYPT_RAND is the only one supported on Windows because Windows (of course) doesn't have /dev/random or /dev/urandom.

注: When using MCRYPT_RAND, remember to call srand() before mcrypt_create_iv() to initialize the random number generator; it is not seeded automatically like rand() is.

例子 1. mcrypt_create_iv() example

<?php
    $size
= mcrypt_get_iv_size(MCRYPT_CAST_256, MCRYPT_MODE_CFB);
    
$iv = mcrypt_create_iv($size, MCRYPT_DEV_RANDOM);
?>

The IV is only meant to give an alternative seed to the encryption routines. This IV does not need to be secret at all, though it can be desirable. You even can send it along with your ciphertext without losing security.

More information can be found at http://www.ciphersbyritter.com/GLOSSARY.HTM#IV, http://fn2.freenet.edmonton.ab.ca/~jsavard/crypto/co0409.htm and in chapter 9.3 of Applied Cryptography by Schneier (ISBN 0-471-11709-9) for a discussion of this topic.


add a note add a note User Contributed Notes
Anonymous
18-Oct-2005 12:01
At:
edwardzyang at thewritingpot dot com
19-Jul-2005 10:06

This is because of the fact, that (like described in the manual above) this function does NOT reseed the random number generator, in contrary to rand(). Use srand() like suggested above to get correct IVs.
05-Sep-2005 02:12
Correction to the last comment, the second parameter of rtrim() uses double quotes, not single quotes.

So the corrected code is as follows:

   $retval = rtrim($retval, "\0");    // trim ONLY the nulls at the END

;)
edwardzyang at thewritingpot dot com
20-Jul-2005 04:06
For some reason, on my Windows installation, MCRYPT_RAND doesn't work at all: it always gives the same IV. This is a huge problem, especially for OFB and CTR, where using the same IV destroys security.

Fortunantely, it's easy to emulate the IV function using other random generators that do indeed work (such as rand() ). Here's an example:

<?php

function alt_mcrypt_create_iv ($size) {
  
$iv = '';
   for(
$i = 0; $i < $size; $i++) {
      
$iv .= chr(rand(0,255));
   }
   return
$iv;
}

?>

Note that this doesn't make it "more random" in any way, it just let's you use your own favorite random function to create randomness than the quirky mcrypt_create_iv.
04-Jun-2005 12:53
First, the IV should be random and variable. The whole point of it is to ensure that the same plaintext does not encrypt to the same ciphertext every time. You most certainly do lose security if the IV is constant or public.

The ciphertext should be E(IV | plaintext, key)

Second, the IV should not be part of the decryption parameters at all. You should be able to decrypt the cipher text, throw away the initial vector at the front w/o even reading it, and have your plaintext:

[IV | plaintext ] = D(ciphertext, key)

All that is public is the size of the IV.

These are well-known facts about cryptography. Check N. Kobliz's books for backup.

Unless mcrypt conforms to the above, it is very seriously flawed and should not be used.
tim at indigopixel dot com
18-Mar-2004 08:32
From http://www.ciphersbyritter.com/GLOSSARY.HTM#IV (linked to above):

"While it is often said that IV values need only be random-like or unpredictable, and need not be confidential, in the case of CBC mode, that advice can lead to man-in-the-middle attacks on the first plaintext block. If a MITM opponent knows the usual content of the first block, they can change the IV to manipulate that block (and only that block) to deliver a different address, or different dollar amounts, or different commands, or whatever. And while the conventional advice is to use a MAC at a higher level to detect changed plaintext, that is not always desirable or properly executed. But the CBC first-block problem is easily solved at the CBC level simply by enciphering the IV and otherwise keeping it confidential, and that can be reasonable even when a MAC will be used later."
robert at peakepro dot com
04-Mar-2004 04:25
It is important to note that all cipher modes except ecb require the same IV to be used in decryption as was used in encryption.

You need to pass the key *and* the IV to your decrypt function. Initializing a new IV in the decrypt routine will not work.

Since, "you even can send [the IV] along with your ciphertext without  loosing security," a nice way to handle this is to prepend your IV to your ciphertext. Since the IV is fixed-width, you can then easily recover the IV and original ciphertext using mcrypt_get_iv_size() and substr().

Here is an example:

<?PHP
function my_encrypt($string,$key) {
  
srand((double) microtime() * 1000000); //for sake of MCRYPT_RAND
  
$key = md5($key); //to improve variance
  /* Open module, and create IV */
 
$td = mcrypt_module_open('des', '','cfb', '');
 
$key = substr($key, 0, mcrypt_enc_get_key_size($td));
 
$iv_size = mcrypt_enc_get_iv_size($td);
 
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
 
/* Initialize encryption handle */
  
if (mcrypt_generic_init($td, $key, $iv) != -1) {

    
/* Encrypt data */
    
$c_t = mcrypt_generic($td, $string);
    
mcrypt_generic_deinit($td);
    
mcrypt_module_close($td);
      
$c_t = $iv.$c_t;
       return
$c_t;
   }
//end if
}

function
my_decrypt($string,$key) {
  
$key = md5($key); //to improve variance
  /* Open module, and create IV */
 
$td = mcrypt_module_open('des', '','cfb', '');
 
$key = substr($key, 0, mcrypt_enc_get_key_size($td));
 
$iv_size = mcrypt_enc_get_iv_size($td);
 
$iv = substr($string,0,$iv_size);
 
$string = substr($string,$iv_size);
 
/* Initialize encryption handle */
  
if (mcrypt_generic_init($td, $key, $iv) != -1) {

    
/* Encrypt data */
    
$c_t = mdecrypt_generic($td, $string);
    
mcrypt_generic_deinit($td);
    
mcrypt_module_close($td);
       return
$c_t;
   }
//end if
}
// to test:
//print my_decrypt(my_encrypt("Hello, world.","foo"),"foo");
?>
fandelem at hotmail dot com
07-Mar-2002 07:59
note: if you are experiencing a problem about complaining that the second parameter has to be a 'long' and you are giving a 'string' (for me, it was using MCRYPT_URANDOM) you might want to try MCRYPT_DEV_URANDOM :)