将文件读取为 unsigned char* 以在 C++ 中使用 openssl 进行加密
Read file as unsigned char* to encrypt with openssl in c++
据我所知,openssl 中的 EVP funktions 只接受 unsigned char *
作为输入。
示例代码为:
int gcm_encrypt(unsigned char *plaintext, int plaintext_len,
unsigned char *aad, int aad_len,
unsigned char *key,
unsigned char *iv, int iv_len,
unsigned char *ciphertext,
unsigned char *tag)
{
EVP_CIPHER_CTX *ctx;
int len;
int ciphertext_len;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new()))
handleErrors();
/* Initialise the encryption operation. */
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
handleErrors();
/*
* Set IV length if default 12 bytes (96 bits) is not appropriate
*/
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
handleErrors();
/* Initialise key and IV */
if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv))
handleErrors();
/*
* Provide any AAD data. This can be called zero or more times as
* required
*/
if(1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len))
handleErrors();
/*
* Provide the message to be encrypted, and obtain the encrypted output.
* EVP_EncryptUpdate can be called multiple times if necessary
*/
if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
handleErrors();
ciphertext_len = len;
/*
* Finalise the encryption. Normally ciphertext bytes may be written at
* this stage, but this does not occur in GCM mode
*/
if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
handleErrors();
ciphertext_len += len;
/* Get the tag */
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
handleErrors();
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return ciphertext_len;
}
我想open/read任何类型的文件并将其作为明文加密。
代码看起来如何能让我读取任何类型的文件?
尝试时,我总是遇到初始化错误:
FILE * pFile;
long lSize;
char * buffer; // same error when using: unsigned char * buffer;
size_t result;
pFile = fopen ( "test.txt" , "rb" );
if (pFile==NULL) {fputs ("File error",stderr); exit (1);}
// obtain file size:
fseek (pFile , 0 , SEEK_END);
lSize = ftell (pFile);
rewind (pFile);
// allocate memory to contain the whole file:
buffer = (char*) malloc (sizeof(char)*lSize);
if (buffer == NULL) {fputs ("Memory error",stderr); exit (2);}
// copy the file into the buffer:
result = fread (buffer,1,lSize,pFile);
if (result != lSize) {fputs ("Reading error",stderr); exit (3);}
cout << typeid(buffer).name() << endl;
unsigned char plaintext[] = buffer; <- Array initializer must be an initializer list or string literal
是否还有其他库也支持更足以完成此任务的 aead 或 openssl 功能?
我收到的错误信息是:
evp-encrypt_input_file.cpp:43:16: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
if (result != lSize) {fputs ("Reading error",stderr); exit (3);}
~~~~~~~^~~~~~~~
evp-encrypt_input_file.cpp:48:19: error: initializer fails to determine size of ‘plaintext’
unsigned char plaintext[] = buffer;
^~~~~~~~~
evp-encrypt_input_file.cpp:48:33: error: array must be initialized with a brace-enclosed initializer
unsigned char plaintext[] = buffer;
另外代码必须是c++,不能用c。
找到更有效的方法来解决问题。
首先使用 unsigned char *
是个坏主意。
在官方documentation中有一个更好的解决方法。
不过我做了两个cahnges。
第一个cahnge:
EVP_CipherInit_ex(&ctx, EVP_aes_128_cbc(), NULL, NULL, NULL,do_encrypt);
至
EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, NULL, NULL,do_encrypt);
第二个变化:
inlen = fread(inbuf, 1, 1024, in);
至
size_t a = fread(inbuf, 1, 1024, in); inlen = int(a);
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/aes.h>
#include <openssl/rand.h>
int do_crypt(FILE *in, FILE *out, int do_encrypt){
/* Allow enough space in output buffer for additional block */
unsigned char inbuf[1024], outbuf[1024 + EVP_MAX_BLOCK_LENGTH];
int outlen;
int inlen;
EVP_CIPHER_CTX *ctx;
/* Bogus key and IV: we'd normally set these from
* another source.
*/
unsigned char key[] = "0123456789abcdeF";
unsigned char iv[] = "1234567887654321";
/* Don't set key or IV right away; we want to check lengths */
ctx = EVP_CIPHER_CTX_new();
EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, NULL, NULL, do_encrypt);
OPENSSL_assert(EVP_CIPHER_CTX_key_length(ctx) == 16);
OPENSSL_assert(EVP_CIPHER_CTX_iv_length(ctx) == 16);
/* Now we can set key and IV */
EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, do_encrypt);
for(;;){
size_t a = fread(inbuf, 1, 1024, in);
inlen = int(a);
if (inlen <= 0) break;
if(!EVP_CipherUpdate(ctx, outbuf, &outlen, inbuf, inlen)){
/* Error */
EVP_CIPHER_CTX_free(ctx);
return 0;
}
fwrite(outbuf, 1, outlen, out);
}
if(!EVP_CipherFinal_ex(ctx, outbuf, &outlen)){
/* Error */
EVP_CIPHER_CTX_free(ctx);
return 0;
}
fwrite(outbuf, 1, outlen, out);
EVP_CIPHER_CTX_free(ctx);
return 1;
}
int main(int arg, char* argv[]){
FILE * in = fopen("in_file", "rb");
FILE * out = fopen("out_file", "wb");
do_crypt(in, out, 1);
}
据我所知,openssl 中的 EVP funktions 只接受 unsigned char *
作为输入。
示例代码为:
int gcm_encrypt(unsigned char *plaintext, int plaintext_len,
unsigned char *aad, int aad_len,
unsigned char *key,
unsigned char *iv, int iv_len,
unsigned char *ciphertext,
unsigned char *tag)
{
EVP_CIPHER_CTX *ctx;
int len;
int ciphertext_len;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new()))
handleErrors();
/* Initialise the encryption operation. */
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
handleErrors();
/*
* Set IV length if default 12 bytes (96 bits) is not appropriate
*/
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
handleErrors();
/* Initialise key and IV */
if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv))
handleErrors();
/*
* Provide any AAD data. This can be called zero or more times as
* required
*/
if(1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len))
handleErrors();
/*
* Provide the message to be encrypted, and obtain the encrypted output.
* EVP_EncryptUpdate can be called multiple times if necessary
*/
if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
handleErrors();
ciphertext_len = len;
/*
* Finalise the encryption. Normally ciphertext bytes may be written at
* this stage, but this does not occur in GCM mode
*/
if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
handleErrors();
ciphertext_len += len;
/* Get the tag */
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
handleErrors();
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return ciphertext_len;
}
我想open/read任何类型的文件并将其作为明文加密。 代码看起来如何能让我读取任何类型的文件?
尝试时,我总是遇到初始化错误:
FILE * pFile;
long lSize;
char * buffer; // same error when using: unsigned char * buffer;
size_t result;
pFile = fopen ( "test.txt" , "rb" );
if (pFile==NULL) {fputs ("File error",stderr); exit (1);}
// obtain file size:
fseek (pFile , 0 , SEEK_END);
lSize = ftell (pFile);
rewind (pFile);
// allocate memory to contain the whole file:
buffer = (char*) malloc (sizeof(char)*lSize);
if (buffer == NULL) {fputs ("Memory error",stderr); exit (2);}
// copy the file into the buffer:
result = fread (buffer,1,lSize,pFile);
if (result != lSize) {fputs ("Reading error",stderr); exit (3);}
cout << typeid(buffer).name() << endl;
unsigned char plaintext[] = buffer; <- Array initializer must be an initializer list or string literal
是否还有其他库也支持更足以完成此任务的 aead 或 openssl 功能?
我收到的错误信息是:
evp-encrypt_input_file.cpp:43:16: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
if (result != lSize) {fputs ("Reading error",stderr); exit (3);}
~~~~~~~^~~~~~~~
evp-encrypt_input_file.cpp:48:19: error: initializer fails to determine size of ‘plaintext’
unsigned char plaintext[] = buffer;
^~~~~~~~~
evp-encrypt_input_file.cpp:48:33: error: array must be initialized with a brace-enclosed initializer
unsigned char plaintext[] = buffer;
另外代码必须是c++,不能用c。
找到更有效的方法来解决问题。
首先使用 unsigned char *
是个坏主意。
在官方documentation中有一个更好的解决方法。
不过我做了两个cahnges。
第一个cahnge:
EVP_CipherInit_ex(&ctx, EVP_aes_128_cbc(), NULL, NULL, NULL,do_encrypt);
至
EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, NULL, NULL,do_encrypt);
第二个变化:
inlen = fread(inbuf, 1, 1024, in);
至
size_t a = fread(inbuf, 1, 1024, in); inlen = int(a);
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/aes.h>
#include <openssl/rand.h>
int do_crypt(FILE *in, FILE *out, int do_encrypt){
/* Allow enough space in output buffer for additional block */
unsigned char inbuf[1024], outbuf[1024 + EVP_MAX_BLOCK_LENGTH];
int outlen;
int inlen;
EVP_CIPHER_CTX *ctx;
/* Bogus key and IV: we'd normally set these from
* another source.
*/
unsigned char key[] = "0123456789abcdeF";
unsigned char iv[] = "1234567887654321";
/* Don't set key or IV right away; we want to check lengths */
ctx = EVP_CIPHER_CTX_new();
EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, NULL, NULL, do_encrypt);
OPENSSL_assert(EVP_CIPHER_CTX_key_length(ctx) == 16);
OPENSSL_assert(EVP_CIPHER_CTX_iv_length(ctx) == 16);
/* Now we can set key and IV */
EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, do_encrypt);
for(;;){
size_t a = fread(inbuf, 1, 1024, in);
inlen = int(a);
if (inlen <= 0) break;
if(!EVP_CipherUpdate(ctx, outbuf, &outlen, inbuf, inlen)){
/* Error */
EVP_CIPHER_CTX_free(ctx);
return 0;
}
fwrite(outbuf, 1, outlen, out);
}
if(!EVP_CipherFinal_ex(ctx, outbuf, &outlen)){
/* Error */
EVP_CIPHER_CTX_free(ctx);
return 0;
}
fwrite(outbuf, 1, outlen, out);
EVP_CIPHER_CTX_free(ctx);
return 1;
}
int main(int arg, char* argv[]){
FILE * in = fopen("in_file", "rb");
FILE * out = fopen("out_file", "wb");
do_crypt(in, out, 1);
}