加密解密
Base64编解码
在参数传输的过程中经常遇到的一种情况:使用全英文的没问题,但一旦涉及到中文就会出现乱码情况。与此类似,网络上传输的字符并不全是可打印的字符,比如二进制文件、图片等。Base64的出现就是为了解决此问题,它是基于64个可打印的字符来表示二进制的数据的一种方法。
我们知道在计算机中任何数据都是按ascii码存储的,而ascii码的128~255之间的值是不可见字符。而在网络上交换数据时,比如说从A地传到B地,往往要经过多个路由设备,由于不同的设备对字符的处理方式有一些不同,这样那些不可见字符就有可能被处理错误,这是不利于传输的。所以就先把数据先做一个Base64编码,统统变成可见字符,这样出错的可能性就大降低了。
Base64索引表:['A','B'...'a','b',...'0','1',...'+','/']
转换步骤:
- 待转换字符串每3个字节分为一组,共24位
- 将上面24位每6个一组分为4组
- 在每组前面添加两个0,总共32位,即4个字节
- 根据上面Base64索引表获得相应的值
因此Base64编码之后的文本要比原文大约三分之一
如果位数不足,依旧是每6分字节一组,不足的用0补齐,后面没有对应数据的用=
补齐.

Base64是一种任意二进制到文本字符串的编码方法,常用于在URL、Cookie、网页中传输少量二进制数据。在项目中,将报文进行压缩、加密后,最后一步必然是使用base64编码,因为base64编码的字符串更适合不同平台、不同语言的传输.
SHA-256 哈希函数
一个n
位的哈希函数就是一个从任意长的消息到n
位哈希值的映射,这样的函数是目前在数字签名和密码保护当中极为重要的手段。当前比较流行的哈希函数主要有128位的MD4和MD5和160位的SHA-1,今天介绍的SHA-2(Secure Hash Algorithm 2)族有着更多位的输出哈希值,破解难度更大,能够提高更高的安全性.
对于任意长度的消息,SHA256都会产生一个256位的哈希值,称作消息摘要,通常用64个十六进制字符串表示.
称谓: 单向散列函数, 哈希函数, 杂凑函数, 消息摘要函数
输入: 原像
输出: 散列值, 哈希值, 指纹, 摘要
常见的应用场景有: 数据库中保护用户密码、防止文件篡改、数字签名、伪随机数生成、秒传等.
RSA加密算法
RSA是目前最有影响力和最常用的公钥加密算法(非对称加密),可以说是公钥加密算法的事实标准。
公钥=(E,N)
私钥=(D,N)
密钥对=(E,D,N)
所以生成密钥对就是求E、D、N.
- N: 准备两个互质数p,q。这两个数不能太小,太小则会容易破解,将p乘以q就是N。如果互质数p和q足够大,那么根据目前的计算机技术和其他工具,至今也没能从N分解出p和q。换句话说,只要密钥长度N足够大(一般1024足矣),基本上不可能从公钥信息推出私钥信息。
- L: p-1 和 q-1的最小公倍数,即lcm(p-1,q-1)
- E: E是一个比1大比L小的数,E和L的最大公约数为1.
- D: 数D是由数E计算出来的,数D必须保证足够大.1 < D < L; E*D mod L = 1.只要D满足上述2个条件,则通过E和N进行加密的密文就可以用D和N进行解密.
因此RSA公钥加密体制包含三个算法:
(PK,M)<---KeyGen(): 密钥生成算法,
是安全常数,值越大,质数p越大
CT <---Encrypt(PK,M): 加密算法
M <---Decrypt(SK,CT): 解密算法
但是公钥加密会面临中间人攻击的危险, 所以我们要确保公钥必须是我们想要发送的对方的公钥,而不是其他人顶替的.这就需要给公钥签名.
非对称加密算法除了支持加密外,还可以实现签名.
签名过程: 使用发送方私钥对消息摘要加密, 生成消息签名, 接收方公钥生成密文发送出去(防止hash值也被篡改)
验签过程: 使用接收方私钥对密文进行解密, 获得消息和消息签名; 使用发送方公钥解密消息签名, 获得消息摘要; 使用相同哈希算法生成消息摘要进行对比,如果相同验签成功.

