在循环内连接 unsigned char *

Concatenate unsigned char * inside a loop

我正在使用 OpenSSL 库通过 AES 进行加密。由于 AES 是分组密码,我需要将数据分成 16 字节的块。因此,如果我想恢复消息,我需要在程序结束时合并这些块。

这是我的代码:

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <openssl/aes.h>

char key[] = "secretkey123";

int main() {
    unsigned char text_slice[128];
    unsigned char enc_slice[128];
    unsigned char dec_slice[128];
    
    unsigned char in[160];
    
    unsigned char enc_out[160] = "";
    unsigned char dec_out[160] = "";
    
    int i;
    int k = 10;
    for (i = 0; i < 16 * k; i++) {
        in[i] = 'A' + (rand() % 26);
    }
    in[160] = '[=10=]';
    printf("IN:%s\n", in);
    
    AES_KEY enc_key, dec_key;
    
    AES_set_encrypt_key(key, 128, &enc_key);
    
    AES_set_decrypt_key(key, 128, &dec_key);
    
    for (i = 0; i < k; i++) {
        text_slice[0] = '[=10=]';
        enc_slice[0] = "[=10=]";
        dec_slice[0] = "[=10=]";
        memcpy(&text_slice[0], &in[15 * i], 15);
        text_slice[16] = "[=10=]";
        printf("TEXT SLICE: %s \n", text_slice);
        AES_encrypt(text_slice, enc_slice, &enc_key);
        memcpy(&enc_out[16 * i], &enc_slice[0], 16);
    }
    printf("ENC:%s\n", enc_out);
    for (i = 0; i < k; i++) {
        text_slice[0] = '[=10=]';
        enc_slice[0] = "[=10=]";
        dec_slice[0] = "[=10=]";
        memcpy(enc_slice, &enc_out[16 * i], 16);
        enc_slice[16] = "[=10=]";
    
        AES_decrypt(enc_slice, dec_slice, &dec_key);
        printf("Dec slice:%s \n", dec_slice);
        memcpy(&dec_out[16 * i], &dec_slice[0], 16);
    }
    printf("DEC OUT:%s\n", dec_out);
    
    return 0;
}

程序的输出如下:

IN:NWLRBBMQBHCDARZOWKKYHIDDQSCDXRJMOWFRXSJYBLDBEFSARCBYNECDYGGXXPKLORELLNMPAPQFWKHOPKMCOQHNWNKUEWHSQMGBBUQCLJJIVSWMDKQTBXIXMVTRRBLJPTNSNFWZQFJMAFADRRWSOFSBCNUVQHFF
TEXT SLICE: NWLRBBMQBHCDARZ 
TEXT SLICE: OWKKYHIDDQSCDXR 
TEXT SLICE: JMOWFRXSJYBLDBE 
TEXT SLICE: FSARCBYNECDYGGX 
TEXT SLICE: XPKLORELLNMPAPQ 
TEXT SLICE: FWKHOPKMCOQHNWN 
TEXT SLICE: KUEWHSQMGBBUQCL 
TEXT SLICE: JJIVSWMDKQTBXIX 
TEXT SLICE: MVTRRBLJPTNSNFW 
TEXT SLICE: ZQFJMAFADRRWSOF 
ENC:j�Q���
�7֡���*n���R  ��m7�zI#4��=v�#�(��V7��ח9.R�q����:C�%��_��!q��(��l��j�3�1�h��
Dec slice:NWLRBBMQBHCDARZ 
Dec slice:OWKKYHIDDQSCDXR 
Dec slice:JMOWFRXSJYBLDBE 
Dec slice:FSARCBYNECDYGGX 
Dec slice:XPKLORELLNMPAPQ 
Dec slice:FWKHOPKMCOQHNWN 
Dec slice:KUEWHSQMGBBUQCL 
Dec slice:JJIVSWMDKQTBXIX 
Dec slice:MVTRRBLJPTNSNFW 
Dec slice:ZQFJMAFADRRWSOF 
DEC OUT:NWLRBBMQBHCDARZ

虽然 dec_slice 按预期工作,但 dec_out 只是获取第一个块的内存副本。更令我惊讶的是,enc_out 在遵循与 dec_out 相同的逻辑时正确执行。我错过了什么?

密钥必须至少有 16 个字节,因为您传递的位数等于 128:

AES_set_encrypt_key(key, 128, &enc_key);
AES_set_decrypt_key(key, 128, &dec_key);

你在这里有未定义的行为:

    in[160] = '[=11=]';

这些行没有意义:

    enc_slice[0] = "[=12=]";
    dec_slice[0] = "[=12=]";
    text_slice[16] = "[=12=]";
    enc_slice[16] = "[=12=]";

为什么要对 15 个字符而不是 16 个字符的块进行编码?

    memcpy(&text_slice[0], &in[15 * i], 15);

这是修改后的版本:

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <openssl/aes.h>

char key[] = "secretkey1234567";

int main() {
    unsigned char text_slice[128];
    unsigned char enc_slice[128];
    unsigned char dec_slice[128];
    unsigned char in[160];
    unsigned char enc_out[160];
    unsigned char dec_out[160];
    
    int i, k = 10;
    for (i = 0; i < 16 * k; i++) {
        in[i] = 'A' + (rand() % 26);
    }
    printf("IN: \"%.160s\"\n", (char *)in);
    
    AES_KEY enc_key, dec_key;
    AES_set_encrypt_key(key, 128, &enc_key);
    AES_set_decrypt_key(key, 128, &dec_key);
    
    for (i = 0; i < k; i++) {
        memcpy(text_slice, &in[16 * i], 16);
        printf("TEXT SLICE: %.16s\n", (char *)text_slice);
        AES_encrypt(text_slice, enc_slice, &enc_key);
        memcpy(&enc_out[16 * i], enc_slice, 16);
    }
    printf("ENC:");
    for (i = 0; i < 16 * k; i++) {
       printf(" %02X\n", enc_out[i]);
    }
    printf("\n");
    for (i = 0; i < k; i++) {
        memcpy(enc_slice, &enc_out[16 * i], 16);
        AES_decrypt(enc_slice, dec_slice, &dec_key);
        printf("Dec slice: %.16s \n", (char *)dec_slice);
        memcpy(&dec_out[16 * i], dec_slice, 16);
    }
    printf("DEC OUT: \"%.160s\"\n", (char *)dec_out);
    return 0;
}

那个代码有很多问题。

AES_set_encrypt_keyAES_set_decrypt_key不是密钥推导函数,第二个参数应该表示第一个参数(userKey)的位长度。

如果您提供长度不是 128 位的任意字符串常量,如 "secretkey123",它可能会导致内存损坏或为您的加密创建一个非常不安全的上下文。

一般来说,对于基于用户密码的加密,我们使用密钥派生函数从任何密码生成密钥(例如PBKDF2,或scrypt)。

这行也不好:

in[160] = '[=10=]';

由于缓冲区的大小为 160,因此最后一个索引应为 160 - 1。如果你在索引 160 处写入,你实际上是溢出了。

还有,写C代码的时候一定要注意单引号和双引号的区别

这很糟糕:

enc_slice[0] = "[=11=]";
dec_slice[0] = "[=11=]";

如果您使用双引号,您实际上并不是在 enc_slicedec_slice 的第一个索引处写入值 0。您正在写入空 read-only 常量字符串的地址。

还有这个:

unsigned char enc_out[160] = "";
unsigned char dec_out[160] = "";

如果你想要空缓冲区,你应该这样做:

unsigned char enc_out[160] = {0};
unsigned char dec_out[160] = {0};

希望这是改进代码并使其正常工作的良好开端。