C语言 memcpy:第二次调用后的隔离错误



我正在为 Karl Malbrain 的 AES 实现编写一个包装器,以处理大于 16 字节的输入文件。因此,我编写了一个函数aes_encrypt_block它将输入缓冲区(message)拆分为16字节(chunk/chunk_cipher)的块,调用加密/解密函数并将加密/解密的16字节放回结果缓冲区。

这行得通。但是,我需要在加密之前填充消息。因此,我加密的最后 16 个字节(在 for 循环之外)是填充字节。将这些字节复制到输出缓冲区(cipher)时,我得到一个段错误。我真的看不出出了什么问题。

你看到错误了吗?

问候

#include "aes.h"
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#define DEBUG 1
void aes_encrypt_block(uint8_t **message, uint8_t **cipher, uint8_t blocks, uint8_t     pad_bytes);
void aes_decrypt_block(uint8_t **msg_decrypted, uint8_t **cipher, uint8_t blocks,     uint8_t pad_bytes);
unsigned long readFile(char *fileName, uint8_t **buffer);
//unsigned long readFile1(char *fileName, uint8_t *buffer);
uint8_t secret[16] = {0x44, 0x43, 0x45, 0x33, 0x44, 0x03, 0x34, 0x44, 0x43, 0x45, 0x33,     0x44, 0x03, 0x34, 0x03, 0x34};
uint8_t *chunk = NULL;
uint8_t *chunk_cipher = NULL;
uint8_t expanded[176] = {0x00};
uint8_t *buffer = NULL;
uint8_t *cipher = NULL;
uint8_t *msg_decrypted = NULL;
uint8_t mode = -1;

int main(int argc, char *argv[]) {
    uint32_t i = 0;
    uint8_t blocks = -1, pad_bytes = -1;
    unsigned long fileLen;
    char* ch = NULL;
    if(argc<3) {
        printf("Wrong arguments supplied.nn%s {0/1} OUTnnt0 - encryptnt1 -     decryptntOUT - file to read from / to write to.nn", argv[0]);
        return 0;
    } else {
        mode = atoi(argv[1]);
        if(mode<0 || mode>1) {
            printf("Wrong arguments supplied.nn%s {0/1} OUTnnt0 -     encryptnt1 - decryptntOUT - file to read from / to write to.nn", argv[0]);
            return 0;
        }
    }
    puts("");
    // Read file
    fileLen = readFile(argv[2], &buffer);
    // Setting up parameters and memory
    if(fileLen%16!=0) {
        printf("- ");
        blocks = fileLen/16+1;
        pad_bytes = (blocks*16)-fileLen;
    } else {
        printf("+ ");
        blocks = fileLen/16+1;
        pad_bytes = 16;
    }
    cipher = malloc((blocks*16)*sizeof(int));
    if(cipher==NULL)    printf("malloc() error!n");
        aes_expand_key(secret, expanded);
        if(DEBUG)   printf("size: %u, size/16: %d, blocks: %d, padding: %dnn", fileLen, fileLen/16, blocks, pad_bytes);
    if(!mode) {     // We will encrypt
        aes_encrypt_block(&buffer, &cipher, blocks, pad_bytes);
        free(buffer);
        FILE *file_enc;
        file_enc = fopen("bla.enc", "wb");
        fileLen = fwrite(&cipher, sizeof(uint8_t), 32, file_enc);
        printf("nWrote %ld bytes to %sn", fileLen, argv[2]);
        fclose(file_enc);
    } else {            // We will decrypt
        msg_decrypted = malloc((16*blocks)*sizeof(uint8_t));
        // Decrypting blocks
        aes_decrypt_block(msg_decrypted, cipher, blocks, pad_bytes);
        puts("nDecrypted message:");
        printf("%sn", msg_decrypted);
        puts("");
        free(msg_decrypted);
    }
    return 0;
}

