PHP加解密算法使用openssl替换mcrypt扩展 【转载】

PHP版本从7.2开始不再支持mcrypt扩展,所以我们需要使用OpenSSl对其进行替换。本文仅列出部分算法的替换示例,所以不在本文出现的算法或模式需要自行尝试,顺水推舟。

本文替换案例:
MCRYPT_RIJNDAEL_128 | MCRYPT_MODE_ECB => AES-128-ECB
MCRYPT_DES | MCRYPT_MODE_CBC => DES-CBC
MCRYPT_RIJNDAEL_128 | MCRYPT_MODE_CBC => AES-128-CBC
MCRYPT_XTEA | MCRYPT_MODE_CBC
在使用 MCRYPT_RIJNDAEL_128 的地方,如果秘钥长度分别为16、24、32,则加密算法用 AES-128-ECB、AES-192-ECB、AES-256-ECB,BlockSize为16、24、32。

首先列出需要用到的数据填充方法:

function ZeroPadding($str, $block = 16) {
    $pad = $block - (strlen($str) % $block);
    if($pad == $block) return $str;
    return $str.str_repeat(chr(0),$pad);
}
function ZeroUnPadding($str) {
    return rtrim($str, "\0");
}
 
 
function PKCS7Padding($str, $block_size) {
    $padding_char = $block_size - (strlen($str) % $block_size);
    $padding_str = str_repeat(chr($padding_char),$padding_char);
    return $str.$padding_str;
}
function PKCS7UnPadding($str) {
    $char=substr($str,-1,1);
    $num=ord($char);
    if($num>0 && $num <= strlen($str)) {
        $str = substr($str, 0, -1 * $num);
    }
    return $str;
}

算法MCRYPT_RIJNDAEL_128 | MCRYPT_MODE_ECB 对应 AES-128-ECB

//使用mcrypt加密
$data = '1234567890123456';
$key = md5('1230456789', true);
$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_ECB);
$edata = base64_encode($encrypted);
return $edata;

//使用OpenSSL加密
$data = '1234567890123456';
$key = md5('1230456789', true);
 
