PHP 实现 3Des ECB 加密算法
这两天对接第三方,对方有个 token 使用的是 3Des ECB 加密算法,并且非常贴心的提供了一段 Java 实现的 demo,具体如下:
Java 版本
public static String Des3EncodeECB(String originData, String SECRET) throws Exception {
DESedeKeySpec dks = new DESedeKeySpec(SECRET.getBytes("UTF-8"));
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
SecretKey securekey = keyFactory.generateSecret(dks);
Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, securekey);
byte[] b = cipher.doFinal(originData.getBytes("UTF-8"));
return new String(Base64.encodeBase64(b), "UTF-8").replaceAll("\r", "").replaceAll("\n", "");
}
public static void main(String[] args) throws Exception {
System.out.println(Des3EncodeECB("1234", "RV3n1wsaREGRm4G1F5AFZpEG")); // 结果:82YoIgPcgTs=
}
殊不知我们使用的是世界上最好的语言。询问对方有无 PHP 版本时,告知没有。
那就只能自己实现了(当然是搜索引擎)。
最后花了小半天,解决了问题,将结果记录如下。
PHP5 版本
class TripleDesEcb{
/**加密
* @param $text string 文本内容
* @param $key string 秘钥 max 24
* @return string
*/
public function encrypt($text,$key)
{
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_TRIPLEDES,MCRYPT_MODE_ECB), MCRYPT_RAND);
$text = $this->pkcs5Pad($text);
$td = mcrypt_module_open(MCRYPT_3DES,'',MCRYPT_MODE_ECB,'');
mcrypt_generic_init($td,$key,$iv);
$data = base64_encode(mcrypt_generic($td, $text));
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
print_r($data);
return $data;
}
/**解密
* @param $text
* @param $key
*/
public function decrypt($text,$key)
{
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_TRIPLEDES,MCRYPT_MODE_ECB), MCRYPT_RAND);
$td = mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_ECB, '');
mcrypt_generic_init($td, $key, $iv);
$data = $this->pkcs5UnPad(mdecrypt_generic($td, base64_decode($text)));
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
print_r($data);
}
/**
* @param $text
* @return string
*/
private function pkcs5Pad($text)
{
$pad = 8 - (strlen($text) % 8);
return $text . str_repeat(chr($pad), $pad);
}
/**
* @param $text
* @return bool|string
*/
private function pkcs5UnPad($text)
{
$pad = ord($text{strlen($text)-1});
if ($pad > strlen($text)) return false;
if (strspn($text, chr($pad), strlen($text) - $pad) != $pad) return false;
return substr($text, 0, -1 * $pad);
}
}
$a = new TripleDesEcb();
$key = 'RV3n1wsaREGRm4G1F5AFZpEG';
$r = $a->encrypt('1234',$key); // 结果:82YoIgPcgTs=
echo "----";
$a->decrypt($r,$key);
目前线上环境跑的是 5.6 的 PHP,但是有计划升级到 7.X 版本,而 mcrypt_ 系列函数在 7.1 版本废弃掉了,我们自然是不能使用该版了。
PHP7 版本(兼容 PHP5.3+)
class TripleDES{
public static function encrypt($str,$key){
$str = self::pkcs5_pad($str, 8);
if (strlen($str) % 8) {
$str = str_pad($str, strlen($str) + 8 - strlen($str) % 8, "\0");
}
$sign = openssl_encrypt($str, 'DES-EDE3', $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING, '');
return base64_encode($sign);
}
private static function pkcs5_pad($text, $blocksize) {
$pad = $blocksize - (strlen($text) % $blocksize);
return $text . str_repeat(chr($pad), $pad);
}
}
echo TripleDES::encrypt('34234324', 'RV3n1wsaREGRm4G1F5AFZpEG'); // 结果:82YoIgPcgTs=
Java 版本、PHP5 版本、PHP7 版本最终结果一致。