memcpy:第二次通话后的Segfault

时间:2013-12-19 12:30:59

标签: c segmentation-fault memcpy

我正在为Karl Malbrain的AES implementation编写一个包装器来处理大于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.\n\n%s {0/1} OUT\n\n\t0 - encrypt\n\t1 -     decrypt\n\tOUT - file to read from / to write to.\n\n", argv[0]);
        return 0;
    } else {
        mode = atoi(argv[1]);
        if(mode<0 || mode>1) {
            printf("Wrong arguments supplied.\n\n%s {0/1} OUT\n\n\t0 -     encrypt\n\t1 - decrypt\n\tOUT - file to read from / to write to.\n\n", 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: %d\n\n", 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 %s\n", 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("%s\n", 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));
}

修改

Valgrind输出(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!

2 个答案:

答案 0 :(得分:2)

如果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;
}

另请注意,您似乎还有一些memory leaks,其中通过malloc分配的内存不在free d,例如chunk中的chunk_cipheraes_encrypt_block()

答案 1 :(得分:0)

我会说这行

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()的第二次调用适用于第一个参数)