unsigned long readFile(char *fileName, uint8_t **buffer) {
    unsigned long fileLen = 0;
    uint8_t i;
    char* ch = NULL;
    FILE *file;
    file = fopen (fileName, "rb");  /* open the file for reading */
    if(file==NULL) {
       perror(fileName);
        return 0;
    }
    fseek(file, 0, SEEK_END);
    fileLen=ftell(file);
    fseek(file, 0, SEEK_SET);
    *buffer=malloc(fileLen+1);
    if (!buffer) {
        fprintf(stderr, "Memory error!");
        fclose(file);
        return;
    }
    fread(*buffer, 1, fileLen, file);
    printf( "Source message in hex(%s, %ld bytes):n", fileName, fileLen );
    for (ch = *buffer ; ch < *buffer + fileLen; ++ch) {
        printf( "%02X", *ch );
    }
    puts("nASCII:n---------");
    for (ch = *buffer ; ch < *buffer + fileLen; ++ch) {
        printf( "%c", *ch );
    }
    puts("");
    fclose(file);
    return fileLen;
}

void aes_encrypt_block(uint8_t **message, uint8_t **cipher, uint8_t blocks, uint8_t pad_bytes) {
    uint8_t i;
    chunk = malloc(16*sizeof(uint8_t));
    if(chunk==NULL) printf("malloc() error!n");
    chunk_cipher = malloc(16*sizeof(uint8_t));
    if(chunk_cipher == NULL)    printf("malloc() error!n");
    for(i=0; i<(blocks-1); i++) {
        memcpy(chunk, message[i*16], 16*sizeof(uint8_t));
        aes_encrypt(chunk, expanded, chunk_cipher);
        memcpy(cipher[i*16], chunk_cipher, 16*sizeof(uint8_t));
    }
    // Padding
memcpy(chunk, message[(blocks-1)*16], (16-pad_bytes)*sizeof(uint8_t));
    uint8_t j;
    for(j=0; j<=pad_bytes; j++) {
        chunk[15-j] = pad_bytes;
    }
    aes_encrypt(chunk, expanded, chunk_cipher);
    memcpy(cipher[i*16], chunk, 16*sizeof(uint8_t));
}

编辑:

瓦尔格林德输出(test.c 中的第 149 行对应于:memcpy(cipher[i*16], chunk, 16*sizeof(uint8_t));

Valgrind outputs:
InvalidWrite: Invalid write of size 4
Call stack:
/usr/lib/valgrind/vgpreload_memcheck-x86-linux.so        0x402E08A: memcpy
/home/dev/aes/test.c|149|0x804A604:        aes_encrypt_block
/home/dev/aes/test.c|59|0x8049AFE:        main
Address 0x0 is not stack'd, malloc'd or (recently) free'd
Valgrind found 1 errors!

如果pad_bytes == 16则此循环:

for(j=0; j<=pad_bytes; j++) {
    chunk[15-j] = pad_bytes;
}

将在chunk开始之前写入无效位置,可能会损坏您的堆。

它可能应该是:

for(j=0; j<pad_bytes; j++) {
    chunk[15-j] = pad_bytes;
}

另请注意,您似乎也有许多内存泄漏,其中通过malloc分配的内存没有free d,例如 chunkchunk_cipher aes_encrypt_block().

我会说这一行

memcpy(cipher[i*16], chunk_cipher, 16*sizeof(uint8_t));

应该是

memcpy((*cipher) + i*16, chunk_cipher, 16*sizeof(uint8_t));

(对于memcpy()的第二个第二个调用,请同样应用于第一个参数)


甚至更好的是将aes_encrypt_block()的签名从

void aes_encrypt_block(uint8_t **message, uint8_t **cipher, uint8_t blocks, uint8_t pad_bytes) 

void aes_encrypt_block(uint8_t **message, uint8_t (*cipher)[16], uint8_t blocks, uint8_t pad_bytes)

并做

memcpy(cipher + i, chunk_cipher, sizeof(*cipher));

(对于memcpy()的第二个第二个调用,请同样应用于第一个参数)

相关内容

  • 没有找到相关文章

最新更新