0


AES对称加密

前言

对称加密(Symmetric Cryptography)

  1. 对称加密是最快速、最简单的一种加密方式,加密(encryption)与解密(decryption)用的是同样的密钥(secret key)。
  2. 对称加密通常使用的是相对较小的密钥,一般小于256 bit。因为密钥越大,加密越强,但加密与解密的过程越慢。
  3. 对称加密的一大缺点是密钥的管理与分配,换句话说,如何把密钥发送到需要解密你的消息的人的手里是一个问题。在发送密钥的过程中,密钥有很大的风险会被黑客们拦截。现实中通常的做法是将对称加密的密钥进行非对称加密,然后传送给需要它的人。
  4. 对称加密,加密速度非常快,适合经常发送数据的场合。缺点是密钥的传输比较麻烦。

非对称加密(Asymmetric Cryptography)

  1. 非对称加密为数据的加密与解密提供了一个非常安全的方法,它使用了一对密钥,公钥(public key)和私钥(private key)。私钥只能由一方安全保管,不能外泄,而公钥则可以发给任何请求它的人。非对称加密使用这对密钥中的一个进行加密,而解密则需要另一个密钥。
  2. 非对称算法,加密解密的速度比较慢,适合偶尔发送数据的场合。优点是密钥传输方便。常见的非对称加密算法为RSA、ECC和EIGamal

相关概念

分组:用来执行加密程序的内存空间有限。
密钥长度

128 bits

192 bits

256 bits

。密钥的长度不同,推荐加密轮数也不同。
**初始向量(IV)**:防止同样的明文块,始终加密成同样的密文块
填充方式:密钥只能对确定长度的数据块进行处理,所以需要对最后一块做额外处理,常用的模式有

PKCS5

,

PKCS7

,

NOPADDING

要想学习AES,首先要清楚三个基本的概念:密钥填充模式

秘钥

密钥是AES算法实现加密和解密的根本

  • 对称加密算法之所以对称,是因为这类算法对明文的加密和解密需要使用同一个密钥。

AES支持三种长度的密钥: 128位,192位,256位

  • 平时大家所说的AES128,AES192,AES256,实际上就是指AES算法对不同长度密钥的使用。三种密钥的区别:从安全性来看,AES256安全性最高。从性能看,AES128性能最高。本质原因是它们的加密处理轮数不同。

填充

要想了解填充的概念,我们先要了解AES的分组加密特性。

什么是分组加密?
在这里插入图片描述
如上图所示,AES算法在对明文加密的时候,并不是把整个明文一股脑的加密成一整段密文,而是把明文拆分成一个个独立的明文块,每一个明文块长度128bit。

这些明文块经过AES加密器复杂处理,生成一个个独立的密文块,这些密文块拼接在一起,就是最终的AES加密的结果。

但这里涉及到一个问题,假如一段明文长度是196bit,如果按每128bit一个明文块来拆分的话,第二个明文块只有64bit,不足128bit。这时候怎么办呢?就需要对明文块进行填充(Padding)。

几种典型的填充方式:

  1. NoPadding:不做任何填充,但是要求明文必须是16字节的整数倍(一般不会使用)
  2. PKCS5Padding(默认): 如果明文块少于16个字节(128bit),在明文块末尾补足相应数量的字符,且每个字节的值等于缺少的字符数。 比如明文:{1,2,3,4,5,a,b,c,d,e},缺少6个字节,则补全为{1,2,3,4,5,a,b,c,d,e,6,6,6,6,6,6}
  3. ISO10126Padding:如果明文块少于16个字节(128bit),在明文块末尾补足相应数量的字节,最后一个字符值等于缺少的字符数,其他字符填充随机数。比如明文: {1,2,3,4,5,a,b,c,d,e},缺少6个字节,则可能补全为 {1,2,3,4,5,a,b,c,d,e,5,c,3,G,$,6}
  4. PKCS7Padding:原理与PKCS5Padding相似,区别是PKCS5Padding的blocksize为8字节,而PKCS7Padding的blocksize可以为1到255字节
  5. ANSIX9.23:跟ISO10126很像,只不过ANSI X9.23其他字节填的都是0而不是随机数

需要注意的是,如果在AES加密的时候使用了某一种填充方式,解密的时候也必须采用同样的填充方式。

工作模式

AES的工作模式,体现在把明文块加密成密文块的处理过程中。
AES加密算法提供了五种不同的工作模式:

ECB

CBC

CFB

OFB

CTR

AES加密算法 - 加密模式

  1. 电码本模式(Electronic Codebook Book (ECB))
  2. 密码分组链接模式(Cipher Block Chaining (CBC))
  3. 密码反馈模式(Cipher FeedBack (CFB))
  4. 输出反馈模式(Output FeedBack (OFB))
  5. 计算器模式(Counter (CTR))

