加解密算法
这篇文章主要介绍加解密算法,以及在PHP中如何使用
按大类划分,加解密分为两大类:对称加密和非对称加密。
简单的区分就是,对称加密,加解密用的是同一套钥匙(公钥+私钥);非对称加密则有两套钥匙(公钥1+私钥1,公钥2+私钥2),一般情况下,公钥用来加密,私钥用来解密(假设A和B进行通讯,A拥有公钥1+私钥1,B拥有公钥2+私钥2,A向B发送消息,使用公钥2加密,B收到后使用私钥2解密,反过来,B向A发送消息,使用公钥1加密,A收到后使用私钥1解密)。
相关函数的使用可以参考官网的函数手册,其中会有对应的示例可用来参考。
对称加密
对称加密的常规算法有:DES,3DES,AES等,支持一些模式,如 ECB,CBC,CTR等。
PHP中的 OpenSSL扩展提供了现成的函数openssl_encrypt
和openssl_decrypt
针对对称加密,支持多种加密算法,包括国密 SM4,可通过openssl_get_cipher_methods
查看具体支持的算法。
非对称加密
非对称加密使用算法RSA
。
RSA
加解密中需要考虑秘钥长度,明文长度和密文长度的问题。
明文长度需要小于秘钥长度(1024位 => 128字节),而密文长度等于秘钥长度。
如果明文和密文的长度大于秘钥长度,则需要先分组,对每一组进行加解密然后拼接。需要分组就涉及到填充模式的选择,PHP
填充支持支持 OPENSSL_PKCS1_PADDING(11), OPENSSL_SSLV23_PADDING, OPENSSL_PKCS1_OAEP_PADDING(41),OPENSSL_NO_PADDING
,其中 OPENSSL_PKCS1_PADDING
填充值就占11个字节。对于一个秘钥长度 1024 bits(128字节)
来说,使用 OPENSSL_PKCS1_PADDING
填充模式,其明文最大长度就是 128 - 11 = 117 字节
。密文长度和秘钥长度相同,这里是 128
字节。
如果明文或者密文的长度超过,则需要分块加解密。
PHP中的使用范例
// 生成密钥资源id,此函数主要用来校验公私秘钥是否能够正常使用
$pi_key = openssl_pkey_get_private($private_key);
$pu_key = openssl_pkey_get_public($public_key);
// 私钥加密,除了这样使用之外,也可以直接原生的秘钥内容,不进行提取
$encrypted = ‘’;
openssl_private_encrypt($data, $encrypted, $pi_key);
// 转码,这里的$encrypted就是私钥加密的字符串
$encrypted = base64_encode($encrypted);
// 公钥解密,$decrypted即为公钥解密后私钥加密前的明文
$decrypted = ‘’;
$encrypted = base64_decode($encrypted);
openssl_public_decrypt($encrypted, $decrypted, $pu_key);
参考资料
PHP OpenSSL扩展 - 非对称加密
非对称加密-维基百科
非对称加密-CSDN
RSA加密长度限制问题
RSA密钥长度、明文长度和密文长度
哈希散列值
散列值计算是单向的,因为无法反向推导,一般用来进行各种校验。比如用户的登录秘钥,数据传输的签名。
算法一般是MD5
,SHA
。
实际的操作中一般会加“盐”来增加破解的难度,无法通过简单的撞库来探测。
实战中需要注意的要点
在实际操作过程中,困难点往往在于明文和密文的获取,通过接口拿到的数据并不能直接作为明文或者密文使用,往往需要经过多个步骤的处理。尤其是银行,中间的步骤会比较曲折和复杂。
一般情况下,拿到的数据需要经过 base64(base64_encode,base64_decode)
以及转换 16进制(bin2hex,hex2bin)
的处理,如果有其他要求,可能还需要转大小写和哈希处理。
比较可行的方式使用甲方提供的 demo
,逐行打印对比,这样的可操作性较强。按照我的经验,甲方的文档都是一些大的步骤,很多的小细节会忽略(比如,bin2hex
拿到的数据要先转大写,然后解密等等)。
一些参考的数值,针对分组加解密。
OPENSSL_PKCS1_PADDING
填充模式下,
明文长度 | 填充长度 | 总长度 | base64_encode | 转16进制(bin2hex) |
---|---|---|---|---|
117 | 11 | 128 | 172 | 256=128*2 |
总结
- 如果加密之后使用
base64_encode
处理密文,反过来切割分组时就是172
- 如果解密之后使用
bin2hex
处理密文,反过来切割分组时就是256
- 转16进制会让字符长度加倍,反过来就是减半,有的文档说加倍或者减半,潜台词就是转16进制处理
OPENSSL_PKCS1_OAEP_PADDING
填充模式下,
明文长度 | 填充长度 | 总长度 | base64_encode | 转16进制(bin2hex) |
---|---|---|---|---|
215 | 41 | 256 |
国密算法
国密算法主要涉及到4个,SM1,SM2,SM3,SM4
SM1 为对称加密。算法不公开,需要通过加密芯片来处理。
SM2 为非对称加密,基于 ECC。算法已公开,签名及秘钥生成速度都快于 RSA。
SM3 消息摘要,算法已公开。
SM4 无线局域网标准的分组数据算法。对称加密,秘钥长度和分组长度均为128位。
SM1,SM4 加解密的分组大小为128bit,对消息加解密时,若消息长度过长,需要进行分组,要消息长度不足,则要进行填充。
资料查找
这篇文章非常的粗略,属于概括性的介绍,实际使用中的细节部分并没有多少涉及,现网上有很多这样细节性的内容。
维基百科和博客园都是不错的信息查找源。
查找举例
搜索栏:加解密 site:cnblogs.com
工具
生成 RSA
使用的公私秘钥。
生成pem私钥,PKCS1格式,可设置不同的秘钥长度
openssl genrsa -out private.pem 1024
PKCS1私钥转换为PKCS8(该格式一般java使用)
openssl pkcs8 -topk8 -inform PEM -in private.pem -outform pem -nocrypt -out private.pem
生成pem公钥
openssl rsa -in private.pem -out public.pem -pubout
本作品采用《CC 协议》,转载必须注明作者和本文链接