【问题标题】:Segmentation fault for AES 192, AES-256 , not for AES-128 bitAES 192、AES-256 的分段错误,不适用于 AES-128 位
【发布时间】:2016-06-20 07:14:33
【问题描述】:

我正在尝试使用具有不同密钥大小的 openssl 的 AES_decrypt 函数解密密文。我成功地解密了密钥大小 = 128 的消息。 这是我的代码

mydecrypt.c

#include <stdio.h>
#include "AES.h"
#include "string.h"
#include "stdlib.h"

#define NO_OF_DECRYPTION 50

static const unsigned char key[]={
0x8E,0xa1,0xeE,0xce,0x5F,0xEB,0x1E,0x8d,0xa5,0xdA,0x95,0x57,0xD0,0x77,0xee,0xd8,0x49,0xfc,0xBd,0x2d,0x0D,0xF0,0x40,0x35,0xd3,0xd8,0x07,0x8f,0xce,0xFD,0x24,0xaF
};     

int main(int argc, char *argv[])
{
    unsigned char *text = (unsigned char *)malloc(16*sizeof(char));;
    unsigned char out[20]; 
    unsigned char * input = (unsigned char *)malloc(NO_OF_DECRYPTION*16*sizeof(char)); 

    FILE *myfile;
    myfile = fopen("encrypted.bin", "r");
    fread(input, sizeof(char), NO_OF_DECRYPTION*16, myfile);

    AES_KEY wctx;
    int aes_counter=0;
    private_AES_set_decrypt_key(key, 128, &wctx);   // keysize = 192, 256 causes segmentation fault
    printf("AES Decryption started\n");     

    while(aes_counter<NO_OF_DECRYPTION)
    {
        text = &input[aes_counter*16];
        AES_decrypt(text, out, &wctx);
        aes_counter++;
    }
    printf("AES Decryption finished\n");        
    fclose(myfile);

return 0;
}

我已经复制了openssl文件的aes_core.c(重命名为AES.c)、aes.h(重命名为AES.h),并创建了我自己的共享库来运行上述代码。

//AES.h

#include <stdint.h>

#ifndef AES_h__
#define AES_h__

typedef uint8_t     u8;
typedef uint16_t    u16;
typedef uint32_t    u32;

struct aes_key_st {
    unsigned int rd_key[4 *(10 + 1)];
    int rounds;
};
typedef struct aes_key_st AES_KEY;

extern int private_AES_set_decrypt_key(const unsigned char *userKey, const int bits,AES_KEY *key);
extern void AES_decrypt(const unsigned char *in, unsigned char *out,const AES_KEY *key);

#endif  // foo_h__

这是我编译代码以成功运行 keysize=128 位的方法。

gcc -c -Wall -Werror -fPIC -O0 AES.c
gcc -shared -o libAES.so AES.o
var=`pwd`
gcc -std=gnu89 -g -L$var -O0 -Wall -o dec mydecrypt.c -lAES -fPIC
LD_LIBRARY_PATH=$var:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH=$var:$LD_LIBRARY_PATH
#run 
./dec   

虽然我能够使用 key_size=128 的 AES_key 加密明文和解密密文,但是对于其他密钥大小 192 和 256,我遇到分段错误。

private_AES_set_decrypt_key(key, 192, &amp;wctx); 没有产生分段错误

但是,private_AES_set_decrypt_key(key, 256, &amp;wctx); 正在生成分段错误

对于 key-size=192 和 key-size=256, AES_decrypt() 正在生成分段错误

key-size 192 和 256 出现分段错误的原因是什么?

我哪里出错了?

任何运行代码以使用 key-size=192/256 解密的建议/线索都会有很大帮助。

我在 Debian 8 中使用 gcc-4.9.2。提前致谢。

注意: 用于加密,key-size=128

AES_set_encrypt_key((const unsigned char *)key, 128, &enc_key);

不会导致任何分段错误,但是

AES_set_encrypt_key((const unsigned char *)key, 192, &enc_key);
AES_set_encrypt_key((const unsigned char *)key, 256, &enc_key);

两者都会导致分段错误。

定义了 private_AES_set_decrypt_key 和 private_AES_set_encrypt_key 的 AES.c 的一部分

/**
 * Expand the cipher key into the encryption key schedule.
 */