$encrypted = openssl_encrypt(ZeroPadding($data, 16), 'AES-128-ECB', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
$edata = base64_encode($encrypted);
return $edata;

//使用OpenSSL解密
$key = md5('1230456789', true);

$data = openssl_decrypt(base64_decode($edata), 'AES-128-ECB', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
$data = ZeroUnPadding($data);
return $data;

算法MCRYPT_DES | MCRYPT_MODE_CBC 对应 DES-CBC

//使用mcrypt加密
$data = '1234567890123456';
$key = md5('1230456789', true);
$encrypted = mcrypt_encrypt(MCRYPT_DES, $key, $data, MCRYPT_MODE_CBC, $iv);
$edata = base64_encode($encrypted);
return $edata;

//使用OpenSSL加密:
$data = '1234567890123456';
$key = 'abcd1234';
$iv = 'mds2345&';
 
$encrypted = openssl_encrypt(ZeroPadding($data, 8), 'DES-CBC', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
$edata = base64_encode($encrypted);
return $edata;

//使用OpenSSL解密:
$key = 'abcd1234';
$iv = 'mds2345&';
 
$data = openssl_decrypt(base64_decode($edata), 'DES-CBC', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
$data = ZeroUnPadding($data);
return $data;

算法MCRYPT_RIJNDAEL_128 | MCRYPT_MODE_CBC 对应 AES-128-CBC

//使用mcrypt加密:
$data = '1234567890123456';
$key = md5('1230456789', true);
$size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($size, MCRYPT_DEV_RANDOM);   //生成随机向量

//对内容进行PKCS7填充
$block_size = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$padding_char = $block_size - (count($str) % $block_size);
$padding_str = '';
if($padding_char<=$block_size) {
    $padding_str = str_repeat(chr($padding_char),$padding_char);
}
$str = $str.$padding_str;
 
$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $str, MCRYPT_MODE_CBC, $iv);
$edata = base64_encode($encrypted);
return $edata;

//使用OpenSSL加密:
$data = '1234567890123456';
$key = md5('1230456789', true);
 
 
$ivlen = openssl_cipher_iv_length('AES-128-CBC');
$iv = openssl_random_pseudo_bytes($ivlen);
$str = PKCS7Padding($data, 16);
 
$encrypted = openssl_encrypt($str, 'AES-128-CBC', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
$edata = base64_encode($encrypted);
return $edata;

//使用OpenSSL解密:
$key = md5('1230456789', true);
//$iv用加密时生成的同一个iv
$data = openssl_decrypt(base64_decode($edata), 'AES-128-CBC', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
$data = PKCS7UnPadding($data);
return $data;

算法MCRYPT_XTEA | MCRYPT_MODE_CBC 需要使用第三方类的修改版本

<?php
// Origin: https://github.com/jungepiraten/nntpboard/blob/master/libs/xtea.class.php
// Modified By imsry.cn
class Xtea
{

    //Private
    var $key;

    // CBC or ECB Mode
    // normaly, CBC Mode would be the right choice
    var $cbc = 1;
    var $iv = null;

//    function Xtea($key)
//    {
//        $this->key_setup($key);
//    }

    function iv_setup($iv){
        $this->iv = $this->_str2long($iv);
    }

    //Verschluesseln
    function encrypt($text)
    {
        $n = strlen($text);
        if ($n % 8 != 0) $lng = ($n + (8 - ($n % 8)));
        else $lng = 0;

        $text = str_pad($text, $lng, "\0");
        $text = $this->_str2long($text);
        $cipher = array();

        //Initialization vector: IV
        if ($this->cbc == 1) {
            if($this->iv === null){
                $cipher[0][0] = time();
                $cipher[0][1] = (double)microtime() * 1000000;
            }else{
                $cipher[0][0] = $this->iv[0];
                $cipher[0][1] = $this->iv[1];
            }
        }

        $a = 1;
        for ($i = 0; $i < count($text); $i += 2) {
            if ($this->cbc == 1) {
                //$text mit letztem Geheimtext XOR Verknuepfen
                //$text is XORed with the previous ciphertext
                $text[$i] ^= $cipher[$a - 1][0];
                $text[$i + 1] ^= $cipher[$a - 1][1];
            }

            $cipher[] = $this->block_encrypt($text[$i], $text[$i + 1]);
            $a++;
        }

        $output = "";
        for ($i = ($this->iv === null?0:1); $i < count($cipher); $i++) {
            $output .= $this->_long2str($cipher[$i][0]);
            $output .= $this->_long2str($cipher[$i][1]);
        }

        return base64_encode($output);
    }


    //Entschluesseln
    function decrypt($text)
    {
        $plain = array();
        $cipher = $this->_str2long(base64_decode($text));
        if($this->iv !== null) {
            $cipher = array_merge($this->iv,$cipher);
        }

        if ($this->cbc == 1)
            $i = 2; //Message start at second block
        else
            $i = 0; //Message start at first block

        for ($i; $i < count($cipher); $i += 2) {
            $return = $this->block_decrypt($cipher[$i], $cipher[$i + 1]);

            //Xor Verknuepfung von $return und Geheimtext aus von den letzten beiden Bloecken
            //XORed $return with the previous ciphertext
            if ($this->cbc == 1)
                $plain[] = array($return[0] ^ $cipher[$i - 2], $return[1] ^ $cipher[$i - 1]);
            else          //EBC Mode
                $plain[] = $return;
        }
        $output = "";
        for ($i = 0; $i < count($plain); $i++) {
            $output .= $this->_long2str($plain[$i][0]);
            $output .= $this->_long2str($plain[$i][1]);
        }

        return $output;
    }

    //Bereitet den Key zum ver/entschluesseln vor
    function key_setup($key)
    {
        if (is_array($key))
            $this->key = $key;
        else if (isset($key) && !empty($key))
            $this->key = $this->_str2long(str_pad($key, 16, $key));
        else
            $this->key = array(0, 0, 0, 0);
    }


    //Performs a benchmark
    function benchmark($length = 1000)
    {
        //1000 Byte String
        $string = str_pad("", $length, "text");


        //Key-Setup
        $start1 = time() + (double)microtime();
        $xtea = new Xtea();
        $xtea->key_setup('key');
        $end1 = time() + (double)microtime();

        //Encryption
        $start2 = time() + (double)microtime();
        $xtea->Encrypt($string);
        $end2 = time() + (double)microtime();


        echo "Encrypting " . $length . " bytes: " . round($end2 - $start2, 2) . " seconds (" . round($length / ($end2 - $start2), 2) . " bytes/second)<br>";


    }

    //verify the correct implementation of the blowfish algorithm
    function check_implementation()
    {

        $xtea = new Xtea();
        $xtea->key_setup('key');
        $vectors = array(
            array(array(0x00000000, 0x00000000, 0x00000000, 0x00000000), array(0x41414141, 0x41414141), array(0xed23375a, 0x821a8c2d)),
            array(array(0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f), array(0x41424344, 0x45464748), array(0x497df3d0, 0x72612cb5)),

        );

        //Correct implementation?
        //Test vectors, see http://www.schneier.com/code/vectors.txt
        foreach ($vectors AS $vector) {
            $key = $vector[0];
            $plain = $vector[1];
            $cipher = $vector[2];

            $xtea->key_setup($key);
            $return = $xtea->block_encrypt($vector[1][0], $vector[1][1]);

            if ((int)$return[0] != (int)$cipher[0] || (int)$return[1] != (int)$cipher[1])
                return false;
        }
        return true;
    }


    /***********************************
     * Some internal functions
     ***********************************/
    function block_encrypt($y, $z)
    {
        $sum = 0;
        $delta = 0x9e3779b9;


        /* start cycle */
        for ($i = 0; $i < 32; $i++) {
            $y = $this->_add($y,
                $this->_add($z << 4 ^ $this->_rshift($z, 5), $z) ^
                $this->_add($sum, $this->key[$sum & 3]));

            $sum = $this->_add($sum, $delta);

            $z = $this->_add($z,
                $this->_add($y << 4 ^ $this->_rshift($y, 5), $y) ^
                $this->_add($sum, $this->key[$this->_rshift($sum, 11) & 3]));

        }

        /* end cycle */
        $v[0] = $y;
        $v[1] = $z;

        return array($y, $z);

    }

    function block_decrypt($y, $z)
    {
        $delta = 0x9e3779b9;
        $sum = 0xC6EF3720;
        $n = 32;

        /* start cycle */
        for ($i = 0; $i < 32; $i++) {
            $z = $this->_add($z,
                -($this->_add($y << 4 ^ $this->_rshift($y, 5), $y) ^
                    $this->_add($sum, $this->key[$this->_rshift($sum, 11) & 3])));
            $sum = $this->_add($sum, -$delta);
            $y = $this->_add($y,
                -($this->_add($z << 4 ^ $this->_rshift($z, 5), $z) ^
                    $this->_add($sum, $this->key[$sum & 3])));

        }
        /* end cycle */

        return array($y, $z);
    }


    function _rshift($integer, $n)
    {
        // convert to 32 bits
        if (0xffffffff < $integer || -0xffffffff > $integer) {
            $integer = fmod($integer, 0xffffffff + 1);
        }

        // convert to unsigned integer
        if (0x7fffffff < $integer) {
            $integer -= 0xffffffff + 1.0;
        } elseif (-0x80000000 > $integer) {
            $integer += 0xffffffff + 1.0;
        }

        // do right shift
        if (0 > $integer) {
            $integer &= 0x7fffffff;                     // remove sign bit before shift
            $integer >>= $n;                            // right shift
            $integer |= 1 << (31 - $n);                 // set shifted sign bit
        } else {
            $integer >>= $n;                            // use normal right shift
        }

        return $integer;
    }


    function _add($i1, $i2)
    {
        $result = 0.0;

        foreach (func_get_args() as $value) {
            // remove sign if necessary
            if (0.0 > $value) {
                $value -= 1.0 + 0xffffffff;
            }

            $result += $value;
        }

        // convert to 32 bits
        if (0xffffffff < $result || -0xffffffff > $result) {
            $result = fmod($result, 0xffffffff + 1);
        }

        // convert to signed integer
        if (0x7fffffff < $result) {
            $result -= 0xffffffff + 1.0;
        } elseif (-0x80000000 > $result) {
            $result += 0xffffffff + 1.0;
        }

        return $result;
    }


    //Einen Text in Longzahlen umwandeln
    //Covert a string into longinteger
    function _str2long($data)
    {
        $n = strlen($data);
        $tmp = unpack('N*', $data);
        $data_long = array();
        $j = 0;

        foreach ($tmp as $value) $data_long[$j++] = $value;
        return $data_long;
    }

    //Longzahlen in Text umwandeln
    //Convert a longinteger into a string
    function _long2str($l)
    {
        return pack('N', $l);
    }

}
//使用mcrypt加密:
$data = '1234567890123456';
$key = md5('1230456789', true);
$iv = '\0\0\0\0';
 
$encrypted = mcrypt_encrypt(MCRYPT_XTEA, $key, $data, MCRYPT_MODE_CBC, $iv);
$edata = base64_encode($encrypted);
return $edata;

//使用Xtea加密:
$data = '1234567890123456';
$key = md5('1230456789', true);
$iv = '\0\0\0\0';
 
$x = new Xtea();
$x->key_setup($key);
$x->iv_setup($iv);
$edata = $x->encrypt($data);
return $edata;

//使用Xtea解密:
$key = md5('1230456789', true);
$iv = '\0\0\0\0';
 
$x = new Xtea();
$x->key_setup($key);
$x->iv_setup($iv);
$data = $x->decrypt($edata);
return $data;

算法名称、IV、BlockSize、key参照表

摘抄自:https://github.com/mfpierre/go-mcrypt

Cipher NameBlock ModeBlock SizeIV SizeDefault Key SizeAll Key Size(s)
CAST-128CBC881616
CAST-128ECB881616
CAST-128OFB881616
CAST-128NOFB881616
CAST-128CFB881616
CAST-128NCFB881616
CAST-128CTR881616
GOSTCBC883232
GOSTECB883232
GOSTOFB883232
GOSTNOFB883232
GOSTCFB883232
GOSTNCFB883232
GOSTCTR883232
Rijndael-128CBC16163216 24 32
Rijndael-128ECB16163216 24 32
Rijndael-128OFB16163216 24 32
Rijndael-128NOFB16163216 24 32
Rijndael-128CFB16163216 24 32
Rijndael-128NCFB16163216 24 32
Rijndael-128CTR16163216 24 32
TwofishCBC16163216 24 32
TwofishECB16163216 24 32
TwofishOFB16163216 24 32
TwofishNOFB16163216 24 32
TwofishCFB16163216 24 32
TwofishNCFB16163216 24 32
TwofishCTR16163216 24 32
RC4STREAM10256
CAST-256CBC16163216 24 32
CAST-256ECB16163216 24 32
CAST-256OFB16163216 24 32
CAST-256NOFB16163216 24 32
CAST-256CFB16163216 24 32
CAST-256NCFB16163216 24 32
CAST-256CTR16163216 24 32
LOKI97CBC16163216 24 32
LOKI97ECB16163216 24 32
LOKI97OFB16163216 24 32
LOKI97NOFB16163216 24 32
LOKI97CFB16163216 24 32
LOKI97NCFB16163216 24 32
LOKI97CTR16163216 24 32
Rijndael-192CBC24243216 24 32
Rijndael-192ECB24243216 24 32
Rijndael-192OFB24243216 24 32
Rijndael-192NOFB24243216 24 32
Rijndael-192CFB24243216 24 32
Rijndael-192NCFB24243216 24 32
Rijndael-192CTR24243216 24 32
Safer+CBC16163216 24 32
Safer+ECB16163216 24 32
Safer+OFB16163216 24 32
Safer+NOFB16163216 24 32
Safer+CFB16163216 24 32
Safer+NCFB16163216 24 32
Safer+CTR16163216 24 32
WAKESTREAM103232
BlowfishCBC8856
BlowfishECB8856
BlowfishOFB8856
BlowfishNOFB8856
BlowfishCFB8856
BlowfishNCFB8856
BlowfishCTR8856
DESCBC8888
DESECB8888
DESOFB8888
DESNOFB8888
DESCFB8888
DESNCFB8888
DESCTR8888
Rijndael-256CBC32323216 24 32
Rijndael-256ECB32323216 24 32
Rijndael-256OFB32323216 24 32
Rijndael-256NOFB32323216 24 32
Rijndael-256CFB32323216 24 32
Rijndael-256NCFB32323216 24 32
Rijndael-256CTR32323216 24 32
SerpentCBC16163216 24 32
SerpentECB16163216 24 32
SerpentOFB16163216 24 32
SerpentNOFB16163216 24 32
SerpentCFB16163216 24 32
SerpentNCFB16163216 24 32
SerpentCTR16163216 24 32
xTEACBC881616
xTEAECB881616
xTEAOFB881616
xTEANOFB881616
xTEACFB881616
xTEANCFB881616
xTEACTR881616
BlowfishCBC8856
BlowfishECB8856
BlowfishOFB8856
BlowfishNOFB8856
BlowfishCFB8856
BlowfishNCFB8856
BlowfishCTR8856
enigmaSTREAM1013
RC2CBC88128
RC2ECB88128
RC2OFB88128
RC2NOFB88128
RC2CFB88128
RC2NCFB88128
RC2CTR88128
3DESCBC882424
3DESECB882424
3DESOFB882424
3DESNOFB882424
3DESCFB882424
3DESNCFB882424
3DESCTR882424

文章出处:https://www.imsry.cn/posts/5c3bf0b6.html

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值