分组密码的工作模式

了解一点密码学的都知道, 对称密码算法只有一个密钥, 加密解密都用同一个密钥. 最常见的AES就属于对称密码. 写成伪代码就是 密码 = AES加密(密钥, 明文). 但是到实际应用的代码的时候, 就会发现AES的加解密库还要求提供其他的一些参数: 其中工作模式(mode)是必填, 这参数是啥, 本文就讨论一下这个问题.

电子密码本(ECB)

AES是分组密码, 也就是明文要先分组, 每组128bit, 然后再对每一组明文加密, 输出密文. 按着这个最基本的思想, 就得到第一种工作模式, 电子密码本(ECB)模式.

ECB模式加密步骤如下

  1. 明文分组为P1, P2, P3…
  2. 对每一组明文分别用密钥进行加密, 得到密文C1, C2, C3…

ECB模式是最简单的, 但它也存在一个明显的问题: 相同的明文分组会生成相同的密文分组. 这在一些场景中可以通过分析密文就可以道到原始明文的一些规率, 例如说包含较多单一色块的图片, 用ECB模式加密后仍然可以辨认出原始图片的一些轮廓.

密码分组链接(CBC)

为了解决ECB的这个问题, 研究人员提出了密码分组链接(CBC)模式. 因为加密算法是个确定性的算法, 也就是不包含随机性的, 相同输入必定产生相同输出的. 要对相同明文产生不同的密文, 就需要引入随机的参数, 这个参数就是初始向量(iv).

CBC模式加密步骤如下

  1. 明文分组为P1, P2, P3…
  2. 生成一个128bit(等于一个分组的大小)的随机数作为iv
  3. iv 与 P1 异或, 得到 M1
  4. 使用密钥加密M1, 得到密文C1
  5. C1 与 P2 异或, 得到 M2
  6. 使用密钥加密M2, 得到密文C2
  7. 重复5和6的步骤, 直到所有明文使用完毕

CBC第一个分组使用了一个随机的iv进行异或计算, 然后再加密, 只要每次使用的iv都不一样, 得到的第一组密文就是不一样的, 然后后面每一个分组的明文都先与上一组的密文做了异或, 再进行加密, 这样由iv所带来的随机性就像链条一样一组一组往后传播, 使得每一组密文都变得不可预测. 这就是"密码分组链接"这个词的由来.

CBC模式的密文解密不只需要密钥, 还需要知道iv才可以完整解密, 因此, 通信双方需要先约定iv的值. iv通常不需要保密, 可以直接明文传输. 如果是对磁盘文件做加密, iv也需要保存下来.

输出反馈(OFB)模式

AES是分组密码, 加密的数据长度必须要是规定的分组长度的整倍数才能进行, 数据并不总能填满一个分组的, 需要对不满一个分组的数据做加密. 这种情况下有两种解决方案, 一种是对数据进行填充, 把长度填充到规定的分组长度的整倍数. 另一种是用序列密码, 序列密码是对数据的每一位做加密, 对数据长度没有要求的. 输出反馈(OFB)模式就是把分组密码作为序列密码使用的一种方式.

OFB模式加密步骤如下:

  1. 明文分组为P1, P2, P3…
  2. 生成一个128bit(等于一个分组的大小)的随机数作为iv
  3. 使用密钥加密iv, 得到加密序列E1
  4. E1 与 P1 异或, 得到密文C1
  5. 使用密钥加密E1, 得到加密序列E2
  6. E2 与 P2 异或, 得到密文C2
  7. 重复步骤5和6, 直到明文使用完毕

OFB模式的是以iv做为随机性的种子, 生成一段与明文等长的加密序列, 然后逐个bit与明文做异或, 得到与明文等长的密文. 从这个过程可以看出, 加密序列的生成与明文是无关的, 只取决于iv, 因此, 加密序列可以预先生成, 而不必等待明文准备好.

OFB模式适合于流加密, 因为加密序列可以预先生成, 明文每出现一个bit, 立即就可以加密一个bit, 而且密文和明文长度完全相等. OFB模式每一个bit的加密结果都对其他bit没有影响, 在传输有可能出错的场合, 这个特性是很有用的. 例如如音视频流的加密, 如果密文传输过程中有少数的几个bit出错, 在解密后, 这些错误只会影响明文对应的那几个bit, 其他数据不受影响, 整个音视频还是基本能用的.

