【问题标题】:Speed of AES ImplementationAES 实施的速度
【发布时间】:2021-02-14 19:22:14
【问题描述】:

我已经编写了 AES 的 C 实现,并试图使其尽可能快(我刚开始编程并接受过 IT 培训)。 到目前为止,我已经实现了大约 600% 的速度提升,但速度仍然非常缓慢。为了将我的 AES 实现与我在 Linux 终端中使用的“openssl speed”命令进行比较。在 3 秒内,此实现加密了大约 36 977 043 个块(16 字节)。我比有点糟糕的慢约 25 倍(36 个字节为 72 秒)。我对两件事感到好奇。

  1. 什么是一个好的目标,实现一个现实的目标有多快。
  2. 为什么我的代码这么慢,我该如何改变它。

我的代码: 我试图省略我的一些函数,所以看看没有它们代码会多快。 完整代码耗时 72 秒。

  • 没有 Mixcolumns 14 秒 #这是一个大问题
  • 没有 Shiftrows 67 秒
  • 无子字节 61 秒

我的加密功能:

uint32_t * encrypt(uint32_t * expkey,uint32_t state[4]){

    uint32_t temp[4];

    state[0] = state[0] ^ expkey[0];
    state[1] = state[1] ^ expkey[1];
    state[2] = state[2] ^ expkey[2];
    state[3] = state[3] ^ expkey[3];
    
    for(int round = 1; round < Nr; round++){
        
        // Subbytes
        for (int c = 0; c < 4;c++){
            temp[c] = ((sbox[state[c] >> 24 & 0xFF]) << 24 ) + ((sbox[state[c] >> 16 & 0xFF]) << 16 ) + ((sbox[state[c] >> 8 & 0xFF]) << 8 ) + (sbox[state[c] & 0xFF]);
        }
        // Shiftrows
        state[0] = (((temp[0] >> 24) & 0xFF) << 24) + (((temp[1] >> 16) & 0xFF) << 16) + (((temp[2] >> 8) & 0xFF) << 8) + (temp[3] & 0xFF);
        state[1] = (((temp[1] >> 24) & 0xFF) << 24) + (((temp[2] >> 16) & 0xFF) << 16) + (((temp[3] >> 8) & 0xFF) << 8) + (temp[0] & 0xFF);
        state[2] = (((temp[2] >> 24) & 0xFF) << 24) + (((temp[3] >> 16) & 0xFF) << 16) + (((temp[0] >> 8) & 0xFF) << 8) + (temp[1] & 0xFF);
        state[3] = (((temp[3] >> 24) & 0xFF) << 24) + (((temp[0] >> 16) & 0xFF) << 16) + (((temp[1] >> 8) & 0xFF) << 8) + (temp[2] & 0xFF);
        
        // Mixcolums
        for (int c = 0; c < 4;c++){
            state[c] = 
                ((xtime((state[c] >> 24) & 0xFF) ^ xtime3((state[c] >> 16) & 0xFF) ^ ((state[c] >> 8) & 0xFF) ^ (state[c] & 0xFF)) << 24) +
                ((((state[c] >> 24) & 0xFF) ^ xtime((state[c] >> 16) & 0xFF) ^ xtime3((state[c] >> 8) & 0xFF) ^ (state[c] & 0xFF)) << 16) + 
                ((((state[c] >> 24) & 0xFF) ^ ((state[c] >> 16) & 0xFF) ^ xtime((state[c] >> 8) & 0xFF) ^ xtime3(state[c] & 0xFF)) << 8 ) +
                (xtime3((state[c] >> 24) & 0xFF) ^ ((state[c] >> 16) & 0xFF) ^ ((state[c] >> 8) & 0xFF) ^ xtime(state[c] & 0xFF));       
        
        }
        // Add Key
        state[0] = state[0] ^ expkey[round * 4];
        state[1] = state[1] ^ expkey[round * 4 + 1];
        state[2] = state[2] ^ expkey[round * 4 + 2];
        state[3] = state[3] ^ expkey[round * 4 + 3];
        
        }
        // Last Subbytes
        for (int c = 0; c < 4;c++){
            temp[c] = ((sbox[state[c] >> 24 & 0xFF]) << 24 ) + ((sbox[state[c] >> 16 & 0xFF]) << 16 ) + ((sbox[state[c] >> 8 & 0xFF]) << 8 ) + (sbox[state[c] & 0xFF]);
        }
        */
        // Last Shiftrow
        state[0] = (((temp[0] >> 24) & 0xFF) << 24) + (((temp[1] >> 16) & 0xFF) << 16) + (((temp[2] >> 8) & 0xFF) << 8) + (temp[3] & 0xFF);
        state[1] = (((temp[1] >> 24) & 0xFF) << 24) + (((temp[2] >> 16) & 0xFF) << 16) + (((temp[3] >> 8) & 0xFF) << 8) + (temp[0] & 0xFF);
        state[2] = (((temp[2] >> 24) & 0xFF) << 24) + (((temp[3] >> 16) & 0xFF) << 16) + (((temp[0] >> 8) & 0xFF) << 8) + (temp[1] & 0xFF);
        state[3] = (((temp[3] >> 24) & 0xFF) << 24) + (((temp[0] >> 16) & 0xFF) << 16) + (((temp[1] >> 8) & 0xFF) << 8) + (temp[2] & 0xFF);
        
        // Last Add Key
        state[0] = state[0] ^ expkey[Nr * 4];
        state[1] = state[1] ^ expkey[Nr * 4 + 1];
        state[2] = state[2] ^ expkey[Nr * 4 + 2];
        state[3] = state[3] ^ expkey[Nr * 4 + 3];
        
        return state;
}

