密码2-加密模式和填充方式

2022-09-09 08:08:34

对称加密 Symmetric cryptography(DES,AES,RC4等)中,会用到各种不同的加密模式和填充方式。
参考:
加密模式:
https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
http://www.cnblogs.com/mafeng/p/6251207.html
填充方式:
https://en.wikipedia.org/wiki/Padding_(cryptography)

AES-128 算法,是目前最常用的加密算法。
每种加密算法的密钥长度和支持的模式有所不同,列表如下:

算法名称密钥长度 (位 / 字节)支持的模式
AES-128 / Rijndael-128128 / 16CBC, CTR, CFB, CFB8, OFB, ECB
AES-192192 / 24CBC, CTR, CFB, CFB8, OFB, ECB
AES-256256 / 32CBC, CTR, CFB, CFB8, OFB, ECB
DES56 / 7CBC, CFB, CFB8, OFB, ECB
TripleDES56 / 7, 112 / 14, 168 / 21CBC, CFB, CFB8, OFB
Blowfish128-448 / 16-56CBC, CFB, OFB, ECB
CAST5 / CAST-12888-128 / 11-16CBC, CFB, OFB, ECB
RC4 / ARCFour40-2048 / 5-256Stream

1 加密模式

模式名称支持的 PHP 驱动备注
CBCMCrypt, OpenSSL安全的默认选择
CTRMCrypt, OpenSSL理论上比 CBC 更好,但并没有广泛使用
ECBMCrypt, OpenSSL忽略 IV(initialization vector,初始化向量) (不推荐)
CFBMCrypt, OpenSSL
CFB8MCrypt, OpenSSL和 CFB 一样,但是使用 8 位模式(不推荐)
OFBMCrypt, OpenSSLN/A
OFB8MCrypt和 OFB 一样,但是使用 8 位模式(不推荐)
XTSOpenSSL通常用来加密可随机访问的数据,如 RAM 或 硬盘
StreamMCrypt, OpenSSL这其实并不是一种模式,只是表明使用了流加密,通常在 算法+模式 的初始化过程中会用到。

PHP 7.1 版本之后,废弃了 MCrypt,所有的加解密请使用 OpenSSL。OpenSSL 文档参考这里

不同算法在不同模式下,数据加密后的长度

算法/模式/填充16字节加密后数据长度不满16字节加密后长度
AES/CBC/NoPadding16不支持
AES/CBC/PKCS5Padding3216
AES/CBC/ISO10126Padding3216
AES/CFB/NoPadding16原始数据长度
AES/CFB/PKCS5Padding3216
AES/CFB/ISO10126Padding3216
AES/ECB/NoPadding16不支持
AES/ECB/PKCS5Padding3216
AES/ECB/ISO10126Padding3216
AES/OFB/NoPadding16原始数据长度
AES/OFB/PKCS5Padding3216
AES/OFB/ISO10126Padding3216

1.1 电子密码本模式ECB

将加密的数据分成若干组,每组的大小跟加密密钥长度相同。然后每组都用相同的算法和密钥加密, 比如DES算法。如果最后一个分组长度不够64位,需要填充。

特点:

  • 每次Key、明文、密文的长度都必须是64位。
  • 一个错误仅仅会对一个密文块产生影响。
  • 相同的明文块被加密成相同的密文块,不能隐藏加密模式。容易受重放攻击。

1.2 密码分组链模式CBC

CBC一直是最常用的操作模式,和ECB相比,加入了初始向量IV。
在CBC模式下,在加密之前,每个明文块与先前的密文块进行异或。 这样,每个密文块依赖于直到那一点处理的所有明文块。 为了使每个消息唯一,必须在第一个块中使用初始化向量。

特点:

  • 每次加密的密文长度为64位
  • 加密是连续的(即它不能并行化),并且消息必须被填充到密码块大小的倍数。
  • 明文或IV中的一位变化影响所有以下密文块,一个错误会影响当前和以后的密文。
  • 当相同的明文使用相同的密钥和初始向量的时候CBC模式总是产生相同的密文。
  • 可以使用不同的初始化向量来避免相同的明文产生相同的密文,一定程度上抵抗字典攻击。
  • 使用不正确的IV解密导致第一个明文块被破坏,但后来的明文块将是正确的。这是因为每个块与前一个块的密文进行异或,而不是明文,因此在将其用作当前解密之前不需要解密前一个块。这意味着可以从两个相邻的密文块中恢复明文块。因此,解密可以并行化。请注意,对密文进行一位更改会导致相应的明文块的完全损坏,并将在下一个明文块中的相应位进行反转,但其余块保持不变。显式初始化向量通过在明文前面加上单个随机块来利用该属性。加密是正常的,除了IV不需要传送到解密例程之外。无论IV解密使用什么,只有随机块“被破坏”。它可以被安全地丢弃,其余的解密是原始的明文。

1.3 加密反馈模式CFB