int private_AES_set_encrypt_key(const unsigned char *userKey, const int bits,
                                AES_KEY *key)
{
    u32 *rk;
    int i = 0;
    u32 temp;

    if (!userKey || !key)
        return -1;
    if (bits != 128 && bits != 192 && bits != 256)
        return -2;

    rk = key->rd_key;

    if (bits==128)
        key->rounds = 10;
    else if (bits==192)
        key->rounds = 12;
    else
        key->rounds = 14;

    rk[0] = GETU32(userKey     );
    rk[1] = GETU32(userKey +  4);
    rk[2] = GETU32(userKey +  8);
    rk[3] = GETU32(userKey + 12);
    if (bits == 128) {
        while (1) {
            temp  = rk[3];
            rk[4] = rk[0] ^
                ((u32)Te4[(temp >> 16) & 0xff] << 24) ^
                ((u32)Te4[(temp >>  8) & 0xff] << 16) ^
                ((u32)Te4[(temp      ) & 0xff] << 8) ^
                ((u32)Te4[(temp >> 24)       ]) ^
                rcon[i];
            rk[5] = rk[1] ^ rk[4];
            rk[6] = rk[2] ^ rk[5];
            rk[7] = rk[3] ^ rk[6];
            if (++i == 10) {
                return 0;
            }
            rk += 4;
        }
    }
    rk[4] = GETU32(userKey + 16);
    rk[5] = GETU32(userKey + 20);
    if (bits == 192) {
        while (1) {
            temp = rk[ 5];
            rk[ 6] = rk[ 0] ^
                ((u32)Te4[(temp >> 16) & 0xff] << 24) ^
                ((u32)Te4[(temp >>  8) & 0xff] << 16) ^
                ((u32)Te4[(temp      ) & 0xff] << 8) ^
                ((u32)Te4[(temp >> 24)       ]) ^
                rcon[i];
            rk[ 7] = rk[ 1] ^ rk[ 6];
            rk[ 8] = rk[ 2] ^ rk[ 7];
            rk[ 9] = rk[ 3] ^ rk[ 8];
            if (++i == 8) {
                return 0;
            }
            rk[10] = rk[ 4] ^ rk[ 9];
            rk[11] = rk[ 5] ^ rk[10];
            rk += 6;
        }
    }
    rk[6] = GETU32(userKey + 24);
    rk[7] = GETU32(userKey + 28);
    if (bits == 256) {
        while (1) {
            temp = rk[ 7];
            rk[ 8] = rk[ 0] ^
                ((u32)Te4[(temp >> 16) & 0xff] << 24) ^
                ((u32)Te4[(temp >>  8) & 0xff] << 16) ^
                ((u32)Te4[(temp      ) & 0xff] << 8) ^
                ((u32)Te4[(temp >> 24)       ]) ^
                rcon[i];
            rk[ 9] = rk[ 1] ^ rk[ 8];
            rk[10] = rk[ 2] ^ rk[ 9];
            rk[11] = rk[ 3] ^ rk[10];
            if (++i == 7) {
                return 0;
            }
            temp = rk[11];
            rk[12] = rk[ 4] ^
                ((u32)Te4[(temp >> 24)       ] << 24) ^
                ((u32)Te4[(temp >> 16) & 0xff] << 16) ^
                ((u32)Te4[(temp >>  8) & 0xff] << 8) ^
                ((u32)Te4[(temp      ) & 0xff]);
            rk[13] = rk[ 5] ^ rk[12];
            rk[14] = rk[ 6] ^ rk[13];
            rk[15] = rk[ 7] ^ rk[14];

            rk += 8;
        }
    }
    return 0;
}

/**
 * Expand the cipher key into the decryption key schedule.
 */
int private_AES_set_decrypt_key(const unsigned char *userKey, const int bits,
                                AES_KEY *key)
{

    u32 *rk;
    int i, j, status;
    u32 temp;

    /* first, start with an encryption schedule */
    status = private_AES_set_encrypt_key(userKey, bits, key);
    if (status < 0)
        return status;

    rk = key->rd_key;

    /* invert the order of the round keys: */
    for (i = 0, j = 4*(key->rounds); i < j; i += 4, j -= 4) {
        temp = rk[i    ]; rk[i    ] = rk[j    ]; rk[j    ] = temp;
        temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp;
        temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp;
        temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp;
    }
    /* apply the inverse MixColumn transform to all round keys but the first and the last: */
    for (i = 1; i < (key->rounds); i++) {
        rk += 4;
        for (j = 0; j < 4; j++) {
            u32 tp1, tp2, tp4, tp8, tp9, tpb, tpd, tpe, m;

            tp1 = rk[j];
            m = tp1 & 0x80808080;
            tp2 = ((tp1 & 0x7f7f7f7f) << 1) ^
                ((m - (m >> 7)) & 0x1b1b1b1b);
            m = tp2 & 0x80808080;
            tp4 = ((tp2 & 0x7f7f7f7f) << 1) ^
                ((m - (m >> 7)) & 0x1b1b1b1b);
            m = tp4 & 0x80808080;
            tp8 = ((tp4 & 0x7f7f7f7f) << 1) ^
                ((m - (m >> 7)) & 0x1b1b1b1b);
            tp9 = tp8 ^ tp1;
            tpb = tp9 ^ tp2;
            tpd = tp9 ^ tp4;
            tpe = tp8 ^ tp4 ^ tp2;
#if defined(ROTATE)
            rk[j] = tpe ^ ROTATE(tpd,16) ^
                ROTATE(tp9,24) ^ ROTATE(tpb,8);
#else
            rk[j] = tpe ^ (tpd >> 16) ^ (tpd << 16) ^ 
                (tp9 >> 8) ^ (tp9 << 24) ^
                (tpb >> 24) ^ (tpb << 8);
#endif
        }
    }
    return 0;
}

