使用libgcrypt使用aes256-cbc在C中加密和解密文件的问题

时间:2013-01-05 17:38:23

标签: c encryption aes

prova 是一个纯文本文件,其中包含你好我是个电脑

加密

FILE *fp = fopen("prova", "r+");
FILE *fpout = fopen("out", "w+");
while(!feof(fp)){
    memset(plain_text, 0, sizeof(plain_text));
    retval = fread(plain_text, 1, 16, fp);
    txtLenght = sizeof(plain_text);
    encBuffer = malloc(txtLenght);
    algo = gcry_cipher_map_name(name);
    gcry_cipher_open(&hd, algo, GCRY_CIPHER_MODE_CBC, 0);
    gcry_cipher_setkey(hd, key, keyLength);
    gcry_cipher_setiv(hd, iniVector, blkLength);
    gcry_cipher_encrypt(hd, encBuffer, txtLenght, plain_text, txtLenght);
    fwrite(encBuffer, 1, 16, fpout);
}

解密:

FILE *fp = fopen("out", "r+");
FILE *fpout = fopen("origdec", "w+");
while(!feof(fp)){
    memset(plain_text, 0, sizeof(plain_text));
    retval = fread(plain_text, 1, 16, fp);
    txtLenght = sizeof(plain_text);
    encBuffer = malloc(txtLenght);
    algo = gcry_cipher_map_name(name);
    gcry_cipher_open(&hd, algo, GCRY_CIPHER_MODE_CBC, 0);
    gcry_cipher_setkey(hd, key, keyLength);
    gcry_cipher_setiv(hd, iniVector, blkLength);
    gcry_cipher_decrypt(hd, encBuffer, txtLenght, plain_text, txtLenght);
    fwrite(encBuffer, 1, 16, fpout);
}

其中:

char key[32] = {0x80};
char iniVector[16] = {0};
char plain_text[16];
char *encBuffer = NULL;

问题:当我解密加密文件时,文件 origdec 包含纯文本以及一些随机无用且无法读取的字符。

2 个答案:

答案 0 :(得分:3)

当你读到你的字符串时,

fread(plain_text, 1, 16, fp);

你可能会得到“你好我是个电脑”(15个字节)加上一个回报。

然后你加密16个字节,解密那16个字节,,你仍然没有字符串终结符,这样printf会写出额外的东西(或者可能是coredump)。

您需要在字符串末尾添加二进制零。尝试:

fread(plain_text, 1, 16, fp);
plain_text[15] = 0x0;

并查看这是否会发生任何变化。

更新

您的代码中存在多个错误。例如,您始终重新初始化密码,并始终重新分配encBuffer,从而导致内存泄漏。我纠正了一些错误;仍有加密文件的功能被填充到16个字节。有一些技术可以摆脱填充;例如,你可能想看看PKCS#7。

我已经任意初始化了一些常量,并采用了就地加密/解密(你不仅限于16的bufSize;但你必须检查填充策略)。

#include <stdio.h>
#include <gcrypt.h>

int main()
{
    char iniVector[16];
    char *encBuffer = NULL;
    FILE *fp, *fpout;
    char *key       = "topolino e minni";
    gcry_cipher_hd_t hd;
    int     bufSize = 16, bytes, algo = GCRY_CIPHER_AES128, keyLength = 16, blkLength = 16;

    memset(iniVector, 0, 16);

    encBuffer = malloc(bufSize);

    fp = fopen("prova", "r");
    fpout = fopen("out", "w");

    gcry_cipher_open(&hd, algo, GCRY_CIPHER_MODE_CBC, 0);
    gcry_cipher_setkey(hd, key, keyLength);
    gcry_cipher_setiv(hd, iniVector, blkLength);

    while(!feof(fp))
    {
        bytes = fread(encBuffer, 1, bufSize, fp);
        if (!bytes) break;
        while(bytes < bufSize)
            encBuffer[bytes++] = 0x0;
        gcry_cipher_encrypt(hd, encBuffer, bufSize, NULL, 0);
        bytes = fwrite(encBuffer, 1, bufSize, fpout);
    }
    gcry_cipher_close(hd);
    fclose(fp);
    fclose(fpout);

    // Decrypt. Same algo as before

    gcry_cipher_open(&hd, algo, GCRY_CIPHER_MODE_CBC, 0);
    gcry_cipher_setkey(hd, key, keyLength);
    gcry_cipher_setiv(hd, iniVector, blkLength);

    fp = fopen("out", "r");
    fpout = fopen("origdec", "w");
    while(!feof(fp))
    {
        bytes = fread(encBuffer, 1, bufSize, fp);
        if (!bytes) break;
        gcry_cipher_decrypt(hd, encBuffer, bufSize, NULL, 0);
        bytes = fwrite(encBuffer, 1, bufSize, fpout);
    }
    gcry_cipher_close(hd);

    free(encBuffer); encBuffer = NULL;
    return 0;
}

答案 1 :(得分:0)

获取过大的解密文件是二进制文件(如数据库)的问题。但是,如果您使用实际长度编写文件作为前缀,则可以截断&#34;太大&#34;假设加密器程序和解密程序已就此协议达成一致,则适当地提交文件。

我还要在前缀中包含初始化向量,以便解密器不必猜测,并且两个程序不必在两个程序中对IV进行硬编码。因此,加密器使用gcry_create_nonce()生成IV,解密器在解密文件的其余部分之前从文件中读取它。

您将如何管理您的密钥?

基于密码的加密适用于gcrypt gcry_kdf_derive()函数(使用SHA512 / 128字节盐的PBKDF2)。同样,salt可以由加密器生成并放在文件的前面;解密器在文件前面拉盐,然后在gcrypt gcry_kdf_derive()调用中使用相同的密码。

因此,加密器读取明文并生成以下文件:

 salt || IV || source-size || ciphertext-blocks

解密器现在可以重建原始文件。

您打算用HMAC保护内容吗?

玩得开心。