0

prova是一个纯文本文件,其中包含hello i am a pc

加密:

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包含纯文本加上一些随机无用和不可读的字符。

4

2 回答 2

3

当你读到你的字符串时,

fread(plain_text, 1, 16, fp);

你可能会得到“你好,我是一台 PC”(15 个字节)加上一个返回。

然后加密 16 个字节,解密这 16 个字节,但仍然没有字符串 terminator,因此 printf 会写入额外的内容(或可能是核心转储)。

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

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;
}
于 2013-01-05T17:47:13.873 回答
0

获取过大的解密文件对于数据库等二进制文件来说是个问题。但是,如果您以实际长度作为前缀编写文件,则可以适当地截断“太大”的文件,假设加密程序和解密程序已在此协议上达成一致。

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

您将如何管理您的密钥?

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

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

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

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

您要使用 HMAC 保护内容吗?

玩得开心。

于 2016-09-01T23:17:21.883 回答