但是在另外的一些场合, 人们可能会希望一个bit的错误会引起明显的后果, 密文反馈(CFB)模式就有这种效果.

密文反馈(CFB)模式

CFB模式和OFB模式一样, 是把分组密码作为序列密码使用的一种方式.

CFB模式加密步骤如下:

  1. 明文分组为P1, P2, P3…
  2. 生成一个128bit(等于一个分组的大小)的随机数作为iv
  3. 使用密钥加密iv, 得到加密序列 E1
  4. 使用 E1 与 P1 异或, 生成密文 P1
  5. 使用密钥加密P1, 得到加密序列 E2
  6. 使用 E2 与 P2 异或, 生成密文 P2
  7. 重复步骤5和6, 直至所有明文使用完毕

OFB的加密序列生成不依赖明文, 可以无限长度预先生成, CFB则相反, 每一组加密序列的生成都依赖于上一组密文, 因此需要依赖上一组的明文, 不能预先生成无限长度的加密序列, 而只能生成一个分组的加密序列.

在最后一个分组, 由于步骤5的加密序列已经生成好, 步骤6仅仅是一个简单的按位异或, 因此只需要截取与最后一组明文相同长度的加密序列与明文进行计算即可, 不需要填充, 所以CFB密文长度也是和明文等长的.

CFB模式的每分组的密文会用于下一个分组的密钥生成, 因此如果密文的某一个bit错误, 由于AES算法的扩散性, 就会导致下一个分组的解密结果完全错误.

明文密码分组链接(PCBC)模式

CBC和CFB模式下, 如下密文发生一个bit的错误, 会影响邻近的两个块的解密结果出错, 影响范围有限. 如果想要错误的影响范围更大, 就可以用PCBC模式.

PCBC模式加密步骤如下:

  1. 明文分组为P1, P2, P3…
  2. 生成一个128bit(等于一个分组的大小)的随机数作为iv
  3. iv 与 P1 异或, 得到 M1
  4. 使用密钥加密M1, 得到密文C1
  5. C1 和 P1 和 P2 异或, 得到 M2
  6. 使用密钥加密M2, 得到密文C2
  7. 重复5和6的步骤, 直到所有明文使用完毕

PCBC模式与CBC模式区别在于步骤5, 对第二组明文加密前, 不只第一组的密文参与异或, 第一组的明文也参与异或, 这种做法导致密文中某个一bit的错误会引起后续所有分组的解密结果都出错, 使得错误变得非常明显.

计数器(CTR)模式

上述的OFB和CFB模式都可以把分组密码作为序列密码使用, 但是它们都有存在的问题是, 在加密序列的生成过程中, 每一个分组都依赖上一个分组的计算结果, 也就是下一个分组必须等待上一个分组计算完成后才可以开始计算, 这样就没法并行计算, 没法充分现代多核CPU的计算能力. CTR模式就是可以一种可以并行计算的工作模式.

CTR模式加密步骤如下:

  1. 明文分组为P1, P2, P3…
  2. 生成一个128bit(等于一个分组的大小)的随机数作为iv, 设置计数器Counter=0
  3. 使用密钥加密iv, 得到加密序列 E1
  4. 使用 E1 与 P1 异或, 生成密文 P1
  5. Count自增1
  6. 使用密钥加密(iv + Counter), 得到加密序列 E2
  7. 使用 E2 与 P2 异或, 生成密文 P2
  8. 重复步骤5,6,7, 直至所有明文使用完毕

由CTR的加密步骤可以看出, 只要知道iv和分组的序号, 就可以独立计算出该分组的加密序列, 而不依赖其他分组的加密计算结果. 因此多核的CPU可以同时进行多个分组的加解密计算, 提高效率. 这个特性对于磁盘上的随机存取文件也很友好, 只要计算出分组序号就可以对加密文件中间的某一段做单独解密, 而不需要从头开始把整个文件解密才能读取中间的一段.