1. 概述

在网络通信中,经常会用到加解密技术,其中AES加解密算法是比较广泛的应用于大块数据的对称加解密算法,本文主要介绍AES算法的一些基本原理,假设您对加解密、秘钥等知识有一定的认识,目标是为了建立对AES算法的概念认知,这里不打算对算法的数学原理进行阐述。

2. 术语

名词 释义
AES Advanced Encryption Standard,高级加密标准,一种对称加密算法。最早由美国NIST发起,广泛征集替代DES的加密算法,最终Rijndael算法族胜出,而AES则是源于该算法的变体标准。目前被广泛应用于互联网。
SPN substitution–permutation network,代替置换网络,一种对数据进行计算的方法,其理论基础是香农的混淆扩散理论。被大量实践在各种加解密算法中,包括AES
S-box substitution box,负责SPN中混淆职能的部分。具体指密文中的任意一个bit的生成,需要依赖于密钥的多个bit。反过来就是说,密钥中的一个bit发生变化,会导致整个密文发生多处改变
P-box permutation box,负责SPN中扩散职能的部分。指明文中一个bit的变化,会导致加密密文中一半bit的变化;密文中一个bit的变化,会导致解密后明文一半的bit发生变化。也就是指密码学上的雪崩效应
Key 加解密使用到的密钥,在AES规范中,支持128、192、256bit三种密钥长度,这也对应了加解密的强度
Round AES加密过程中的轮,不同的密钥长度,加密的轮数不同
Block 分块,也叫分组,也叫做加密算法中的块,作为加解密的基本计算单元,数据往往被分为多个块进行处理,狭义上也指分组加密模式
Block cipher mode 分组加密模式
Stream cipher mode 流式加密模式
IV Initialization vector,在部分分组加密模式中使用的,额外输入的随机初始化向量,其作用一般是用于使同样的明文多次加密的结果增加随机性,工程实践中一般称为Nonce
ECB Electronic codebook,一种基于AES的分组加密模式,分组之间无关联
CBC Cipher block chaining,一种基于AES的分组加密模式,需要IV,分组之间存在关联
CTR CounTeR,一种基于AES的分组加密模式,需要IV,分组之间存在联系,基于IV生成计数器,使用AES算法对计数器加密,再与明文运算生成密文
GCM Galois/counter mode,伽罗瓦计数器模式,一种基于CTR的变体,允许添加除IV之外的自定义数据,来参与计算MAC值,预防数据篡改
Padding 数据对齐
MAC Message Authentication Code,消息认证码,一种加密数据防篡改手段

这里概念很多,很容易迷失在名词里,其实这里只有两个重点:AES基于SPN模型的多轮计算过程是AES加解密的内核,而加密模式是在AES加解密算法的基础上,增加了Block之间关联关系的方法。这样脉络就清晰了,下面就这两个过程分别进行介绍。

3. AES加解密过程

3.1. 对齐

AES规范中,约定Block的大小固定为128bit(16Byte),也就是说,所有的加密过程是按照16字节独立来进行的。
由于待加密的明文可能不是16字节的整数倍,所以一般第一步的处理,就是对明文进行Padding,为了确保解密时能够获得正确的明文,Padding过程具有一定的要求,比如用明文的长度除16取余,以16进制表示该余数,这样可以放在一个字节中,然后在明文后面追加该字节,直到整个明文达到16字节整数倍。不同的算法具有不同的Padding规范。

3.2. 分块

对齐之后,明文数据就可以分为同样大小的Block了,后续的加密过程,是按照Block来独立进行的,Block和Block之间没有关联。

3.3. 轮

在对Block加密的过程中,不是只计算一次就结束了,而是在16个字节的空间上,重复地进行加密计算,一个Block经过加密计算后,还是一个16Byte的Block,循环往复多次。对于不同的Key长度,加密的轮数也不一样,128bit的秘钥,会对一个Block执行10轮加密,而192和256bit的Key,会对一个Block执行12、14轮加密。而每一轮的计算中,都包含基于SPN模型的混淆和扩散操作。

3.4. 块加密

AES最核心的加密过程,单轮总共有四个步骤,首先将一个Block的16字节视作一个4x4的矩阵

序号 步骤 说明
1 SubBytes 对4x4矩阵中的元素进行查表替换,表格内容可以参考这里lookup table,这一过程即是对应S-box的混淆过程。在golang标注库中的crypto/aes/const.go源码中可以找到该table的定义
2 ShiftRows 将矩阵行向左移位rowindex次,比如block[1][2],行索引是1,所以移动到block[1][1],再比如block[3][1],行索引是3,所以移动到block[3][2]。这一过程对应P-box的扩散过程。在多轮加密中一个原始的bit位由于被多次移位,当明文中这一bit发生变更时,会影响密文中的多个bit
3 MixColumns 每一列与一个常量矩阵进行乘法运算。将4x4矩阵的列视为向量,乘以一个常量矩阵,并回写到原位置。有关这个常量矩阵的描述可以看这里
4 AddRoundKey 基于Rijndael秘钥生成算法,生成轮秘钥,并与Block异或计算。粗略地讲,Rijndael算法就是以原始输入Key为种子,为每一轮加密生成不同的轮密钥,轮密钥长度与Key长度无关,与Block长度相同。所以这也解释了,为什么Key越长越安全,因为生成的轮秘钥不可预测性会更好

上面这四个步骤充满数学色彩,涉及线性代数、伽罗瓦域等概念,非密码学专业可以不用理会,AES加密过程就是把上述过程重复N次,N依密钥长度不同而不同。

具体来说,以128bit的key为例,第一轮仅执行【4】,中间2-9轮执行【1、2、3、4】所有步骤,最后第10轮,执行【1、2、4】
每一个步骤都以前一个步骤的运算结果矩阵为输入进行计算,每一轮都以前一轮的结果矩阵为输入进行计算,这就是整个AES对Block的加密过程。

3.5. 相关优化

当待加密数据较长时,Block数量会随之增多,那么加密的计算量还是比较大的,幸运的是Intel为这个加密过程提供了内置的指令集支持。
块加密过程被整体打包进AESENC/AESENCLAST指令,而go基于该指令封装了encryptBlockAsm方法,其实现如下:

TEXT ·encryptBlockAsm(SB),NOSPLIT,$0MOVQ nr+0(FP), CXMOVQ xk+8(FP), AXMOVQ dst+16(FP), DXMOVQ src+24(FP), BXMOVUPS 0(AX), X1MOVUPS 0(BX), X0 // 读取Block到X0寄存器ADDQ $16, AXPXOR X1, X0SUBQ $12, CXJE Lenc196JB Lenc128
Lenc256:MOVUPS 0(AX), X1AESENC X1, X0MOVUPS 16(AX), X1AESENC X1, X0ADDQ $32, AX
Lenc196:MOVUPS 0(AX), X1AESENC X1, X0MOVUPS 16(AX), X1AESENC X1, X0ADDQ $32, AX
Lenc128:MOVUPS 0(AX), X1    // 读密钥到X1寄存器AESENC X1, X0       // 对Block进行AES单轮加密MOVUPS 16(AX), X1AESENC X1, X0MOVUPS 32(AX), X1AESENC X1, X0MOVUPS 48(AX), X1AESENC X1, X0MOVUPS 64(AX), X1AESENC X1, X0MOVUPS 80(AX), X1AESENC X1, X0MOVUPS 96(AX), X1AESENC X1, X0MOVUPS 112(AX), X1AESENC X1, X0MOVUPS 128(AX), X1AESENC X1, X0MOVUPS 144(AX), X1AESENCLAST X1, X0 // 最终轮加密MOVUPS X0, 0(DX)RET

可以看到,192加密比128加密多执行了两次AESENC(go源码这里jump label可能是写错了,不是196,应该是192,不过不影响逻辑正确性),而256加密又比192多执行了两次AESENC,而128加密执行了9次AESENC,最后一轮使用AESENCLAST指令完成加密。

根据公开的测试数据,intel的这项优化使AES加密过程提速30%-50%。要知道AES对称加密与RSA等非对称加密不同,常用于大块数据的加解密,这种级别的性能提升是非常显著的。

3.6. 数据大小

根据上面的描述可以看到,加解密过程都是以Block为单位进行的,而计算完成后的密文,其长度也是16字节,所以AES加密后的密文长度,就等于明文长度+Padding,所以如果需要对密文进行内存分配或存储,这是一个数据依据,在加密之前,密文长度是可预测的。

3.7. 安全

AES加密的强度,往上有很多资料,容易被忽视的一点是,加密过程本身不防篡改,对于AES来说,即使对密文进行了修改,解密过程也可以正常完成,但是解密的内容可能已经面目全非了。在业务上,这部分功能通常通过约定计算方式生成的指纹,来达到防篡改的目的。而开放加解密标准中也是通过指纹的方式来防止篡改,叫做MAC,有一些开源库支持生成MAC指纹。总之AES本身无法避免被篡改的可能。

3.8. 解密

如果理解了加密的过程,解密就是所有以上的逆运算而已。我们只要证明其可逆即可。纵观整个加密过程,运算规则有:查表映射、取异或、移位、矩阵乘法。查表的反向映射表即可完成逆运算,异或操作也是已知可逆的,移位可逆是基本常识,而矩阵乘法结果,乘其逆矩阵可以还原线性空间,所以整个加密过程可逆。

同样的,intel也提供了用于解密的AESDEC、AESDECLAST指令用于加速解密。

4. 加密模式

前面讲了,AES加解密只管Block内的事情,而加密模式管的是Block之间的关系。加密模式解决的是Block之间的混淆扩散问题,严格来讲它不属于AES的一部分,任何基于块加密的算法都可以套用这些模式。

4.1. ECB

如果仅仅是对数据应用AES加密,那么这就是ECB模式了,也就是说Block之间没有关系。

虽然在Block内是满足了SPN模型,但是同样的16字节明文块会产生同样的密文,这不满足混淆理论,而一个Block的变动,不会影响其他Block,这不满足扩散理论,所以ECB模式的加密强度显然不够高。

在一些特定领域,ECB是完全不推荐使用的,比如下面的图片数据加密对比图。原始图片中相同色块具有相等的RGB值,按Block进行加密后,产生的密文数据也是相同的,所以仍然能够通过肉眼识别出图片中的部分信息。
|

4.2. CBC

这种模式是将当前Block的明文与前一个Block的密文进行异或后,再进行当前Block的AES加密过程,对于第一个明文块,与额外输入的IV向量进行异或,其计算过程的归纳描述如下:

其中C是密文块,P是明文块,i是明文/密文块的索引,E是AES对块的加密方法,IV…它就是IV

加密过程
Ci=Ek(Pi⊕Ci−1)C0=IVC_i=E_k(P_i\oplus C_{i-1})\\ C_0=IVCi​=Ek​(Pi​⊕Ci−1​)C0​=IV

解密过程
Pi=Dk(Ci)⊕Ci−1C0=IVP_i=D_k(C_i)\oplus C_{i-1}\\ C_0=IVPi​=Dk​(Ci​)⊕Ci−1​C0​=IV

它解决了ECB的痛点,使Block之间通过异或进行混淆扩散,缺点是由于当前Block密文CiC_iCi​的计算依赖上一个Block的密文Ci−1C_{i-1}Ci−1​,所以无法进行并行AES加密计算,性能上打了折扣。

4.3. CTR

Counter模式转变了思路,这次AES不对明文进行加密了,而改为对一个数字进行加密,用加密过的内容与明文异或,产生密文。

数字由输入的IV初始化,按照Block的顺序依次递增,为每个Block分配一个数字。这样不仅使Block之间产生了关联,同时,由于AES加密的输入是预生成的数字序列,所以也可以进行并行加密,性能上较CBC也更好。

4.4. GCM

伽罗瓦计数器模式从名字上可以看出来,它还是以CTR模式为蓝本,除此之外还提供了防篡改校验。其原理是允许输入一定的自定义数据参与MAC校验码的生成。

如果你对比ECB和GCM对同样明文的加密,会发现GCM的密文比ECB的密文要长,这是因为GCM的密文中还追加了MAC指纹。这也是为什么,如果你修改了ECB的密文,解密并不会失败,只是得不到期望的值,而修改了GCM的密文,解密会失败,因为GCM解密过程中还要对MAC指纹进行校验。之所以较伽罗瓦计数器模式,就是因为在计算MAC的过程中,用到了伽罗瓦域的原理。

5. 结语

综合以上,加密模式其实跟加密算法关系不是很大,换言之只要是基于Block的加密算法,都可以使用以上这些加密模式。

所以当我们进行需要加解密的网络通信对接时,不仅需要对齐加解密的算法,还需要在加解密模式上达成共识,才能正确进行加解密。比如如果说采用AES-GCM方式,你作为解密方,需要知道对方传入的IV(工程场景一般叫做Nonce,一个随机串),还需要知道对方参与生成MAC的字段有哪些,这些字段是如何组织在一起参与MAC值计算的。

这里只介绍了比较常见的加密模式,如果有兴趣学习其他加密模式,可以查看Block cipher mode of operation这个wiki,里面有对各种加密模式的详细阐述。

6. 引用

Advenced Encryption Standard
Block cipher mode of operation
Substitution–permutation network
Confusion and diffusion
Intel® Advanced Encryption Standard (AES) New Instructions Set
什么是AES-GCM加密算法

AES加解密基本原理相关推荐

  1. C语言实现AES加解密

    C语言实现AES加解密 AES算法 具体代码 AES算法 (AES)RIJNDAEL算法是一个数据块长度盒密钥长度都可变的分组加密算法,其数据块长度和密钥长度都可独立地选定为大于等于128位且小于等于 ...

  2. Java code lib aes 加解密

    Java aes 加解密 /*** Created by LvJianwei on 2018/2/8.*/import javax.crypto.Cipher; import javax.crypto ...

  3. 数据採集器服务——Socket(今天才发现AES加解密代码跟贴的时候不一样,貌似乱码,不知什么情况)...

    近期刚做的一个项目.关于 Socket TCP 通信. 需求方提供了一个 ARM 机器,及数据採集器,须要我做一个服务端与数据採集器进行交互. 目的: 数据採集器:定时将读取到的数据发送到服务端. 服 ...

  4. 前端 crypto-js aes 加解密

    背景 前段时间公司做项目,该项目涉及到的敏感数据比较多,经过的一波讨论之后,决定前后端进行接口加密处理,采用的是 AES + BASE64 算法加密~ 网上关于 AES 对称加密的算法介绍看上一篇! ...

  5. 记一次Java AES 加解密 对应C# AES加解密 的一波三折

    最近在跟三方对接 对方采用AES加解密 作为一个资深neter Ctrl CV 是我最大的优点 所以我义正言辞的问他们要了demo java demo代码: public class EncryptD ...

  6. C语言实现AES加解密算法

    C语言实现AES加解密算法 AES加解密 AES加解密 #include <stdio.h> #include <stdint.h> #include <memory.h ...

  7. openssl c++实现bouncycastle中AES加解密

    0x01 为什么要用bouncycastle 先说说JCE(Java Cryptography Extension)是一组包,它们提供用于加密.密钥生成和协商以及 Message Authentica ...

  8. aes加密php源码,AES加解密类源码 · ThinkPHP5高阶实战教程 --诠释为API开发而生 · 看云...

    # AES加解密类源码 > 根据网络整理 ~~~ /** * Created by PhpStorm. * Power by Mikkle * QQ:776329498 * Date: 2017 ...

  9. Golang AES 加解密

    文章目录 AES 简介 AES 加解密实现 小结 参考文献 AES 简介 利用 Go 提供的 AES 加解密与 Base64 编解码包,我们可以轻松实现 AES 加解密.实现之前,首先了解一下 AES ...

最新文章

  1. 服务器安装使用rstudio-server
  2. UNITY技巧-查找脚本被哪个场景引用
  3. JavaScript入门(part4)--简单数据类型
  4. jenkins 启动_通过http请求启动jenkins任务
  5. 20-10-025-安装-KyLin-2.6.0-单机版安装(MAC官网下载)成功
  6. mysqld --initialize --console 没有 打印信息_JavaScript设计模式--装饰者模式
  7. python 近期用到的基础知识汇总(五)
  8. 从荣耀小米扎堆“滑盖全面屏”,看国产手机的“取巧”式创新
  9. xtrabackup与mysqldump对比测试
  10. 【转】12 TOP Command Examples in Linux
  11. Data Visualization [--0]
  12. 现代信号处理——自适应滤波器(匹配滤波器)
  13. 18650锂电池保护板接线图_3.7v锂电池保护板原理图
  14. 计算机考研408的算法题详解
  15. 【C#】 .NET Reflector 安装与学习
  16. 小米5 android 4.1.2,三星GALAXY NOTE i9220 Miui V5完美运行 Android4.1.2 华丽流畅体验
  17. 解决:The requested URL returned error: 403
  18. Chapter8.金融时间序列
  19. ODB 入门介绍(二)
  20. Ubunbu18.4运行代码bug提示:Successful NUMA node read from SysFS had negative value (-1)

热门文章

  1. [安装程序配置服务器失败]解决SQL Server2000安装失败
  2. python算法设计 - 汉诺塔
  3. 潭州学院html学习(day05)
  4. 输入6名学生的学号,姓名和三门课程的成绩,三门课程的名称:(programming,databse,network)。。。。。。。
  5. 南大计算机跨专业考研,GitHub - weizhang27/NJU-CS-Kaoyan: 南京大学计算机考研相关问题...
  6. python字符串及其函数
  7. Grandpa's Estate POJ - 1228(凸包极角序改写)
  8. Mifare plus卡调试总结
  9. 使用jquery制作漂亮相册集
  10. 中文电子病历实体关系抽取研究