写给自己看的的密码学知识
最近在做一些蓝牙相关的开发,其中遇到了加密协议,之前没接触过这块,sha256,AES这些东西只知道名字,也没想到有一天会用到。眼看着10月即将过去,给自己定的一个月一篇水文的目标都快要达不到了,实在惭愧。趁着10月的尾巴,补上这篇。
摘要算法
摘要算法又称哈希算法、散列算法。它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示),常用的有MD5, SHA1, SHA256,SHA512等。这种算法可以用来验证文件的有效性,比如某个文件下载下来是不是完整的,另外一种场景是,将用户密码存储到数据库中的时候,不存明文,而是存储密码的hash值
加盐
由于黑客可以通过反查内容和hash之间对应的表,来破解我们的密码,所以有了加盐的方式来提高安全性。比如用户的密码是123456,MD5得到的hash是e10adc3949ba59abbe56e057f20f883e,我们在计算hash时,可以在密码后拼接salt, 把密码变成123456salt,然后再计算并存到数据库里面,这样,即使黑客拿到了hash,也无法轻易通过反查表的方式得到密码。
HMAC
我们在调用一些API的时候,需要验证签名,可能会遇到使用HMAC-SHA256方式来验证签名,那么这个 HMAC-SHA256 和 SHA256 是一个东西吗,这两者有联系,但是其实不是一个东西。我们来看一个图:
我们可以看到HMAC算法里面的入参有两个,一个secretKey,一个message,最后输出一个MAC(message auth code)
HMAC的加密实现:HMAC (key, message) = H ( (key XOR opad ) + H( (key XOR ipad ) + message ) )
其中:
opad 是外部填充常数(0x5c5c5c…5c5c,一段十六进制常量)
ipad 是内部填充常数(0x363636…3636,一段十六进制常量)
我们可以看到,HMAC是使用了我们前面提到的摘要算法的,其中key相当于之前提到的盐,但是HMAC通过算法让这个过程更安全。
有了HMAC,平台侧可以把secret key发放给授权用户,用户调用api时,通过这个key,使用指定 的HMAC算法对内容加密,并把内容和sign一起给平台进行校验,如果平台算出的sign和请求带的sign一致,则返回正确的结果,否则就报错。这个过程就是验签。
对称加密和非对称加密
前面提到的算法虽然可以验证有效性,但是得到的hash值却不能用来解密来得到原文是什么。如果希望根据密文解密出原文,需要用到对称加密或者非对称加密。
对称加密的加密密钥和解密密钥使用同一个,所以速度相对较快,常见的算法有AES,DES等;
非对称加密的加密密钥和解密密钥是不同的,这样即便暴露了加密密钥,别人也不能知道原文是啥,从而安全性更高,常见的有RSA等。我们常用到的ssh免密码登录就用到了RSA算法。
AES
AES是常用的对称加密算法,它也是一种分组加密算法,也就是说,将原文分成一系列长度为16字节(128 bit)的块,进行加密运算之后再进行拼接得到密文。有人问了,如果原文的大小不是16字节的整数倍呢,那就需要先进行填充,使总数达到16字节的整数倍,具体怎么填充,详见填充模式。可以看下面这个视频来粗略了解下 https://www.bilibili.com/video/av883701367?t=168.7
填充模式
假如我们原文分块之后,最后一块是8字节,那么需要填充8字节。这8字节应该填充什么呢,这就是填充模式了,AES支持的填充模式有,NoPadding,PKCS5Padding,PKCS7Padding,ISO10126Padding等
具体每种模式的填充方式可以看这里:https://juejin.cn/post/6966832843104190472
工作模式
在加密的过程中,上一字节块的加密结果时候会对下一块的结果产生影响呢,这个就是由工作模式决定的,常见的工作模式有电子密码本:Electronic Code Book Mode (ECB)
密码分组链接:Cipher Block Chaining Mode (CBC)
密文反馈:Cipher Feedback Mode (CFB)
输出反馈:Output Feedback Mode (OFB)
对于每种工作模式的介绍可以看这里: https://juejin.cn/post/6967261330193678350
明文和密文长度关系
在原始数据长度为 16 的整数倍时
假如原始数据长度等于 16n,则使用 NoPadding 时加密后数据长度等于 16n,其它情况下加密数据长度等于 16*(n+1)。
在不足 16 的整数倍的情况下
假如原始数据长度等于 16n+m [其中 m 小于16],除了 NoPadding 填充之外的任何方式,加密数据长度都等于 16(n+1);