对称加密
加密和解密使用同一个密钥的方式成为共享密钥加密(Common key crypto system),也被成为对称密钥加密。
以共享的方式加密时必须将密钥也发送给对方。
AES算法
高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。
对称加密算法也就是加密和解密用相同的密钥,具体的加密流程如下图:
- 明文P:没有经过加密的数据。
- 密钥K:用来加密明文的密码,在对称加密算法中,加密与解密的密钥是相同的。密钥为接收方与发送方协商产生,但不可以直接在网络上传输,否则会导致密钥泄漏,通常是通过非对称加密算法加密密钥,然后再通过网络传输给对方,或者直接面对面商量密钥。密钥是绝对不可以泄漏的,否则会被攻击者还原密文,窃取机密数据。
- AES加密函数:设AES加密函数为E,则 C = E(K, P),其中P为明文,K为密钥,C为密文。也就是说,把明文P和密钥K作为加密函数的参数输入,则加密函数E会输出密文C。
- 密文C:经加密函数处理后的数据。
- AES解密函数:设AES解密函数为D,则 P = D(K, C),其中C为密文,K为密钥,P为明文。也就是说,把密文C和密钥K作为解密函数的参数输入,则解密函数会输出明文P。
密钥
AES的区块长度固定为128比特,密钥长度则可以是128,192或256比特。
以密钥长度128比特为例,密钥可以是:
(1)16个字符的随机字符串
假如我们跟客户端协商好,密钥是一个随机字符串(全英文),那么它应该包含16个字符,直接用getBytes()
获取128位。
为什么是16个字符?
客户端一般将AES算法写在so库里,用C语言实现。而C语言中char
是1个字节,8位,那么16x8=128位。
注意这16个字符不要包含中文等特殊字符,因为在Java中,char
是两个字节。由于英文可以用1个字节表示,所以仅用低8位,可以理解为英文字符也占1个字节,8位。
而中文等字符,使用Unicode编码表示,可能占据3个甚至多个字节。
(2)32个字符的十六进制字符串
另一种约定方式,是约定一个特殊字符串,每个字符是一个十六进制,一共32个字符,作为128位的十六进制表示,4x32=128。
这样两端在使用这个密钥时,都需要将十六进制转成二进制,而不是直接getBytes()
。
生成一个十六进制字符串秘钥:
AES属于对称加密,内容传输之前,前端使用密钥将内容加密,后端拿到后,使用相同的密钥将内容解密。
模式
主要使用以下两种模式:
- ECB:ECB是最简单的块密码加密模式,加密前根据加密块大小(如AES为128位)分成若干块,之后将每块使用相同的密钥单独加密,解密同理。ECB模式由于每块数据的加密是独立的因此加密和解密都可以并行计算,ECB模式最大的缺点是相同的明文块会被加密成相同的密文块,这种方法在某些环境下不能提供严格的数据保密性。
- CBC:CBC模式对于每个待加密的密码块在加密前会先与前一个密码块的密文异或然后再用加密器加密。第一个明文块与一个叫
初始化向量
的数据块异或。CBC模式相比ECB有更高的保密性,但由于对每个数据块的加密依赖与前一个数据块的加密所以加密无法并行。与ECB一样在加密前需要对数据进行填充,不是很适合对流数据进行加密。
ECB模式
这里介绍使用16长随机字符串进行ECB模式加解密。
|
|
CBC模式
这里介绍使用16字节初始向量vi
和32长十六进制密钥字符串进行CBC模式加解密。
|
|
对应的js代码: