在C ++中使用OpenSSL使用AES128加密字符串时出错

时间:2019-05-07 17:18:31

标签: c++ encryption openssl aes

我在CBC模式下使用OpenSSL库和AES 128算法生成的加密消息的最后一个字符有问题,这些是我正在使用的数据:

Message in Hex = "7b22494443223a2232363930393439376434222c22444553223a2256656e74616d656e7564656f222c22414d4f223a3530302c22444154223a313530383233303035383730362c22524546223a302c22434f4d223a312c22545950223a31392c2276223a7b224e414d223a2252616661656c56616c656e7a75656c614172656e6173222c22414343223a2235383732313233343536373836303132222c2242414e223a34303132372c22545943223a332c22444556223a22353532373139323132382f30227d7da"
Key128 in Hex = "dadf11e74d014a62d73ccadd9591442a"
Initialization Vector in Hex = "cab9da8940cd7dc9510c7249fe47c6e6"

这是我正在使用的代码:

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <math.h>
#include <assert.h>
#include <stdint.h>
#include <stdbool.h>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <locale>

#include <openssl/aes.h>
#include <openssl/des.h>
#include <openssl/sha.h>
#include <openssl/hmac.h>

using namespace std;

/* AES key for Encryption and Decryption */
const static unsigned char aes_key[16]={0xda, 0xdf, 0x11, 0xe7, 0x4d, 0x01, 0x4a, 0x62, 0xd7, 0x3c, 0xca, 0xdd, 0x95, 0x91, 0x44, 0x2a};

/* Print Encrypted and Decrypted data packets */
void print_data(const char *tittle, const void* data, int len)
{
    printf("%s : ",tittle);
    const unsigned char * p = (const unsigned char*)data;
    int i = 0;

    for (; i<len; ++i)
    {
        printf("%02X ", *p++);
    }

    printf("\n");
}

int main( )
{
    /* Input data to encrypt */
    unsigned char enc_out[235]={0x7b, 0x22, 0x49, 0x44, 0x43, 0x22, 0x3a, 0x22, 0x32, 0x36, 0x39, 0x30, 0x39, 0x34, 0x39, 0x37, 0x64, 0x34, 0x22, 0x2c, 0x22, 0x44, 0x45, 0x53, 0x22, 0x3a, 0x22, 0x56, 0x65, 0x6e, 0x74, 0x61, 0x6d, 0x65, 0x6e, 0x75, 0x64, 0x65, 0x6f, 0x22, 0x2c, 0x22, 0x41, 0x4d, 0x4f, 0x22, 0x3a, 0x35, 0x30, 0x30, 0x2c, 0x22, 0x44, 0x41, 0x54, 0x22, 0x3a, 0x31, 0x35, 0x30, 0x38, 0x32, 0x33, 0x30, 0x30, 0x35, 0x38, 0x37, 0x30, 0x36, 0x2c, 0x22, 0x52, 0x45, 0x46, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x43, 0x4f, 0x4d, 0x22, 0x3a, 0x31, 0x2c, 0x22, 0x54, 0x59, 0x50, 0x22, 0x3a, 0x31, 0x39, 0x2c, 0x22, 0x76, 0x22, 0x3a, 0x7b, 0x22, 0x4e, 0x41, 0x4d, 0x22, 0x3a, 0x22, 0x52, 0x61, 0x66, 0x61, 0x65, 0x6c, 0x56, 0x61, 0x6c, 0x65, 0x6e, 0x7a, 0x75, 0x65, 0x6c, 0x61, 0x41, 0x72, 0x65, 0x6e, 0x61, 0x73, 0x22, 0x2c, 0x22, 0x41, 0x43, 0x43, 0x22, 0x3a, 0x22, 0x35, 0x38, 0x37, 0x32, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x36, 0x30, 0x31, 0x32, 0x22, 0x2c, 0x22, 0x42, 0x41, 0x4e, 0x22, 0x3a, 0x34, 0x30, 0x31, 0x32, 0x37, 0x2c, 0x22, 0x54, 0x59, 0x43, 0x22, 0x3a, 0x33, 0x2c, 0x22, 0x44, 0x45, 0x56, 0x22, 0x3a, 0x22, 0x35, 0x35, 0x32, 0x37, 0x31, 0x39, 0x32, 0x31, 0x32, 0x38, 0x2f, 0x30, 0x22, 0x7d, 0x7d, 0xa};

    /* Init vector */
    unsigned char iv[16]={0xca, 0xb9, 0xda, 0x89, 0x40, 0xcd, 0x7d, 0xc9, 0x51, 0x0c, 0x72, 0x49, 0xfe, 0x47, 0xc6, 0xe6};
    //memset(iv, 0x00, AES_BLOCK_SIZE);

    /* Buffers for Encryption and Decryption */
    unsigned char dec_out[400];
    unsigned char aux_out[400];

    memset(dec_out, 0, sizeof(dec_out));
    memset(aux_out, 0, sizeof(aux_out));

    /* AES-128 bit CBC Encryption */
    AES_KEY enc_key, dec_key;
    AES_set_encrypt_key(aes_key, sizeof(aes_key)*8, &enc_key);
    AES_cbc_encrypt(enc_out, dec_out, sizeof(enc_out), &enc_key, iv, AES_ENCRYPT);
    /* AES-128 bit CBC Decryption */
    memset(iv, 0x00, AES_BLOCK_SIZE); // don't forget to set iv vector again, else you can't decrypt data properly
    AES_set_decrypt_key(aes_key, sizeof(aes_key)*8, &dec_key); // Size of key is in bits
    AES_cbc_encrypt(dec_out, aux_out, sizeof(enc_out), &dec_key, iv, AES_DECRYPT);

    /* Printing and Verifying */
    print_data("\n Original ",enc_out, sizeof(enc_out)); // you can not print data as a string, because after Encryption its not ASCII

    print_data("\n Encrypted",dec_out, sizeof(enc_out));

    print_data("\n Decrypted",aux_out, sizeof(dec_out));

    return 0;
}

