Convert mcrypt Keys in PHP

If you're here, it's probably because you got this error (with slightly different details):

Warning: mcrypt_decrypt(): Key of size 29 not supported by this algorithm. Only keys of sizes 16, 24 or 32 supported in file.php on line 30

Chances are, that's because you recently upgraded to a new version of PHP. Starting in version 5.6.0, "Invalid key and iv sizes are no longer accepted. mcrypt_decrypt() will now throw a warning and return FALSE if the inputs are invalid."

The solution is to pick a new key that's one of those lengths and start using it, but first you'll have to convert your old data. Here's how:

First, set these variables:

$old = 'oGCsqAzkxNG4HzJK7wP'; //your old key
$new = 'ZxbE6GBduZtDXmEFV7FKdozEEdaxpWZf'; //your new key
$table = 'example'; //the MySQL table you're updating
$cols = array('password'); //the column(s) you're updating
$idcol = 'id'; //the name of your ID column

An easy way to get your new 32-character key is by using our random password generator.

Once that's done, you'll want to confirm that the new key is the right length. You'll also need to pad your old key so that it's usable. According to the documentation, "Previously keys and IVs were padded with '\0' bytes to the next valid size." So, we'll do that same thing here:

if (!in_array(strlen($new),array(16,24,32))) { die('Error: Invalid new key length: '.strlen($new)); }

if (strlen($old) > 24) {
	while (strlen($old) < 32) { 
		$old .= "\0";
} elseif (strlen($old) > 16) {
	while (strlen($old) < 24) { 
		$old .= "\0";
} else {
	while (strlen($old) < 16) { 
		$old .= "\0";

Before the next step, make a backup of your MySQL table. That should be obvious, but we'll say it anyway.

Now, we go through the data, decrypt it using the old key, and encrypt it using your new key:

$result = mysqli_query($link,'SELECT * FROM `'.$table.'` ORDER BY `'.$idcol.'`');
while ($row = mysqli_fetch_array($result,MYSQL_ASSOC)) {
	$updates = array();
	foreach ($cols as $col) {
		$value = $row[$col];
		if ($value) {

			//decrypt the old value
			$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
			$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
			$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $old, $value, MCRYPT_MODE_ECB, $iv);
			$decrypted = trim($decrypted);
			//display the decrypted value to be sure you're on the right track
			//warning: this displays your sensitive data, so only uncomment if you're working someplace secure
			//echo '<p>'.$col.': '.$decrypted.'</p>';

			$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
			$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
			$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $new, $decrypted, MCRYPT_MODE_ECB, $iv);

			$updates[] = '`'.$col.'`=\''.mysqli_real_escape_string($link,$encrypted).'\'';

	if (count($updates) > 0) {
		$query = 'UPDATE `'.$table.'` SET '.implode(',',$updates).' WHERE `'.$idcol.'`=\''.mysqli_real_escape_string($link,$row[$idcol]).'\'';
		echo '<p>'.$query;
		mysqli_query($link,$query); echo ' - '.mysqli_affected_rows($link).' rows affected';
		echo '</p>';

The last step is to update your PHP files to include your new key. After that, you should be all set.



This post was published on June 23rd, 2016 by Robert James Reese in PHP. Before using any of the code or other content in this post, you must read and agree to our terms of use.