前段时间对接了某行支付,一个接口前前后后共有三次数据加解密,证书格式还必须按照银行已有系统规范生成,感慨银行系统还是安全呀。对接过程还算顺利,因为本身自己在对接之前就认真了了解了加密这块,对接完成之后又重新整理了这方面的知识点,方便日后回顾。
文章目录
以下各种加密算法、证书使用demo:https://gitee.com/izhangwu_123/those-certificerts.git
1.加密算法
对于搞编程的人来说,对加密肯定再熟悉不过了。弄懂各种加密算法的特点以及使用加密算法是每个程序猿必须具备的技能。读者有兴趣的话也可以深入了解加密算法底层的原理。
常见常用的安全领域下的加密算法有三种:
- 哈希算法
- 对称加密算法
- 非对称加密算法
哈希算法
哈希算法是单向算法,不可逆。
哈希算法主要的的特点有:
- 能将任意长度的输入变换成固定长度的输出
- 相同的输入一定得到相同的输出
- 不同的输入大概率得到不同的输出
上述特点意味着两个不同的输入有一定可能会得到相同的输出,这就是哈希碰撞。哈希碰撞是一定有可能出现的,只是概率会非常非常小。因为输出的长度固定,输入的可以是任意长度,无限的输入对应有限的输出,必然会产生哈希碰撞。
常见的哈希算法有:
- MD5
- SHA-1、SHA-256、SHA-512
哈希算法 | 输出长度 |
---|---|
MD5 | 16字节 |
SHA-1 | 20字节 |
SHA-256 | 32字节 |
SHA-512 | 64字节 |
哈希算法常见应用场景:
- 用户敏感信息加密。为了防止用户重要信息泄露,通常会将用户敏感信息(例如用户登录密码)经过哈希加密后,再进行数据库持久化存储。
- 判断下载文件是否被篡改、是否完整。在 OTA(远程固件升级)的时候,为了防止文件被篡改或者不完整,会将文件进行哈希加密计算得到的值与正确值进行比对,如果相同则说明文件完整。
对称加密算法
对称加密算法可逆。在对称加密过程中,将原始数据分割成固定大小的块,经过秘钥和加密算法逐个加密后,发送给接收方。接收方收到密文后,使用同一个秘钥将密文解密成铭文读取。
对称加密算法有以下几个特点:
- 加密和解密必须使用相同的秘钥
- 加密解密速度比较快,加密效率高,数据量比较大时也适合使用
常见常用的对称加密算法有:
算法 | 秘钥长度(位) | 备注 |
---|---|---|
DES | 56/64 | 已破解,不在安全 |
3DES | 112/168/128/192 | 计算秘钥时间太长,加密效率不高,基本上也不用 |
AES | 128/192/256 | 最常用的对称加密算法 |
IDEA | 128 | 常用的电子邮件加密算法 |
对称加密算法中还有两个关键的名词:
- 工作模式。常用的工作模式有:ECB、CBC、CFB、OFB
- 填充方式Padding。常见的填充方式有:NoPadding、PKCS5Padding和PKCS7Padding
非对称加密算法
非对称加密算法是日常工作中使用频率最高的加密算法。非对称加密算法有一个密钥对:公钥和私钥。非对称加密算法中加解密使用的是不同的秘钥。用公钥加密必须得用私钥解密。
也有一种场景是用私钥加密,公钥解密。私钥是保密的,公钥是公开的,用私钥加密相当于所有人都可以解密。它的意义在于让其他人确定消息是由私钥持有者发出的。用私钥加密的过程也称为签名,这一点在后面讲https原理的时候会详细介绍。
常用的非对称算法有:
- RSA
- DSA
- ECDSA
RSA是目前应用最广泛的非对称秘钥加密算法。国内的支付宝就是通过RSA算法来进行签名验证。秘钥的长度决定着它的安全强度。目前主流可选秘钥长度为1024、2048和4096位。支付宝的官方文档上推荐的是2048位,虽然秘钥更长更安全,但是也意味着会产生更大的性能开销。
编码算法
编码算法中主要有 URL 编码和 Base64 编码。
URL编码
URL编码是浏览器发送数据给服务器时使用的编码,它通常附加在URL的参数部分。例如:
http://www.ijuvenile.com?name= %E5%BC%A0%E6%AD%A6
URL编码规则
如果字符在ASCII码中存在,则保持不变
如果是其他字符,先转化成UTF-8编码,然后对每个字节以%xx表示,xx表示16进制Hex值
Base64编码
Base64编码是对二进制数据进行编码,表示成文本格式。
Base64编码可以把任意长度的二进制数据变为纯文本,且编码后的数据只包含A-Z、a-z、0-9、+、/、=这些字符。它的原理是把3字节的二进制数据按6bit一组,用4个int整数表示,然后查表,把int整数用索引对应到字符,得到编码后的字符串。
6bit可以表示的范围是0-63。上述的查表就是将0-63这些整数数字和A-Z、a-z、0-9、+、/、=这些字符意义对应。字符A-Z对应索引0-25,字符a-z对应索引26-51,字符0-9对应索引52-61,最后两个索引62、63分别用字符+和/表示。
这样子会存在一个问题,当字节数不是3的倍数的时候,最后余下的字节数怎么办?答案是最后补上一个或者两个0x00。编码后,在结尾加一个 = 表示补充了1个0x00,加两个 = 表示补充了2个0x00,解码的时候,去掉末尾补充的一个或两个0x00即可。
2.那些证书
实际开发过程中,我们会遇到不同扩展名的文件,例如pem、der、cer、csr、pfx、p12、key 等等。
讲这些不同扩展名文件的特点和区别之前,先说说另外一个词——约定大于配置。例如pem扩展名结尾的文件通常表示该文件是一个PEM编码的证书,der扩展名结尾的证书通常表示该文件是一个DER编码的证书。将一个DER编码的证书扩展名改为pem也没错,只是不规范。命名不规范,程序猿两行泪。
上面提到了PEM编码和DER编码,它们是两种不同的编码格式:
- PEM编码。纯文本文件,以—BEGIN XXX—开头,—END XXX—结尾,内容为Base64编码格式
- DER编码。二进制文件格式,用电脑中记事本打开会是一堆乱码,不可读
X.509是一种证书标准,主要定义了证书中应该包含哪些内容。我们熟悉的SSL证书就是遵循着这种证书标准。
X.509证书标准定义的两种编码格式为PEM编码和DER编码,这两种编码方式可以使用openssl相互转换。
无论扩展名如何,只要是符合X.509标准的证书,其内部编码格式只能是PEM和DER这两种编码格式中的一种。
再来谈谈这些不同扩展名文件的特点和区别:
-
pem、der、crt、cer。证书文件,证书格式PEM和DER编码都有可能。通常情况下 pem 和 cer 用 PEM 编码,der 和 crt 用 DER 编码。证书中包含着公钥等信息
-
key。秘钥文件,并非证书,通常来存放一个公钥或者私钥。编码可能是PEM,也有可能是DER。
-
csr。证书签名请求,并不是一个证书。用户向权威证书颁发机构获取签名证书的申请,其核心内容包含一个RSA公钥和其他附带信息。
-
pfx。也写作p12。全称PKCS12,它是公钥加密标准系统中的一种。它用来将包含了公钥的证书和私钥以及其他相关信息打包进行交换。简单可以理解为:一份.pfx文件 = 证书 + 私钥。通常情况下,pfx文件都会有一个提取密码,用于提取文件中的重要信息。
-
jks。即Java Key Stroage。可以利用 Java 自带的keytool生成jks扩展名的文件,也可以将pfx扩展名文件转化成jks的。
公钥文件和证书文件有什么区别
证书一般包含以下内容:
- 证书拥有者的公钥
- 证书的有效期
- 主体标识符信息(如名称和电子邮件地址)
- 颁发者的数字签名
- 数字证书的序列号
而公钥文件中仅仅包含了一个RSA公钥,一般以-----BEGIN RSA PUBLIC/PRIVATE KEY-----开头,以-----END RSA PUBLIC/PRIVATE KEY-----。
3.HTTPS单向和双向认证流程
如果有人问你 HTTPS 的实现原理,一开始你可以回答:用非对称加密算法传递对称加密算法的秘钥和加密方式。然后在阐述 HTTPS 单向认证和双向认证的流程。
HTTPS单向认证
-
客户端向指定域名的服务器发送 HTTPS 请求,请求内容包括
- 客户端支持的 SSL/TLS 协议版本列表
- 支持的对称加密算法列表
- 随机数A
-
服务器收到请求后,回应客户端,内容包括
- 双方都支持的 SSL/TLS 的最高版本,如果客户端的 SSL/TLS 服务端都不支持,则直接不允许访问
- 双方都支持的最安全的对称加密算法
- 公钥证书
- 服务器端生成的随机数B
-
客户端收到公钥证书检查证书的合法性,主要包括
-
检查证书是否过期
-
检查证书是否吊销
-
证书是否可信。客户端会有一个信任库,里面保存了该客户端信任的CA证书,如果收到的证书签发机构不在信任库中,则客户端会提示用户证书不可信。
- 若客户端是浏览器,浏览器开始查找操作系统中已内置的受信任的证书颁发机构CA,与服务器发来的证书中的颁发者CA比较,用于检查证书是否为合法机构颁发。
- 若客户端为程序。以 JAVA 客户端为例,需要配置信任库文件,以判断证书是否可信。如果没有设置,则默认使用 JDK 自带的证书库。
如果验证了证书合法,则取出公钥,对服务器发来的证书中的签名进行解密得到X,使用相同的hash算法计算服务器发来证书的hash值得到Y,比对X和Y,若相同则确定证书是服务器发来的。
-
检查收到的证书中的域名与请求的域名是否一致
- 若客户端是浏览器,则会出现警告,用户可以跳过,也可以进行访问
- 若客户端是程序,这一项配置可以不检查。
证书验证通过后,客户端生成随机数C,对随机数C用公钥加密,发送给服务器。
-
-
服务器的最后回应
服务器用私钥解密,得到随机数C。此时,服务器和客户端都拿到了随机数A,B,C,双方通过这三个随机数使用DH密钥交换算法得到相同的对称加密秘钥,这个密钥作为后续数据传输时对称加密使用的密钥。服务器回应客户端,握手结束,可以采用对称加密传输数据了。
DH秘钥交换算法思想:不通过网络传输密钥,而是双方协商一个共同的密钥生成方式,DH算法通过数学定律保证了双方各自计算出的密钥是相同的。
用一张流程图更清晰地展示 HTTPS 单向认证流程:
HTTPS双向认证
单向认证中,客户端会验证服务端,服务端对来访的客户端身份不做任何限制。如果服务端的服务只要要特定的客户端访问,那么就可以采用双向认证。双向认证在实际环境下用的较少。
HTTPS 双向认证在单向认证的基础上,增加了:
- 上述第二步中,服务器回应给客户端的消息中,会要求客户端提供客户端的证书
- 上述第三步中,客户端在验证完服务端之后,会发送给服务端自己的证书文件
- 服务端收到客户端的证书后,确认这个证书是否在自己的信任库中,如果验证不通过则会拒绝连接,验证通过则继续后续交互。
值得注意一点的是,使用单向认证还是双向认证,是服务端决定的。
4.openssl简单使用
openssl是一个开源项目,其组成主要包括以下三个组件:
- openssl:多用途的命令行工具
- libcrypto:加密算法库
- libssl:加密模块应用库,实现了SSL和TLS
openssl生成公私钥秘钥对文件
首先需要使用 genrsa 标准命令生成私钥,再使用 rsa 命令从私钥中提取公钥
openssl genrsa -out private_key.key 2048
在做RSA加解密时,不同语言使用的公私钥文件采用了不同的标准生成的私钥文件。例如python使用的是PKCS1标准,JAVA 使用的是 PKCS8 标准。openssl可以将证书在任何标准格式之间转化。
JAVA 需要使用的话私钥必须要经过PKCS#8编码
openssl pkcs8 -topk8 -inform PEM -in private_key.key -outform PEM -out pkcs8_private_key.key -nocrypt
在相同目录下,根据私钥生成对应的公钥
openssl rsa -pubout -in private_key.key -out public_key.key
可以发现默认生成的秘钥格式为PEM编码格式,PEM编码格式可以和DER编码格式互换。
openssl rsa -in private_key.key -outform der -out private_key_der.key
openssl rsa -in private_key_der.key -inform der -out pem -out private_key_pem.key
openssl生成自签名证书
我们先说说自签的SSL证书和CA认证的SSL证书的区别:
- 自签 SSL 证书免费,CA证书一般收费。阿里云上可以申请10个免费的SSL证书,有效期为一年,但免费的证书只支持单域名。
- 自签 SSL 证书不受客户端操作系统信任,所以自签SSL证书要想使用在HTTPS网站上时,客户端必须在操作系统中手动导入证书,否则浏览器会提示不安全。操作系统中默认内置CA认证的SSL证书,客户端不需要导入证书就可以访问HTTPS网站。
openssl生成一个RSA私钥
openssl genrsa -des3 -out server.key 2048
会要求输入安全密码,此秘钥用于加密key文件。这里随便输入一个123456。
如果不需要安全密码,可以使用下面这个命令
openssl rsa -in server.key -out server-nopassword.key
生成证书请求文件
openssl req -new -key server.key -out server.csr
按照提示一步一步输入个人信息即可。注意有一个common name,可以写名字或者域名。如果为了 HTTPS 请求,这个必须和域名一样,为什么要一样可以参考 HTTPS 单向认证中客户端检查证书的合法性原理。
对上一步生成的证书请求进行签名生成公钥证书
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
生成好的自签名证书
.key:私钥文件
.csr:证书请求文件
.crt:公钥证书
默认生成的证书和文件都是PEM编码格式,可以使用openssl命令转化成DER编码格式的。开发者就可以拿到这些证书和文件进行相关配置,来实现网站的 HTTPS 访问,自签名的SSL证书一般不会用在生产环境下。本文第六结会详细讲到如何申请CA机构颁发的浏览器受信任的 SSL 证书。
5.keytool生成自签名证书
JDK中的keytool是一个证书管理工具,可以快速的生成自签名证书。能达到的最终效果和上面的用openssl生成自签名证书效果一致。
keytool -genkey -alias server -keypass 123456 -keyalg RSA -keysize 2048 -keystore server.jks -validity 365
命名解释:
- -alias server(别名,可以随便起名字)
- -keypass 12345(别名密码)
- -keyalg RSA(生证书的算法名称)
- -keysize 2048(密钥长度)
- -validity 365(证书有效期,天单位)
- -keystore server.jks(指定生成证书的位置和证书名称)
- -storepass 123456(获取keystore信息的密码)
按照提示一步一步输入个人信息即可。
生成公钥证书
keytool -alias server -keypass 123456 -exportcert -keystore server.jks -file server.cer
6.物联网场景下消息传输建立SSL安全连接
MQTT 是当下适用最为广泛的物联网通讯协议。同HTTP一样,MQTT 也是应用层协议。
EMQX 是业界相对成熟的MQTT Broker。本章节主要讲解如何基于 EMQX 建立SSL安全连接。
8883是EMQX默认的MQTT SSL安全连接端口。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-seZybOE8-1581563027173)(E:\我们开始了\gitchat\那些证书\MQTT SSl.jpg)]
用章节4-2中的方式生成自签名证书,将证书放置在/etc/emqx/mycert目录下。EMQX有默认的自签名证书,在cert文件目录下,也可以使用。
server.crt:公钥证书
server-nopassword.key:不带密码的私钥文件
修改emqx.conf配置文件,然后重启 emqx
listener.ssl.external.keyfile = /etc/emqx/mycert/server-nopassword.key
listener.ssl.external.certfile = /etc/emqx/mycert/server.crt
使用Mqttfx工具连接测试,会指定公钥证书的路径
热衷技术的朋友可以关注我正在运营的公众号
从传统web项目转战物联网应用开发的朋友可以学习下面这篇专题