ECB

最简单的加密模式,明文消息被分成固定大小的块(分组),并且每个块被单独加密。

每个块的加密和解密都是独立的,且使用相同的方法进行加密,所以可以进行并行计算,但是这种方法一旦有一个块被破解,使用相同的方法可以解密所有的明文数据,安全性比较差。

适用于数据较少的情形,加密前需要把明文数据填充到块大小的整倍数。
在这里插入图片描述
优点:
1.简单
2.有利于并行计算
3.误差不会被传送
缺点:
1.不能隐藏明文的模式
2.可能对明文进行主动攻击

CBC

这种模式是先将明文切分成若干小段,然后每一小段与初始块或者上一段的密文段进行异或运算后,再与密钥进行加密。

这样每个密文块依赖该块之前的所有明文块,为了保持每条消息都具有唯一性,第一个数据块进行加密之前需要用初始化向量IV进行异或操作。

CBC模式是一种最常用的加密模式,它主要缺点是加密是连续的,不能并行处理,并且与ECB一样消息块必须填充到块大小的整倍数。
在这里插入图片描述
优点:
1.不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。
缺点:
1.不利于并行计算
2.误差传递
3.需要初始化向量IV

CFB

和CBC模式比较相似,前一个分组的密文加密后和当前分组的明文XOR异或操作生成当前分组的密文。CFB模式的解密和CBC模式的加密在流程上其实是非常相似的。
在这里插入图片描述
优点:
1.隐藏了明文模式
2.分组密码转化为流模式
3.可以及时加密传送小于分组的数据
缺点:
1.不利于并行计算
2.误差传送:一个明文单元损坏影响多个单元
3.唯一的IV

OFB

将分组密码转换为同步流密码,也就是说可以根据明文长度先独立生成相应长度的流密码。通过流程图可以看出,OFB和CFB非常相似,CFB是前一个分组的密文加密后XOR当前分组明文,OFB是前一个分组与前一个明文块异或之前的流密码XOR当前分组明文。由于异或操作的对称性,OFB模式的解密和加密完全一样的流程。
在这里插入图片描述
优点:
1.隐藏了明文模式
2.分组密码转化为流模式
3.可以及时加密传送小于分组的数据
缺点:
1.不利于并行计算
2.对明文的主动攻击是可能的
3.误差传送:一个明文单元损坏影响多个单元

CTR

对一系列输入数据块(称为计数)进行加密,产生一系列的输出块,输出块与明文异或得到密文

加密过程使用了密钥、Nonce(类似IV)、Counter(一个从0到n的编号)

最大的优势是可以并行执行,因为所有的块只依赖于Nonce与Counter,并不会依赖于前一个密文块,可事先进行加解密准备,适合高速传输需求
在这里插入图片描述

GCM工作模式

CBC、CFB、OFB 三种模式可以解决 ECB 模式中相同明文生成相同密文的缺陷,CTR 又可以在此基础上提供多分组并行加密特性,但是它们都不能提供密文消息完整性校验功能,所有就有了 GCM 模式。

微信支付成功回调通知使用了该模式

完整性

有的人可能会想到,如果将密文的hash值随密文一起发送,接收者对收到的密文计算hash值,与收到的hash值进行比对,这样是否就能校验消息的完整性呢?

但再仔细想想,就能发现这其中的漏洞。

如果篡改者截获原始密文后,先篡改密文,而后计算篡改后的密文hash,替换掉原始消息中的密文hash。这样,接收者依旧没有办法发现对密文的篡改。

可见,使用单向散列函数计算hash值仍然不能解决消息完整性校验的问题。

MAC消息验证码

MAC:Message Authentication Code, 消息验证码
在这里插入图片描述
消息验证码是一种与密钥相关的单项散列函数。

发送者使用密钥和消息得到MAC值,接收者利用密钥和收到的密文计算MAC值,与随消息而来的MAC值做 比较,从而判断消息是否被改过(完整性)。

当篡改者篡改密文后,因为没有密钥,就无法计算篡改后的密文的MAC值。

GMAC

GMAC:Galois message authentication code mode, 伽罗瓦消息验证码

对应到上图中的消息认证码,GMAC就是利用伽罗华域(Galois Field,GF,有限域)乘法运算来计算消息的MAC值。

GCM

GCM中的G 就是值GMAC,C就是指CTR。 所以GCM可以提供对消息的加密和完整性校验。
在这里插入图片描述
就像CTR模式下一样,先对块进行顺序编号,然后将该块编号与初始向量(IV)组合,并使用密钥K,对输入做AES加密,然后,将加密的结果与明文进行XOR运算来生成密文。像CTR模式下一样,应该对每次加密使用不同的IV。对于附加消息,会使用密钥H(由密钥K得出),运行GMAC,将结果与密文进行XOR运算,从而生成可用于验证数据完整性的身份验证标签。最后,密文接收者会收到一条完整的消息,包含密文、IV(计数器CTR的初始值)、身份验证标签(MAC值)。

