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

本文替换案例:

  1. MCRYPT_RIJNDAEL_128 | MCRYPT_MODE_ECB => AES-128-ECB
  2. MCRYPT_DES | MCRYPT_MODE_CBC => DES-CBC
  3. MCRYPT_RIJNDAEL_128 | MCRYPT_MODE_CBC => AES-128-CBC
  4. MCRYPT_XTEA | MCRYPT_MODE_CBC

在使用 MCRYPT_RIJNDAEL_128 的地方,如果秘钥长度分别为16、24、32,则加密算法用 AES-128-ECB、AES-192-ECB、AES-256-ECB,BlockSize为16、24、32。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//使用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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//使用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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//使用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 需要使用第三方类的修改版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
<?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);
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//使用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 Name Block Mode Block Size IV Size Default Key Size All Key Size(s)
CAST-128 CBC 8 8 16 16
CAST-128 ECB 8 8 16 16
CAST-128 OFB 8 8 16 16
CAST-128 NOFB 8 8 16 16
CAST-128 CFB 8 8 16 16
CAST-128 NCFB 8 8 16 16
CAST-128 CTR 8 8 16 16
GOST CBC 8 8 32 32
GOST ECB 8 8 32 32
GOST OFB 8 8 32 32
GOST NOFB 8 8 32 32
GOST CFB 8 8 32 32
GOST NCFB 8 8 32 32
GOST CTR 8 8 32 32
Rijndael-128 CBC 16 16 32 16 24 32
Rijndael-128 ECB 16 16 32 16 24 32
Rijndael-128 OFB 16 16 32 16 24 32
Rijndael-128 NOFB 16 16 32 16 24 32
Rijndael-128 CFB 16 16 32 16 24 32
Rijndael-128 NCFB 16 16 32 16 24 32
Rijndael-128 CTR 16 16 32 16 24 32
Twofish CBC 16 16 32 16 24 32
Twofish ECB 16 16 32 16 24 32
Twofish OFB 16 16 32 16 24 32
Twofish NOFB 16 16 32 16 24 32
Twofish CFB 16 16 32 16 24 32
Twofish NCFB 16 16 32 16 24 32
Twofish CTR 16 16 32 16 24 32
RC4 STREAM 1 0 256
CAST-256 CBC 16 16 32 16 24 32
CAST-256 ECB 16 16 32 16 24 32
CAST-256 OFB 16 16 32 16 24 32
CAST-256 NOFB 16 16 32 16 24 32
CAST-256 CFB 16 16 32 16 24 32
CAST-256 NCFB 16 16 32 16 24 32
CAST-256 CTR 16 16 32 16 24 32
LOKI97 CBC 16 16 32 16 24 32
LOKI97 ECB 16 16 32 16 24 32
LOKI97 OFB 16 16 32 16 24 32
LOKI97 NOFB 16 16 32 16 24 32
LOKI97 CFB 16 16 32 16 24 32
LOKI97 NCFB 16 16 32 16 24 32
LOKI97 CTR 16 16 32 16 24 32
Rijndael-192 CBC 24 24 32 16 24 32
Rijndael-192 ECB 24 24 32 16 24 32
Rijndael-192 OFB 24 24 32 16 24 32
Rijndael-192 NOFB 24 24 32 16 24 32
Rijndael-192 CFB 24 24 32 16 24 32
Rijndael-192 NCFB 24 24 32 16 24 32
Rijndael-192 CTR 24 24 32 16 24 32
Safer+ CBC 16 16 32 16 24 32
Safer+ ECB 16 16 32 16 24 32
Safer+ OFB 16 16 32 16 24 32
Safer+ NOFB 16 16 32 16 24 32
Safer+ CFB 16 16 32 16 24 32
Safer+ NCFB 16 16 32 16 24 32
Safer+ CTR 16 16 32 16 24 32
WAKE STREAM 1 0 32 32
Blowfish CBC 8 8 56
Blowfish ECB 8 8 56
Blowfish OFB 8 8 56
Blowfish NOFB 8 8 56
Blowfish CFB 8 8 56
Blowfish NCFB 8 8 56
Blowfish CTR 8 8 56
DES CBC 8 8 8 8
DES ECB 8 8 8 8
DES OFB 8 8 8 8
DES NOFB 8 8 8 8
DES CFB 8 8 8 8
DES NCFB 8 8 8 8
DES CTR 8 8 8 8
Rijndael-256 CBC 32 32 32 16 24 32
Rijndael-256 ECB 32 32 32 16 24 32
Rijndael-256 OFB 32 32 32 16 24 32
Rijndael-256 NOFB 32 32 32 16 24 32
Rijndael-256 CFB 32 32 32 16 24 32
Rijndael-256 NCFB 32 32 32 16 24 32
Rijndael-256 CTR 32 32 32 16 24 32
Serpent CBC 16 16 32 16 24 32
Serpent ECB 16 16 32 16 24 32
Serpent OFB 16 16 32 16 24 32
Serpent NOFB 16 16 32 16 24 32
Serpent CFB 16 16 32 16 24 32
Serpent NCFB 16 16 32 16 24 32
Serpent CTR 16 16 32 16 24 32
xTEA CBC 8 8 16 16
xTEA ECB 8 8 16 16
xTEA OFB 8 8 16 16
xTEA NOFB 8 8 16 16
xTEA CFB 8 8 16 16
xTEA NCFB 8 8 16 16
xTEA CTR 8 8 16 16
Blowfish CBC 8 8 56
Blowfish ECB 8 8 56
Blowfish OFB 8 8 56
Blowfish NOFB 8 8 56
Blowfish CFB 8 8 56
Blowfish NCFB 8 8 56
Blowfish CTR 8 8 56
enigma STREAM 1 0 13
RC2 CBC 8 8 128
RC2 ECB 8 8 128
RC2 OFB 8 8 128
RC2 NOFB 8 8 128
RC2 CFB 8 8 128
RC2 NCFB 8 8 128
RC2 CTR 8 8 128
3DES CBC 8 8 24 24
3DES ECB 8 8 24 24
3DES OFB 8 8 24 24
3DES NOFB 8 8 24 24
3DES CFB 8 8 24 24
3DES NCFB 8 8 24 24
3DES CTR 8 8 24 24