#endif /* AES_ASM */

在使用 key-size=192 和 256 调用这两个函数时会发生分段。尽管在这两个函数中,它明确指定了与 key-size 相关的轮数(key-size=128, total_round=10,key- size=192, total_round=12,key-size=256, total_round=14),这两个函数还是会出现分段错误。

【问题讨论】:

  • 你为什么在NO_OF_DECRYPTION上循环?
  • @zaph 我需要进行 50 次解密。
  • @zaph 我用过 AES_set_encrypt_key((const unsigned char *)key, 128, &enc_key);对于 key-size=128 和 AES_encrypt(text, enc_out, &enc_key);加密文本。但是, AES_set_encrypt_key((const unsigned char *)key, 192, &enc_key);和 AES_set_encrypt_key((const unsigned char *)key, 256, &enc_key);两者都会导致分段错误。
  • 如果 key-size= 192 和 256,分段错误发生在 AES_set_encrypt_key((const unsigned char *)key, 256, &enc_key);表示未开始加密。
  • AES_encrypt 和 AES_decrypt 的代码在 aes_core.c 中声明(在我的例子中是 AES.c)。

标签: c openssl cryptography performance-testing


【解决方案1】:

忽略我之前的错误答案尝试。

AES_KEYrd_key 字段是一个有 44 个元素的 unsigned int 数组。

rounds 字段可以用值 12(对于 192 位密钥)或 14(对于 256 位密钥)进行初始化。

然后将rounds 字段用作rd_key 数组的索引限制(通过rk 指针),并且索引可以超出数组的末尾。在private_AES_set_decrypt_key() 中有这个sn-p 的代码:

/* invert the order of the round keys: */
for (i = 0, j = 4*(key->rounds); i < j; i += 4, j -= 4) {
    temp = rk[i    ]; rk[i    ] = rk[j    ]; rk[j    ] = temp;
    temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp;
    temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp;
    temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp;
}

rounds 为12 时,j 将从48 开始,因此在上述前两次循环迭代中使用j 变量的所有访问都超出了数组的末尾。当 256 位密钥使用 14 轮时,情况会更糟。由于其中一些访问是写入,rounds 字段也将被覆盖,此时谁知道rd-key 数组会发生什么,因为rounds 在以下循环中被用作限制?

其他循环将rk 指针移动到rd_key 数组的开头之外,因此很难知道它们是否访问到数组末尾之外,但应该能够使用调试器验证是否发生这种情况.

也许您需要做的就是将struct aes_key_st 的定义更改为:

struct aes_key_st {
    unsigned int rd_key[4 *(14 + 1)];
    int rounds;
};

最多可容纳 14 个 rounds 的 256 位密钥。

【讨论】:

  • 非常感谢。以上解决方案解决了我的问题。
【解决方案2】:

不要使用块级加密代码,您需要使用支持比块更大的输入的级别,因此不需要循环,例如CBC的模式和PKCS#7等填充

【讨论】:

  • 有一些基于“C”的 SO 示例。使用块级加密是非常少见的。对于块级别,您必须为不是块大小倍数的输入进行自己的填充。该模式本质上是不安全的 ECB 模式,请参阅ECB Mode,向下滚动到 Penguin。
  • 我同意你的观点,如果输入不是块大小的倍数,我需要进行填充。截至目前,我正在传递块大小(硬编码)倍数长度的输入,并尝试使用块级加密。我认为默认情况下实现了 CBC,在这种情况下如何使用 key-size=192 和 256 解决这个分段错误?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-12
  • 2013-08-11
  • 2011-05-23
  • 2015-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多