往期回顾
- 基础密码学入门: 随机数、hash算法、对称加密算法
消息验证码(MAC)算法
为什么需要MAC算法?
hash算法只可以验证数据的完整性,但是无法保证数据防篡改。
乍一看,好像上述的示例是成立的,但是一旦遇到“中间人攻击”。
你会发现攻击者对消息进行篡改了,但是通过hash算法计算摘要值,你是无法知道消息被改动过的。因此这个时候就需要MAC算法了。
MAC特点
- 跟hash算法一样,可以验证数据的完整性。
- 可以验证数据确实是由原始发送方发出的。
MAC值 = mac(消息+密钥)
MAC值一般和原始消息一起传输,原始消息可以选择加密,也可以选择不加密,通信双方会以相同的方式生成MAC值,然后进行比较,一旦两个MAC值相同表示MAC验证正确,否则验证失败。
MAC算法分类
在密码学中,MAC算法有两种形式,分别是CBC-MAC算法和HMAC算法。在HTTP中应用最多的MAC算法是HMAC算法。
HMAC(Hash-based Message Authentication Code)算法使用Hash算法作为加密基元,HMAC结合Hash算法有多种变种,比如HMAC-SHA-1、HMAC-SHA256、HMAC-SHA512。不要误以为HMAC算法就是Hash算法加上一个密钥,HMAC算法只是基于Hash算法的,内部的实现还是相当复杂的。
现在回想目前介绍过的密码学算法:
- 对称加密算法:保证数据的机密性
- hash算法:可以验证数据的完整性
- mac算法:可以验证数据完整性、以及验证数据是否被篡改
AD加密
借助MAC、对称加密算法我们可以组合出一些不同的加密模式。
Encrypt-and-MAC (E&M)
密钥指的是对称加密算法中的密钥,既用这个密钥对原始数据进行对称加密,以及通过MAC算法(明文+密钥)计算出MAC值。最后将两个数据发送出去。
MAC-then-Encrypt (MtE)
- MAC算法(明文+密钥)计算出MAC值。
- 把上一次计算出的MAC值+明文,再次用密钥对称加密,得到最终密文,发生出去。
Encrypt-then-MAC (EtM)
- 先用密钥+明文进行对称加密得到秘文。
- 用MAC(密钥+秘文)计算出MAC值。
- 将密文、MAC值发送出去。
公开密钥算法
公开密钥算法(Public KeyCryptography),也称为非对称加密算法(Asymmetrical Cryptography),公开密钥算法不是一个算法而是一组算法,如果公开密钥算法用于加密解密运算,习惯上称为非对称加密算法。
在介绍公开密钥算法之前,我们可以对比下它与对称加密算法的异同:
- 功能不一样
对称加密算法主要用于数据加密,而公开密钥算法不仅仅可以用于数据加密,还可以用于密钥协商、数字签名。
- 密钥是一对
对称加密算法中,密钥是一串数字,加密者和解密者使用同样的一个密钥。
公开密钥算法之所以包含公开两字,表示密钥可以部分公开,公开密钥算法的密钥是一对,分别是公钥(public key)和私钥(private key),一般私钥由密钥对的生成方(比如服务器端)持有,避免泄露,而公钥任何人都可以持有,也不怕泄露。
- 运算速度
如果加密数据比较大,公开密钥算法的执行速度是比较慢的,不过还好的是,公开密钥算法一般用于密钥协商、数字签名,这两者涉及的数据量不大。
公开密钥算法最重要和最广泛使用的算法就是RSA算法,该算法是Ron Rivest、Adi Shamir、Leonard Adleman三个人创建的,以三个人名字的首字母命名。RSA算法是一个多用途的算法,可以进行加密解密、密钥协商、数字签名,需要重点理解。
RSA的内部结构
对称加密算法中的密钥是一串数字,没有太多的其他含义,而RSA算法中的公钥和私钥在生成的时候有很大的关系,公钥和私钥不只是一串数字,由很多参数组成,公钥和私钥一般以文件的形式提供。
关于RSA结构、加密、解密更详细就需要查阅资料,这里就不扩展了。
目前,对于RSA非对称加密算法来说,一个2048比特长度的密钥对被认为是安全的。
RSA使用场景
单步加密
客户端可以使用公钥加密一些敏感数据发生到密钥生成方,接受方收到后,通过私钥解密,获取消息内容,而无需回应。
举个场景示例:
- 客户端向服务器端发送连接请求,服务器返回RSA密钥对的公钥给客户端,自己保留密钥对的私钥。
- 客户端接收到服务器的公钥,使用公钥对身份证号进行RSA加密,并发送给服务器。
- 服务器端用RSA私钥解密接收到的数据,获取的值就是用户的身份证号。
双向加密
在单步加密过程中,服务器端无法发送密文,如果服务器端用私钥加密数据,然后发送给客户端,由于公钥是公开的,任何人都能解密,所以这个过程是不成立的。
通过RSA算法如何真正做到加密呢?如何确保通信的过程中,服务器端和客户端能够互相发送加密消息呢?
这里就用到了双向加密,我们可以举例(不考虑传输性能)说明下。
- 客户端生成一对RSA密钥对,然后连接服务器端,并将自己的公钥(clientPublicKey)发给服务器端。
- 服务器端接收请求后,保存客户端的公钥,然后生成另外一对RSA密钥对,并将公钥(serverPublicKey)发送给客户端。
- 客户端使用服务器的公钥(serverPublicKey)加密身份证号,加密的数据发送给服务器端,期待服务器端返回自己的账户余额。4. 服务器端接收到数据后,用自己的私钥(serverPrivateKey)解密出客户端的身份证号,然后查询出用户的余额,并用客户端的公钥(clientPublicKey)加密余额,并发送给客户端。
- 客户端用自己的私钥(ClientPrivateKey)解密接收到的数据,这个数据就是自己账户下的余额。
可见就是利用了两个RSA密钥对。