【问题标题】:AES 256-cbc encryption C++ using OpenSSL使用 OpenSSL 的 AES 256-cbc 加密 C++
【发布时间】:2017-08-28 18:48:42
【问题描述】:

我正在尝试创建一个函数,我可以将一个字符串密钥(我有另一种生成密钥的算法)放入一个消息字符串中。该函数应使用 OpenSSL 库中的 aes256-cbc 对文本进行加密和解密

#define AES_KEYLENGTH 256
string cipher_AES(string key, string message);

int main(int argc, char* argv[])
{
     cipher_AES("115792089237316195423570985008687907853269984665640564039457583884239776304164", "Hello, how are you, you mad?");
     return 0;
}

// a simple hex-print routine. could be modified to print 16 bytes-per-line
static void hex_print(const void* pv, size_t len)
{
    const unsigned char * p = (const unsigned char*)pv;
    if (NULL == pv)
        printf("NULL");
    else
    {
        size_t i = 0;
        for (; i<len;++i)
            printf("%02X ", *p++);
    }
    printf("\n");
}

/* computes the ciphertext from plaintext and key using AES256-CBC algorithm */
string cipher_AES(string key, string message)
{
    size_t inputslength = message.length();
    unsigned char aes_input[inputslength];
    unsigned char aes_key[AES_KEYLENGTH];
    memset(aes_input, 0, inputslength/8);
    memset(aes_key, 0, AES_KEYLENGTH/8);
    strcpy((char*) aes_input, message.c_str());
    strcpy((char*) aes_key, key.c_str());

    /* init vector */
    unsigned char iv[AES_BLOCK_SIZE];
    memset(iv, 0x00, AES_BLOCK_SIZE);

    // buffers for encryption and decryption
    const size_t encslength = ((inputslength + AES_BLOCK_SIZE) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE;
    unsigned char enc_out[encslength];
    unsigned char dec_out[inputslength];
    memset(enc_out, 0, sizeof(enc_out));
    memset(dec_out, 0, sizeof(dec_out));

    AES_KEY enc_key, dec_key;
    AES_set_encrypt_key(aes_key, AES_KEYLENGTH, &enc_key);
    AES_cbc_encrypt(aes_input, enc_out, inputslength, &enc_key, iv, AES_ENCRYPT);

    AES_set_decrypt_key(aes_key, AES_KEYLENGTH, &dec_key);
    AES_cbc_encrypt(enc_out, dec_out, encslength, &dec_key, iv, AES_DECRYPT);

    printf("original:\t");
    hex_print(aes_input, sizeof(aes_input));
    printf("encrypt:\t");
    hex_print(enc_out, sizeof(enc_out));

    printf("decrypt:\t");
    hex_print(dec_out, sizeof(dec_out));

    stringstream ss;
    for(int i = 0; i < encslength; i++)
    {
        ss << enc_out[i];
    }
    return ss.str(););
}

在输出中似乎有些东西是一样的,但不是全部:

original:       48 65 6C 6C 6F 2C 20 68 6F 77 20 61 72 65 20 79 6F 75 2C 20 79 6F 75 20 69 64 69 6F 74 3F
encrypt:        25 C3 B4 4B 92 68 2E DA 61 B6 AB 19 97 D3 90 8A 5F 8B 3C 4B 78 13 FC E1 3A AF 2C B5 3F C8 2B D7
decrypt:        17 EE 50 27 17 3F DC 89 55 D8 0C D4 4D AD 0B AE 6F 75 2C 20 79 6F 75 20 69 64 69 6F 74 3F

【问题讨论】:

  • 虽然将所有内容都塞在一个语句中并消除变量“看起来”很好,但会阻碍可理解性。 keydata 等变量让事情变得更加清晰。为人类读者编写代码是一个值得追求的目标。
  • AES 支持三种密钥长度:128、192 和 256 ,所以人们对 key "115792089237316195423570985008687907853269984665640564039457583884239776304164" 感到好奇。最好使用完全支持的密钥大小。
  • @zaph 只是一个小于 2^256 的随机数,如果我没记错的话,它应该可以用作 256 位密钥。我不打算以固定键值的这种特殊方式使用它。
  • 确实如此,但通常最好提供完全正确的参数大小,几乎不清楚任何实现将如何处理不正确大小的参数。

标签: c++ encryption cryptography


【解决方案1】:

查看您的数据,第一个块(16 个字节)是错误的,但后面的块是正确的。这表明解密时使用了错误的 IV。一个小测试(在第一次调用 AES_cbc_encrypt 之前和之后打印 IV)表明 IV 确实在这次调用期间发生了变化。

在 OpenSSL 源代码上稍作检查表明它在加密时是 changes the IV parameter to be the last block of the ciphertext

在解密修复它之前重置 IV,你会得到正确的明文重新生成:

memset(iv, 0x00, AES_BLOCK_SIZE);
AES_cbc_encrypt(enc_out, dec_out, encslength, &dec_key, iv, AES_DECRYPT);

【讨论】:

  • 哇,这太糟糕了,太出乎意料了。文档是否说明了这一点?
  • @zaph 用于加密block[n] 的IV 是ciphertext(block[n-1]),除非n == 0,这是在使用输入IV 时。如果您考虑在循环中调用此 API,则此副本是有意义的。前一个块的输出是下一个块的IV。
  • @Unsigned 我想这是有道理的。该方法已经包含一个块循环,这就是为什么我说我不知道​​为什么 IV 被覆盖,但我想这是一个相当低级的方法,这将允许多次调用某种 update 函数.
  • @Unsigned 如果没有命名解密函数,我会更倾向于认为它不是 POS:AES_cbc_encrypt
【解决方案2】:

阅读openssl的cbc128.c源码,存在一个循环调用iv或last block的输出。当循环结束时,iv 将被更新。

void CRYPTO_cbc128_encrypt(const unsigned char *in, unsigned char *out,
                           size_t len, const void *key,
                           unsigned char ivec[16], block128_f block)
{
    size_t n;
    const unsigned char *iv = ivec;

    if (len == 0)
        return;

#if !defined(OPENSSL_SMALL_FOOTPRINT)
    if (STRICT_ALIGNMENT &&
        ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
        while (len >= 16) {
            for (n = 0; n < 16; ++n)
                out[n] = in[n] ^ iv[n];
            (*block) (out, out, key);
            iv = out;
            len -= 16;
            in += 16;
            out += 16;
        }
    } else {
        while (len >= 16) {
            for (n = 0; n < 16; n += sizeof(size_t))
                *(size_t_aX *)(out + n) =
                    *(size_t_aX *)(in + n) ^ *(size_t_aX *)(iv + n);
            (*block) (out, out, key);
            iv = out;
            len -= 16;
            in += 16;
            out += 16;
        }
    }
#endif
    while (len) {
        for (n = 0; n < 16 && n < len; ++n)
            out[n] = in[n] ^ iv[n];
        for (; n < 16; ++n)
            out[n] = iv[n];
        (*block) (out, out, key);
        iv = out;
        if (len <= 16)
            break;
        len -= 16;
        in += 16;
        out += 16;
    }
    memcpy(ivec, iv, 16);
}

【讨论】:

    猜你喜欢
    • 2013-08-11
    • 2019-04-14
    • 1970-01-01
    • 2018-09-09
    • 2022-06-11
    • 2022-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多