[英]Issues with encrypting a file using openssl evp api(aes256cbc)
我試圖在這種情況下讀取文件(.txt),並使用openssl的EVP API使用AES256CBC對其進行加密/解密。 (讀(plain.txt) - >創建(encrypt.txt) - >創建(decrypt.txt))
# include <stdio.h>
# include <stdlib.h>
# include <openssl/evp.h>
# include <openssl/aes.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <unistd.h>
# include <string.h>
# include <assert.h>
# include <error.h>
# include "debug.h"
# define SIZE 32
char buf[SIZE];
int aes_init(unsigned char* pwd, unsigned int pwd_len, unsigned char * salt, EVP_CIPHER_CTX *e_ctx, EVP_CIPHER_CTX *d_ctx)
{
int i, rounds =5; /* rounds */
unsigned char key[32], iv[32];
i = EVP_BytesToKey(EVP_aes_256_cbc(),EVP_sha1(),salt,pwd,pwd_len,rounds,key,iv);
if(i != 32)
{
printf("\n Error,Incorrect key size generated:%d:\n",i);
return -1;
}
EVP_CIPHER_CTX_init(e_ctx);
EVP_EncryptInit_ex(e_ctx, EVP_aes_256_cbc(), NULL, key, iv);
EVP_CIPHER_CTX_init(d_ctx);
EVP_DecryptInit_ex(d_ctx, EVP_aes_256_cbc(), NULL, key, iv);
return 0;
}
unsigned char* aes_encrypt(EVP_CIPHER_CTX *e,unsigned char * plain_text, unsigned int * len ) /* this function encryptes the file:fd is passed as parameter */
{
int ci_len = (*len) + AES_BLOCK_SIZE;
int flen =0;
unsigned char * cipher_text = malloc(ci_len);
EVP_EncryptInit_ex(e, NULL, NULL, NULL, NULL); /* allows reusing of e for multiple cipher cycles */
EVP_EncryptUpdate(e, cipher_text, &ci_len, plain_text, *len); /* Update cipher text */
EVP_EncryptFinal_ex(e, cipher_text+ci_len, &flen); /* updates the remaining bytes */
*len = ci_len + flen;
return cipher_text;
}
unsigned char* aes_decrypt(EVP_CIPHER_CTX *e, unsigned char * c_text, unsigned int * len)
{
int pi_len = (*len);
int flen = 0;
unsigned char * plain_text = malloc(pi_len);
EVP_DecryptInit_ex(e, NULL, NULL, NULL, NULL);
EVP_DecryptUpdate(e, plain_text, &pi_len, c_text, *len);
EVP_DecryptFinal_ex(e, plain_text+pi_len, &flen);
(*len) = pi_len + flen;
return plain_text;
}
int main(int argc,char **argv)
{
if(argc != 2)
{
perror("\n Error:\nCorrect Usage: Enter Password to be used");
exit(-1);
}
EVP_CIPHER_CTX en,de; /* The EVP structure which keeps track of all crypt operations see evp.h for details */
int in, out, fd, dec,i =0; /* fd for input and output files and random dev*/
unsigned int pwd_len = strlen((const char *)argv[1]); /* Length of the pwd supplied by the user */
unsigned char *pwd =(unsigned char*) argv[1]; /* Pointer to the pwd supplied by the user */
unsigned int rd= 0;
unsigned char salt[8];
unsigned char * encry = NULL, *decry = NULL;
i =0;
if((in = open("plain.txt",O_RDONLY)) == -1) /* Opening a plain text file for encryption */
{
perror("\n Error,Opening file for reading::");
exit(-1);
}
if((fd = open("/dev/random", O_RDONLY)) == -1)
{
perror("\n Error,Opening /dev/random::");
exit(-1);
}
else
{
if(read(fd,salt,8) == -1)
{
perror("\n Error,reading from /dev/random::");
exit(-1);
}
}
if(aes_init(pwd,pwd_len,(unsigned char*) salt,&en,&de)) /* Generating Key and IV and initializing the EVP struct */
{
perror("\n Error, Cant initialize key and IV:");
return -1;
}
if((out = open("encrypt.txt",O_RDWR|O_CREAT,0400 | 0200)) == -1)
{
dbug_p("ENC%d",out);
perror("\n Error,Opening the file to be written::");
exit(-1);
}
rd =0;
while((rd = read(in,buf,SIZE)) >0)
{
dbug_p("\nREAD::%s::%d*\n",buf,rd);
encry = aes_encrypt(&en,(unsigned char*) buf, &rd);
if((write(out,encry,rd)) != rd)
{
perror("\n Error,Required encrypted bytes not written::");
exit(-1);
}
free(encry);
}
rd =0;
if((dec = open("dec22.txt",O_RDWR|O_CREAT,0400 | 0200)) == -1)
{
dbug_p("dec%d",dec);
perror("\n Error,Opening the decrypting o/p file::");
exit(-1);
}
if((lseek(out,0,SEEK_SET)) != 0) perror("\n Error:setting lseek::");
for(i=0;i<SIZE;i++) buf[i] =0;
while((rd = read(out,dbuf,SIZE)) >0)
{
decry = aes_decrypt(&de,(unsigned char*) dbuf, &rd);
if((write(dec,decry,rd)) != rd)
{
perror("\n Error,Required decrypted bytes not written::");
exit(-1);
}
free(decry);
}
close(in);
close(fd);
EVP_CIPHER_CTX_cleanup(&en);
EVP_CIPHER_CTX_cleanup(&de);
return 0;
}
我的問題是,當我解密加密文件時,我得到的文件沒有正確解密(例如,正確的字符串垃圾,正確的字符串垃圾 ...)
abhi@ubuntu:~/mpro/EFF$ cat plain.txt
Today is tuesday
tomorrow is wednesday
then thursday and friday and saturday
finally sunday
解密文件
cat dec22.txt
Today is tuesdayw)Q������O-%�A�8���R��.�O���and saturday
finally sunday
這可能是什么原因。 它是否還在讀取其他內容,或者我在某處犯了任何愚蠢的錯誤。
編輯 :如果我只是加密一個數組(嘗試用36char長),它正確加密和解密,而不會打印任何垃圾。
我想我正在丟失(不處理)一些* nix文件結構的詳細信息.. ?? 還是有更好的方法對文件進行加密?
非常感謝
我認為您的分析是錯誤的。 這個循環是有問題的:
while((rd = read(in,buf,SIZE)) >0)
{
dbug_p("\nREAD::%s::\n",buf);
encry = aes_encrypt(&en,(unsigned char*) buf, &rd);
dbug_p("\n EN::%s::\n",encry);
decry = aes_decrypt(&de,(unsigned char*) encry,&rd);
dbug_p("\n DE::%s::\n",decry);
free(encry);
free(decry);
}
首先,因為您使用%s
進行打印,所以期望終止符為零。 但是,加密/解密的數據不是零終止的。 相反,您應該使用類似於for (i = 0; i < rd; i++) printf("%02x ");
的循環來打印rd
字符for (i = 0; i < rd; i++) printf("%02x ");
-這就是為什么您對問題的分析可能存在缺陷的原因。
其次,我認為在您的實際問題中,您一次讀取SIZE
個字節,並將其分別發送到aes_decrypt()
。 這將失敗,因為EVP_DecryptFinal_ex()
時間過早(在讀取所有加密塊之前)。 你有兩個選擇。 您可以在每次循環迭代中通過EVP_DecryptUpdate()
發送讀取的字節,並在完成循環后調用EVP_DecryptFinal()
(並在循環之前進行相應的初始化),或者先將整個文件讀入緩沖區,然后再通過aes_decrypt()
發送aes_decrypt()
一口氣。
或者換句話說,你需要發送從導致整個數據塊aes_encrypt()
以后aes_decrypt()
您不能以不同的塊形式發送它們,除非將功能分開並在單獨的塊上使用EVP“更新”功能。
while((rd = read(in,buf,SIZE)) >0)
{
dbug_p("\nREAD::%s::%d*\n",buf,rd);
encry = aes_encrypt(&en,(unsigned char*) buf, &rd);
和,
unsigned char* aes_encrypt(EVP_CIPHER_CTX *e,unsigned char * plain_text, unsigned int * len ) /* this function encryptes the file:fd is passed as parameter */
{
int ci_len = (*len) + AES_BLOCK_SIZE;
int flen =0;
unsigned char * cipher_text = malloc(ci_len);
EVP_EncryptInit_ex(e, NULL, NULL, NULL, NULL); /* allows reusing of e for multiple cipher cycles */
EVP_EncryptUpdate(e, cipher_text, &ci_len, plain_text, *len); /* Update cipher text */
EVP_EncryptFinal_ex(e, cipher_text+ci_len, &flen); /* updates the remaining bytes */
您多次調用EVP_EncryptFinal_ex
。 最后應該只調用一次。 您進行解密的方式也是如此。
這是手冊頁中有關如何進行加密的簡單示例。 具有類似的解密功能,它應該可以工作。
int do_crypt(char *outfile)
{
unsigned char outbuf[1024];
int outlen, tmplen;
/* Bogus key and IV: we'd normally set these from
* another source.
*/
unsigned char key[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
unsigned char iv[] = {1,2,3,4,5,6,7,8};
char intext[] = "Some Crypto Text";
EVP_CIPHER_CTX ctx;
FILE *out;
EVP_CIPHER_CTX_init(&ctx);
EVP_EncryptInit_ex(&ctx, EVP_bf_cbc(), NULL, key, iv);
if(!EVP_EncryptUpdate(&ctx, outbuf, &outlen, intext, strlen(intext)))
{
/* Error */
return 0;
}
/* Buffer passed to EVP_EncryptFinal() must be after data just
* encrypted to avoid overwriting it.
*/
if(!EVP_EncryptFinal_ex(&ctx, outbuf + outlen, &tmplen))
{
/* Error */
return 0;
}
outlen += tmplen;
EVP_CIPHER_CTX_cleanup(&ctx);
/* Need binary mode for fopen because encrypted data is
* binary data. Also cannot use strlen() on it because
* it wont be null terminated and may contain embedded
* nulls.
*/
out = fopen(outfile, "wb");
fwrite(outbuf, 1, outlen, out);
fclose(out);
return 1;
}
下面的示例根據您的情況讀取文件。 查看如何使用Update
(多次調用)和Final
( Final
一次)例程。
int do_crypt(FILE *in, FILE *out, int do_encrypt)
{
/* Allow enough space in output buffer for additional block */
inbuf[1024], outbuf[1024 + EVP_MAX_BLOCK_LENGTH];
int inlen, outlen;
/* Bogus key and IV: we'd normally set these from
* another source.
*/
unsigned char key[] = "0123456789";
unsigned char iv[] = "12345678";
/* Don't set key or IV because we will modify the parameters */
EVP_CIPHER_CTX_init(&ctx);
EVP_CipherInit_ex(&ctx, EVP_rc2(), NULL, NULL, NULL, do_encrypt);
EVP_CIPHER_CTX_set_key_length(&ctx, 10);
/* We finished modifying parameters so now we can set key and IV */
EVP_CipherInit_ex(&ctx, NULL, NULL, key, iv, do_encrypt);
for(;;)
{
inlen = fread(inbuf, 1, 1024, in);
if(inlen <= 0) break;
if(!EVP_CipherUpdate(&ctx, outbuf, &outlen, inbuf, inlen))
{
/* Error */
EVP_CIPHER_CTX_cleanup(&ctx);
return 0;
}
fwrite(outbuf, 1, outlen, out);
}
if(!EVP_CipherFinal_ex(&ctx, outbuf, &outlen))
{
/* Error */
EVP_CIPHER_CTX_cleanup(&ctx);
return 0;
}
fwrite(outbuf, 1, outlen, out);
EVP_CIPHER_CTX_cleanup(&ctx);
return 1;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.