还有xtime函数:

uint8_t xtime(uint8_t x){
    return (x << 1) ^ (0x11b & -(x >> 7));
}

我期待所有提示技巧和改进。

【问题讨论】:

  • 寻求有关工作代码的反馈(包括性能改进)的问题将更适合Code Review
  • 首先,你确定openssl是在用户空间加密的吗?如果它使用 AES-NI 指令,就可以解释为什么它至少快 10 倍。
  • @Cheatah:为什么你认为用户空间是相关的? AES 指令只对数据进行操作;他们没有特权。

标签: c performance encryption aes


【解决方案1】:

OpenSSL 在可用的情况下使用 AES-NI。

openssl speed -evp aes-128-cbc

和输出


The 'numbers' are in 1000s of bytes per second processed.
type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes  16384 bytes
aes-128-cbc    531549.19k   969335.21k  1045437.10k  1066826.75k  1054665.39k  1052120.41k

由于您没有使用 AES-NI,因此您需要将其与软件版本进行比较

 OPENSSL_ia32cap=”~0x200000200000000″ openssl speed -elapsed -evp aes-128-cbc

The 'numbers' are in 1000s of bytes per second processed.
type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes  16384 bytes
aes-128-cbc    143802.75k   161369.51k   165049.17k   166054.57k   166262.10k   166461.44k

如果我们比较最后一列,您会发现 AES-NI 比 OpenSSL 的软件版本快约 6.3 倍。这意味着您的速度比软件版本慢 4 倍左右。

在很多情况下,编译器优化参数也会影响速度。查看编译器的手册,如果您使用的是 GCC,那么它们是 -O[0..3]


关于代码;

如果您查看 OpenSSL 的 AES 代码,您会发现它们使用 pre-computed tables,这是一种非常常见的技术。

SubytesShiftrowsMixColums 被转换为查表。速度差就是这些。并不是说表查找容易受到cache-timing attacks 的攻击。

【讨论】:

  • 不是您问题的确切答案,但是,这应该在您的脑海中。
【解决方案2】:

你必须优化代码。

  1. 有不必要的转变>。 你可以简单的面具。 替换代码如下:

= (temp[0] &gt;&gt; 24) &amp; 0xFF) &lt;&lt; 24) + (((temp[1] &gt;&gt; 16) &amp; 0xFF) &lt;&lt; 16) + (((temp[2] &gt;&gt; 8) &amp; 0xFF) &lt;&lt; 8) + (temp[3] &amp; 0xFF);

使用如下代码:

= (temp[0] &amp; 0xFF000000) + (temp[1] &amp; 0x00FF0000) + (temp[2] &amp; 0x0000FF00) &lt;&lt; 8) + (temp[3] &amp; 0xFF);

  1. 替换这个:

^ expkey[Nr * 4 ];
^ expkey[Nr * 4 + 1];
^ expkey[Nr * 4 + 2];
^ expkey[Nr * 4 + 3];

用这个:

ptr = expkey + (Nr

^ ptr[0];
^ ptr[1];
^ ptr[2];
^ ptr[3];

这样你将消除大量的计算

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-04
    • 1970-01-01
    相关资源
    最近更新 更多