代码示例

/**
 * 密钥长度:128位、192位、256位
 * 工作模式:ECB/CBC/PCBC/CTR/CTS/CFB/CFB8 to CFB128/OFB/OBF8 to OFB128
 * 填充方式:Nopadding/PKCS5Padding/ISO10126Padding/
 */publicclassAESUtils{privatestaticfinalString KEY_ALGORITHM ="AES";privatestaticfinalString DEFAULT_CIPHER_ALGORITHM ="AES/ECB/PKCS5Padding";//默认的加密算法publicstaticbyte[]initSecretKey()throwsNoSuchAlgorithmException{//返回生成指定算法密钥生成器的 KeyGenerator 对象KeyGenerator kg =KeyGenerator.getInstance(KEY_ALGORITHM);//初始化此密钥生成器,使其具有确定的密钥大小//AES 要求密钥长度为 256
        kg.init(256);//生成一个密钥SecretKey secretKey = kg.generateKey();return secretKey.getEncoded();}privatestaticKeytoKey(byte[] key){//生成密钥returnnewSecretKeySpec(key, KEY_ALGORITHM);}publicstaticbyte[]encrypt(byte[] data,Key key)throwsException{returnencrypt(data, key, DEFAULT_CIPHER_ALGORITHM);}publicstaticbyte[]decrypt(byte[] data,Key key)throwsException{returndecrypt(data, key,DEFAULT_CIPHER_ALGORITHM);}publicstaticbyte[]encrypt(byte[] data,byte[] key)throwsException{returnencrypt(data, key, DEFAULT_CIPHER_ALGORITHM);}publicstaticbyte[]decrypt(byte[] data,byte[] key)throwsException{returndecrypt(data, key,DEFAULT_CIPHER_ALGORITHM);}publicstaticbyte[]encrypt(byte[] data,byte[] key,String cipherAlgorithm)throwsException{//还原密钥Key k =toKey(key);returnencrypt(data, k, cipherAlgorithm);}publicstaticbyte[]encrypt(byte[] data,Key key,String cipherAlgorithm)throwsException{//实例化Cipher cipher =Cipher.getInstance(cipherAlgorithm);//使用密钥初始化,设置为加密模式
        cipher.init(Cipher.ENCRYPT_MODE, key);//执行操作return cipher.doFinal(data);}publicstaticbyte[]decrypt(byte[] data,byte[] key,String cipherAlgorithm)throwsException{//还原密钥Key k =toKey(key);returndecrypt(data, k, cipherAlgorithm);}publicstaticbyte[]decrypt(byte[] data,Key key,String cipherAlgorithm)throwsException{//实例化Cipher cipher =Cipher.getInstance(cipherAlgorithm);//使用密钥初始化,设置为解密模式
        cipher.init(Cipher.DECRYPT_MODE, key);//执行操作return cipher.doFinal(data);}privatestaticStringshowByteArray(byte[] data){if(null== data){returnnull;}StringBuilder sb =newStringBuilder("{");for(byte b:data){
            sb.append(b).append(",");}
        sb.deleteCharAt(sb.length()-1);
        sb.append("}");return sb.toString();}publicstaticvoidmain(String[] args)throwsException{byte[] key =initSecretKey();System.out.println("key字节数组:"+showByteArray(key));Key k =toKey(key);//生成秘钥System.out.println("key base64编码:"+Base64.getEncoder().encodeToString(key));System.out.println("key base64解码:"+showByteArray(Base64.getDecoder().decode(Base64.getEncoder().encodeToString(key))));System.out.println();String data ="AES数据";System.out.println("加密前数据: string: "+data);System.out.println("加密前数据: byte[]: "+showByteArray(data.getBytes()));System.out.println();byte[] encryptData =encrypt(data.getBytes(), k);//数据加密System.out.println("加密后数据: byte[]: "+showByteArray(encryptData));String base64Data =Base64.getEncoder().encodeToString(encryptData);System.out.println("加密后数据: base64: "+ base64Data);//       System.out.println("加密后数据: hexStr:"+Hex.encodeHexStr(encryptData));System.out.println();byte[] decryptData =decrypt(Base64.getDecoder().decode(base64Data), k);//数据解密System.out.println("解密后数据: byte[]:"+showByteArray(decryptData));System.out.println("解密后数据: string:"+newString(decryptData));}}
标签: web安全

本文转载自: https://blog.csdn.net/chenming3030/article/details/124991348
版权归原作者 chenming3030 所有, 如有侵权,请联系我们删除。

“AES对称加密”的评论:

还没有评论