在NodeJS和OpenSSL C ++中加密时获得不同的值

时间:2018-12-24 22:19:55

标签: c++ node.js openssl aes cbc-mode

我正在进行客户端-服务器通信,并坚持确保双方提出相同的加密令牌值。无法弄清楚它们为何不同。密钥和初始化向量以及消息本身都是相同的。

以下是在客户端代码中进行加密的功能:

int main()
{

try
    {
        std::string message = "HelloWorld";

        while ((message.size() & 0xf) != 0xf)
            message += " ";

        size_t inputslength = message.length();
        unsigned char aes_input[inputslength];

        memset(aes_input, 0, inputslength/8);

        strcpy((char*) aes_input, message.c_str());





        unsigned char iv[] = {'0','f','9','3','8','7','b','3','f','9','4','b','f','0','6','f'};

        unsigned char aes_key[] = {'Z','T','k','0','Y','T','U','5','Y','j','N','h','M','j','k','4','N','G','I','3','N','m','I','x','N','W','E','x','N','z','d','i'};

        // 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));

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

输出

original: 48 65 6C 6C 6F 57 6F 72 6C 64 20 20 20 20 20 
encrypt: 72 70 A2 0D FB A1 65 15 17 97 6E 5D 36 23 E2 FA 
decrypt: 0A 73 F7 52 AC C1 68 54 1D CA 7A 1F 70 33 F4 

同时在服务器上:

function encryptToken(token)
{
    const iv = '0f9387b3f94bf06f';
    const key = 'ZTk0YTU5YjNhMjk4NGI3NmIxNWExNzdi';

    console.log("key len: " + key.length);

    const encrypt = (value) => {
       const cipher = crypto.createCipheriv('AES-256-CBC', key, iv);
       let encrypted = cipher.update(value, 'utf8', 'hex');
       encrypted += cipher.final('hex');
       return encrypted;
    };

    console.log('Encrypteddd value: ', encrypt('HelloWorld'));
}

输出

Encrypteddd value:  0c491f8c5256b9744550688fc54926e8

在尝试使用CBC-256进行加密之前,我尝试了更简单的加密模式ECB-128,所有这些都归结为相同的问题。客户端和服务器端生成的不同加密令牌导致无法解密来自服务器端的内容。任何集思广益的提示都将对您有帮助。我的想法不多了,谢谢。

更新12.26-

在对客户端的初始化向量和数组长度提出建议之后。这是我更新后的输出代码:

int main()
{

try
    {
        std::string message = "HelloWorld";
    while ((message.size() & 0xf) != 0xf)
        message += " ";

    size_t inputslength = message.length();
    unsigned char aes_input[inputslength+1];

    memset(aes_input, 0, inputslength/8);

    strcpy((char*) aes_input, message.c_str());





    unsigned char iv[] = {0x0f, 0x93, 0x87, 0xb3, 0xf9, 0x4b, 0xf0, 0x6f};
    unsigned char aes_key[] = {'Z','T','k','0','Y','T','U','5','Y','j','N','h','M','j','k','4','N','G','I','3','N','m','I','x','N','W','E','x','N','z','d','i'};

    // 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));

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

}

//Output:
original:   48 65 6C 6C 6F 57 6F 72 6C 64 00 
encrypt:    54 CD 98 20 59 D9 7B 2D D4 23 ED EC D0 13 97 59 

Nodejs代码未更改,这仍然是输出:

Encrypteddd value:  0c491f8c5256b9744550688fc54926e8

1 个答案:

答案 0 :(得分:1)

所以,这是交易。每次对AES_cbc_encrypt的调用都会更改初始化向量的值。他们这样做是为了使您可以将调用链接到AES_*_encrypt并处理大于一个块的消息。但是因为加密调用更改了iv的值,所以解密调用获得了不同初始化向量。

一个(糟糕的)解决方案是制作两个向量:

unsigned char iv_encrypt[] = { /* stuff */ };
unsigned char iv_decrypt[] = { /* same stuff */ };

这样,您将向每个AES_cbc_encrypt调用传递相同的数据。这至少表明您可以解密为原始数据。实现目标的一种更好,更灵活的方法是为每个调用使用初始化矢量的克隆。像这样:

unsigned char iv[] = { /* stuff */ };
unsigned char *tmp_iv = static_cast<unsigned char*>( malloc( sizeof( iv ) ) );
...
memcpy( tmp_iv, iv, sizeof(iv) );
AES_cbc_encrypt(aes_input, enc_out, inputslength, &enc_key, tmp_iv, AES_ENCRYPT);
...
memcpy( tmp_iv, iv, sizeof(iv) );
AES_cbc_encrypt(enc_out, dec_out, inputslength, &dec_key, tmp_iv, AES_DECRYPT);