RSA签名体制同样包含三个算法:
(PK,SK)<---KeyGen()
<---Sign(SK,M): 签名算法以私钥SK和待签名的消息M作为输入,输出签名
b <---Verify(PK,,M): 验证算法以公钥PK,签名
以及消息M作为输入,输出一个比特值b。b=1意味着验证通过。b=0意味着验证不通过
HTTPS加密过程和证书验证过程
首先https=http+tls. TLS是基于TCP协议之上的,由SSL发展而来.TLS协议的优势是与高层应用层协议无耦合,应用层协议能够透明的运行在TLS协议之上,由TLS协议进行创建加密通道需要的协商和认证。应用层协议传送的数据在通过TLS协议时都会被加密,从而保证通信的私密性。
基本过程是: 客户端像服务器端索要公钥;双方生成“对话密钥”;双方采用“对话密钥”进行通信.
问题:
-
如何保证公钥不被篡改?
将公钥放在证书里,只要证书可信,公钥就是可信的.
-
公钥加密计算量太大,如何减少耗用时间?
每一次对话(session),客户端和服务器端都生成一个"对话密钥"(session key),用它来加密信息。由于"对话密钥"是对称加密,所以运算速度非常快,而服务器公钥只用于加密"对话密钥"本身,这样就减少了加密运算的消耗时间。
TLS协议流程
一旦客户端和服务器都同意使用TLS协议,他们通过一个握手过程协商出一个有状态的连接以传输数据.这通常发生在TCP连接建立以后.具体过程为:
-
客户端发送TLS版本号+所支持加密套件列表(加密算法、哈希算法)+客户端生成的随机数+希望使用的TLS选项
-
服务器端选择一个客户端加密套件+自己的证书+服务端生成的随机数+希望使用的TLS选项+(要求客户端证书)
-
客户端验证服务器身份后,取出证书中的公钥,发送(自己证书)+使用服务器公钥加密一个随机数(此时双方各有三个相同随机数,用于生成会话密钥)
为什么需要三个随机数?
客户端和服务器加上pre master secret三个随机数一同生成的密钥就不容易被猜出了,一个伪随机可能完全不随机,可是是三个伪随机就十分接近随机了,每增加一个自由度,随机性增加的可不是一.
-
服务器端使用私钥解密出信息后,计算生成会话密钥,发送加密的finish消息,表明完成握手,接下来进行的通信就是普通的http协议,只不过发送的是加密过的消息.
证书验证过程
证书签发过程:
- 撰写证书元数据信息
- 通过Hash算法计算出消息摘要
- 然后用CA机构的私钥对消息摘要加密,生成签名,附在文件证书上,使之变成一个签名过的证书.
证书验证过程:
- 客户端获得站点的证书,解码后获得元数据信息和签名,要验证站点可信后,才能使用其公钥,因此客户端找到其站点证书颁发者的信息
- 站点证书的颁发者验证了服务端站点是可信的,但客户端依然不清楚该颁发者是否可信
- 再往上回溯,找到了认证了中间证书商的根证书颁发者。由于根的证书颁发者非常少,我们浏览器之前就认识了,因此可以认为根证书颁发者是可信的;
- 一路倒推,证书颁发者可信,那么它所颁发的所有站点也是可信的,最终确定了我们所访问的服务端是可信的;
- 客户端使用证书中的公钥,继续完成
TLS
的握手过程
自签证书
首先,X.509是一个标准,规范了公开秘钥认证、证书吊销列表、授权凭证、凭证路径验证算法等。X.509证书包含三个文件: .key、.csr、.crt(.pem),分别是私钥、证书签名请求文件、签名后的证书.
我们可以使用openssl命令行工具给自己签证书,用于测试使用或内部系统使用,但这样会被浏览器提示未认证的签名机构,需要我们自己信任该证书,不过有的浏览器可能对于私有证书会直接拒绝不给提示的机会.
自签证书相当于把自己生成的证书签名请求文件,用自己的私钥去做签名,相当于CA证书,自己给自己做验证.这个证书还可以给其他客户端去做前面,这样当我们有多个客户端的时候,只需要在客户端安装根证书就可以了,不必重复安装客户端证书.
X.509证书有两种编码格式:
- PEM: 是明文格式的, 以 -----BEGIN CERTIFICATE-----开头,已-----END CERTIFICATE-----结尾,中间是经过base64编码的内容,apache需要的证书就是这类编码的证书 查看这类证书的信息的命令为 :openssl x509 -noout -text -in server.pem
- DER: 是二进制格式的证书,查看这类证书的信息的命令为 :openssl x509 -noout -text -inform der -in server.der
我们遇到常用的证书扩展名.crt、.cer、.pem大部分都使用PEM编码格式.
.key 一般公钥或者密钥都会用这种扩展名,可以是DER编码的或者是PEM编码的 查看DER编码的(公钥或者密钥)的文件的命令为 openssl rsa -inform DER -noout -text -in xxx.key 查看PEM编码的(公钥或者密钥)的文件的命令为 openssl rsa -inform PEM -noout -text -in xxx.key