最近在对接客户的CRM系统,获取令牌时,要用DES方式加密解密,由于之前没有搞错这种加密方式,经过请教了“百度”和“谷歌”两个老师后,结合了多篇文档内容后,终于实现了。
一、DES介绍
DES 是对称性加密里面常见一种,全称为 Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法。密钥长度是64位(bit),超过位数密钥被忽略。所谓对称性加密即加密和解密密钥相同,对称性加密一般会按照固定长度,把待加密字符串分成块,不足一整块或者刚好最后有特殊填充字符。
- 跨语言做 DES 加密解密经常会出现问题,往往是填充方式不对、编码不一致或者加密解密模式没有对应上造成。
- 常见的填充模式有: pkcs5、pkcs7、iso10126、ansix923、zero。
- 加密模式有:DES-ECB、DES-CBC、DES-CTR、DES-OFB、DES-CFB。
加密用到的方法:
openssl_encrypt($data, $method, $password, $options, $iv)
参数说明:
- $data 加密明文
-
$method 加密方法
- DES-ECB
- DES-CBC
- DES-CTR
- DES-OFB
- DES-CFB
- $passwd 加密密钥[密码]
-
$options 数据格式选项(可选)【选项有:】
- 0
- OPENSSL_RAW_DATA=1
- OPENSSL_ZERO_PADDING=2
- OPENSSL_NO_PADDING=3
- $iv 密初始化向量(可选)
需要注意:如果$method为DES-ECB,则$iv无需填写
二、解密用到的方法:
openssl_decrypt($data, $method, $password, $options, $iv)
参数说明:
- $data 要解密的数据
- 其他参数同加密方法
三、用法案例:
参数:
$data = '1234567887654321';//加密明文
$method = 'DES-ECB';//加密方法
$passwd = '12344321';//加密密钥
$options = 0;//数据格式选项(可选)
$iv = '';//加密初始化向量(可选)
(1) 默认填充方式:
-
加密:
$result = openssl_encrypt($data, $method, $passwd, $options); var_dump($result);
结果:
string(32) "kQYOdswcm9I5elv2wdJucplqAgqDNqXg"
-
解密
$result = 'kQYOdswcm9I5elv2wdJucplqAgqDNqXg'; var_dump(openssl_decrypt($result, $method, $passwd, 0));
结果:
string(16) "1234567887654321"
(2) OPENSSL_RAW_DATA方式【会用PKCS#7进行补位】
-
加密
$result = openssl_encrypt($data, $method, $passwd, OPENSSL_RAW_DATA); var_dump($result);
结果:
string(24) "�v���9z[���nr�j �6��"
我们可以看到结果是乱码的,这时我们需要base64一下
$result = openssl_encrypt($data, $method, $passwd, OPENSSL_RAW_DATA); var_dump(base64_encode($result));
这时结果是
string(32) "kQYOdswcm9I5elv2wdJucplqAgqDNqXg"
-
解密
result = openssl_encrypt($data, $method, $passwd, OPENSSL_RAW_DATA); var_dump(openssl_decrypt($result, $method, $passwd,OPENSSL_RAW_DATA));
结果:
string(16) "1234567887654321"
我们可以看到:默认填充方式与OPENSSL_RAW_DATA,这两种方式加密结果是一样的
(3) OPENSSL_ZERO_PADDING方式
看字面意思,是用0填充,但是测试并不起作用
-
加密
$result = openssl_encrypt($data, $method, $passwd, OPENSSL_ZERO_PADDING); var_dump($result);
结果:
string(24) "kQYOdswcm9I5elv2wdJucg=="
-
解密:
$result = openssl_encrypt($data, $method, $passwd, OPENSSL_ZERO_PADDING); var_dump(openssl_decrypt($result, $method, $passwd,OPENSSL_ZERO_PADDING));
结果:
string(16) "1234567887654321"
(4) OPENSSL_NO_PADDING【不填充,需要手动填充】
- 在openssl_encrypt前加上填充过程
-
加密
$str_padded = $data; if (strlen($str_padded) % 16) { $str_padded = str_pad($str_padded,strlen($str_padded) + 16 - strlen($str_padded) % 16, "\0"); } $result = openssl_encrypt($str_padded, $method, $passwd, OPENSSL_NO_PADDING); var_dump($result); echo '<br>'; var_dump( base64_encode($result));
结果:
string(16) "�v���9z[���nr" string(24) "kQYOdswcm9I5elv2wdJucg=="
我们可以看到结果是加密的乱码,需要用base64一下,就可以看到结果了
-
解密:
//加密begin $str_padded = $data; if (strlen($str_padded) % 16) { $str_padded = str_pad($str_padded,strlen($str_padded) + 16 - strlen($str_padded) % 16, "\0"); } $result = openssl_encrypt($str_padded, $method, $passwd, OPENSSL_NO_PADDING); //加密end //解密begin $str = base64_encode($result); $m = openssl_decrypt( base64_decode($str) , $method, $passwd, OPENSSL_NO_PADDING); var_dump( rtrim( rtrim( $m,chr(0) ), chr(7) ) ); //解密 end
结果:
string(16) "1234567887654321"
** 结尾要去除填充字符’0’和’a’。
‘a’是为了兼容用OPENSSL_RAW_DATA加密的结果。 **
参照的文档有:
- PHP 基础篇 - PHP 中 DES 加解密详解
https://www.jianshu.com/p/546... - 关于mcrypt_encrypt和openssl_encrypt加密结果不一致的解决
http://www.heylc.com/fuanyuop...
相关知识文章
- RSA密码传输加密方案
https://wenku.baidu.com/view/... - iOS 实现对称加密多种填充方式(ANSIX923、ISO10126、Zero)
https://www.jianshu.com/p/7b6... - PHP由mcrypt扩展加密改为openssl扩展加密
https://www.xxling.com/blog/a... - PHP用openssl_encrypt代替mcrypt_encrypt
https://coderlife.cn/1624.html - AES加密CBC模式兼容互通四种编程语言平台【PHP、Javascript、Java、C#】
https://my.oschina.net/Jacker... - 在PHP7.1中使用openssl取代mcrypt
https://swoole.app/2018/05/15... - PHP openssl加密扩展使用总结
https://www.bbsmax.com/A/ke5j... - PHP 7.2+使用openssl进行加解密
https://www.lytit.com/2018/01... - PHP OpenSSL扩展 - 对称加密
https://www.jianshu.com/p/8f8... - DES 加解密工具
http://tool.chacuo.net/cryptdes - RSA填充方式
https://www.jianshu.com/p/205... - AES加密模式和填充方式,hash,md5,ca
http://blog.sina.com.cn/s/blo...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。