使块密码成为自同步流密码。 操作非常相似; 特别是,CFB解密与反向执行的CBC加密几乎相同:
特点:

  • 每次加密的明文和密文长度不大于64bit。
  • 一旦某位数据出错,只影响部分数据。

1.4 输出反馈模式OFB

1.5 对比

ECB是不推荐的方式,Key相同时,相同的明文在不同的时候产生相同的明文,容易遭到字典攻击。
CBC由于加入了向量参数,一定程度上抵御了字典工具,但缺点也随之而来,一旦中间一个数据出错或丢失,后面的数据将受到影响。
CFB与CBC类似,好处是明文和密文不用是8bit的整数倍,中间一个数据出错,只影响后面的几个块的数据。
OFB比CFB方式,一旦一个数据出错,不会影响后面的数据,但安全性降低。

2 初始向量IV(Initialization vector)

初始化向量用于确保即使相同的明文被相同密钥独立地多次加密也可以产生不同的密文。
大多数加密模式需要一个唯一的二进制序列,通常称为初始化向量(IV),用于每个加密操作。 IV必须是不重复的,对于某些模式也是随机的。
在大多数情况下,初始化向量最好不要在同一个密钥下重复使用。对于CBC和CFB,重用IV会泄漏关于第一个明文块的一些信息,以及两个消息共享的任何公共前缀。对于OFB和CTR,重用IV彻底破坏了安全性。

3 填充方式(Padding)

某些模式(即ECB和CBC)要求在加密之前填补最终的块。存在几种填充方案。最简单的是将空字节添加到明文中以使其长度达到块大小的倍数,但必须注意可以恢复明文的原始长度,如果明文是一个C风格的字符串,除了最后不包含空字节。稍微复杂一点就是添加一个置一位,后面加上足够的零位来填写块。如果消息在块边界上结束,则将添加整个填充块。
CFB,OFB和CTR模式不需要任何特殊措施来处理长度不是块大小倍数的消息,因为这些模式通过将明文与块密码的输出进行异或工作。最后的部分明文块与最后一个密钥流块的前几个字节进行异或,产生与最终部分明文块大小相同的最终密文块。流密码的这种特性使得它们适用于需要加密密文数据与原始明文数据相同大小的应用程序,以及用于以不方便添加填充字节的流式传输数据的应用程序。

3.1 PKCS#7

PKCS(Public-Key Cryptography Standards)。
PKCS5的分组大小固定为 64 位(8字节),而PKCS7的分组大小可以是1到255字节。如果加密操作的分组大小为 64 位(8字节)时,PKCS5 同 PKCS7 填充结果一致。比如DES加密,分组长度64位,此时用PKCS5或PKCS7加密结果一样。
填充是整数字节。 每个添加的字节的值是添加的字节数,即N个字节,每个值N被添加。 添加的字节数将取决于消息需要扩展到的块边界。

填充将是以下之一:

01
02 02
03 03 03
04 04 04 04
05 05 05 05 05
06 06 06 06 06 06
etc.

示例:在以下示例中,块大小为8字节,4字节需要填充
... | DD DD DD DD DD DD DD DD | DD DD DD DD 04 04 04 04 |

3.2位填充

位填充可以应用于任何大小的消息。
填充时,第一个位填充1,其他所有位(可能没有)填充0。
位填充是在许多散列函数(包括MD5和SHA)中使用的两步填充方案的第一步。

3.3 字节填充

可以应用于可以编码为整数字节的消息。

3.4 ISO 10126

ISO 10126规定填充应在最后一个块的末尾用随机字节完成,填充边界应由最后一个字节指定。

示例:在以下示例中,块大小为8字节,4字节需要填充
... | DD DD DD DD DD DD DD DD | DD DD DD DD 81 A6 23 04 |

3.5 ISO / IEC 7816-4

与位填充方案相同,适用于N字节的纯文本。 这意味着在实践中,第一个字节是值为“80”(十六进制)的必填字节,如果需要,则0到N-1个字节设置为’00’,直到达到块的结尾。 ISO / IEC 7816-4本身是包含文件系统的智能卡的通信标准,本身不包含任何加密规范。

示例:在以下示例中,块大小为8字节,4字节需要填充
... | DD DD DD DD DD DD DD DD | DD DD DD DD 80 00 00 00 |

3.6 零填充

需要填充的所有字节都用零填充。
如果原始文件以一个或多个零字节结束,则零填充可能不可逆,这使得无法区分明文数据字节和填充字节。 当消息的长度可以在带外导出时,可以使用它。 它通常应用于二进制编码的字符串,因为空字符通常可以作为空白来剥离。

示例:在以下示例中,块大小为8字节,4字节需要填充
... | DD DD DD DD DD DD DD DD | DD DD DD DD 00 00 00 00 |

  • 作者:kikajack
  • 原文链接:https://blog.csdn.net/kikajack/article/details/78329567
    更新时间:2022-09-09 08:08:34