显然,只有链的末端是不正确的(最后32个字符),其余的都很好,我研究了一下,所有内容都指向文本填充的类型,但是根据我的意思读取它已经用PKCS5填充(实际上是我需要的填充),所以我看不到错误是什么。

The Correct Encryption = EFC063DD33406D424D359809695D0B1E2D65027E803962C6A115DF7CCABEEB0C8C358830E556ED23943FA4F02E6461D235EF913CFCE5519F7CE2279DD07D3C4054D045827D5D7D9FE94DA3C5B718A24E79539B3FFC1E68E4C3FF441EEA176F61EE3D7B33B622E3069D95815F6407FBC79342BB972A2DDE4E50FDE9302BDE4409B7D2BD388AB6A043B9EF236D982937D8537F954564FF4134BD8A6EAB994FE4C29E9DC4E54D53A561A4688C45C90961EDB1763B6EF6C86B593C7E16FDF35C49CE16B1E6948BB1EAE6A8692326A019960B

The Output of the Program = EFC063DD33406D424D359809695D0B1E2D65027E803962C6A115DF7CCABEEB0C8C358830E556ED23943FA4F02E6461D235EF913CFCE5519F7CE2279DD07D3C4054D045827D5D7D9FE94DA3C5B718A24E79539B3FFC1E68E4C3FF441EEA176F61EE3D7B33B622E3069D95815F6407FBC79342BB972A2DDE4E50FDE9302BDE4409B7D2BD388AB6A043B9EF236D982937D8537F954564FF4134BD8A6EAB994FE4C29E9DC4E54D53A561A4688C45C90961EDB1763B6EF6C86B593C7E16FDF35C49CE608E3F73FC8E3DDF1D3BCF40B3DFACD00B732A9FCC10F6E0FB18E126A1C21A082D7A4F053F131A9329474D

我了解该代码已进行了许多改进,并且我没有考虑解密密码,但是目前我不需要它。

2 个答案:

答案 0 :(得分:2)

AES_cbc_encrypt正在使用低级原语进行加密。它不执行任何填充。这是AES CBC代码直接调用的基础CBC源代码的链接:https://github.com/openssl/openssl/blob/master/crypto/modes/cbc128.c-完全没有填充。

真正的问题是为什么您将使用描述不明确的底层实现函数,而不是OpenSSL本身倡导的EVP API。您可能认为较低级别的原语性能更好,但是如果例如部署了AES-NI;无论如何,与加密本身相比,呼叫开销将最小。

答案 1 :(得分:1)

enc_out数组的大小为235个字节,但仅显式地初始化为200个字节,即,其余的字节隐式地使用{{ 1}}值。这对应于长度为240字节(= 15 x 16字节)的密文。因此,当前代码返回的密文长度为240个字节,其后三个块为:

0x00

这对应于具有608E3F73FC8E3DDF1D3BCF40B3DFACD0 0B732A9FCC10F6E0FB18E126A1C21A08 2D7A4F053F131A9329474DE44DA772BC 值的隐式填充。发布的密文中缺少最后5个字节,这是因为输出使用了明文(而不是密文)的长度。

很可能只应加密前200个字节。这将与长度为208个字节(= 13 x 16个字节)的密文相对应,这正是预期的密文的长度。为此,0x00数组的大小必须从235减小到200,甚至更好,根本不要明确指定大小。

然后再短两个代码块,但生成相同的密文,这与预期的密文仅在最后一个代码块中有所不同,现在这仅由缺少PKCS7填充引起。