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 包含纯文本以及一些随机无用且无法读取的字符。
答案 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保护内容吗?
玩得开心。