与加密算法一起使用的字节顺序是否会影响其安全性?

信息安全 加密 AES 二进制代码
2021-09-07 22:34:54

我正在实现 AES 块密码,它以 16 字节块读取/写入数据。我正在使用的实现通常以小端格式读取数据。但是在我的平台中,我使用的字节序是“网络顺序”大字节序。我可以使用 BE 作为加密算法吗?字节序通常会改变算法的工作方式吗?这有关系吗?我认为不是,因为它可能只是您正在阅读的不同数据。

3个回答

首先,让我们确保我们得到字节顺序:

// needs a C99 compiler like gcc. Will work with msvc as well.
#include <stdint.h>
#include <stdio.h>

union endian_test
{
    struct 
    {
        uint8_t a;
        uint8_t b;
        uint8_t c;
        uint8_t d;
    };
    uint32_t x;
};


int main(int argc, char** argv)
{
    union endian_test e;
    e.x = 0xAABBCCDD;
    printf("%x %x %x %x", e.a, e.b, e.c, e.d);
}

如果你的系统是小端,你会得到 DD CC BB AA 作为输出,而大端会给你相反的结果。我们在这里所做的只是让处理器有机会以它使用的任何字节顺序来表示一个整数,然后使用一个小 C 技巧来按照它们在内存中表示的顺序输出字节。

AES 适用于 128 位块,这确实很方便,因为如果将该联合中的所有字段大小乘以 4,您将得到一个 AES 输入块。

所以现在你的问题归结为:

如果我要颠倒我的块的输入顺序,那会产生安全问题吗?

嗯,这取决于输出。让我们假设一些天真的事情,比如颠倒输入的顺序会产生一个颠倒的密文,所以如果输入是加密为 12345678 的 AABBCCDD,而 DDCCBBAA 加密为 78563412。

这是一类称为CCA2的加密漏洞或选择的自适应密文攻击的问题。由于密文是可延展的,因此您可以请求执行各种解密操作,虽然您不知道明文,但您可以推断出一些关于它的信息。您可能想阅读一些关于密文不可区分性的内容。

因此,加密方案不应受到字节顺序的影响。如果它是可延展的,它有一些可能需要解决的安全问题(并且在某些实现中,例如,通过不提供解密预言)。

AES 被定义为在 16 字节块上运行。这样的块是一个有序的字节序列:有第一个字节,第二个字节,依此类推,直到第十六个字节。我们经常说第一个字节最左边,最后一个字节最右边,因为我们是西方人,使用拉丁字母,从左到右书写,我们只是盲目地和隐含地假设从右到左书写的人是错误的.

字节序是关于将字节序列解释为整数值;例如,四个字节的序列,解释为 0 到 4294967295 之间的整数。要进行这样的解释,我们决定一个字节用于单位(我们将其数值乘以 1),另一个用于乘以256,另一个 65536(即 256*256),还有一个 16777216(即 256*256*256)。Little-endian 约定是指单位字节在前,然后是值 256 的字节,然后是值 65536 的字节,最后是值 16777216 的字节。Big -endian 约定是字节顺序相反的情况。

在 AES 中,没有将字节序列解释为更大的整数,因此不适用字节顺序。然而,即使对于确实涉及将字节序列解释为整数的算法,算法规范也定义了要使用的字节序。然后由实现来遵循定义的约定,无论它是否符合 CPU 的最佳表现。例如,在散列函数MD5中,输入消息(字节序列)经过填充后被拆分为 64 字节块,每个块被拆分为 16 个 4 字节序列,每个序列被解释为整数小端约定. MD5是MD5;它是确定性的,它对给定输入文件的输出不应取决于计算机是否使用 x86、ARM、PowerPC 或 Sparc CPU。因此,在大端 CPU 上运行的实现必须包括必要的字节交换步骤才能正确进行计算。

补充三点:

  • 字节序对性能的重要性被高估了。即使对于非常快的 MD5(在我的计算机上,它每秒处理超过 400 兆字节),大端 CPU 的字节交换意味着不超过 15% 的开销。这就是为什么通常的 SHA-1 / SHA-256 散列函数可以使用 big-endian 约定(这就是它们的定义方式),这与基本 PC 本身所做的相反,它仍然不是一个大问题。

  • 如果你的 C 代码必须知道字节顺序,那么它做错了。不是字节序中性的 C 代码是 C 代码,它访问相同的内存对象作为字节串整数。此类代码违反了严格的别名规则,这意味着当使用不同的编译器版本或不同的编译器选项编译时,代码可能会停止正常运行。这是草率的编程。

  • 除了 little-endian 和 big-endian 之外,还存在其他约定,通常称为mixed-endian这些大部分都消失了。然而,大端和小端架构仍在蓬勃发展,因此,仅出于可移植性考虑,代码应该是端中立的。

AES 适用于字节序列。您应该做的第一件事是将字节转换为规范的字节顺序,然后您可以进行解密。应在应用程序中使用应用程序数据进行加密。换句话说,您应该在比加密更低的抽象层更正字节顺序。