簡體   English   中英

將文件讀取為無符號字符 * 以在 C++ 中使用 openssl 進行加密

[英]Read file as unsigned char* to encrypt with openssl in c++

據我所知,openssl 中的 EVP 功能只接受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;
}

我想打開/讀取任何類型的文件並將其用作明文來加密它。 這樣的代碼將如何使我能夠讀取任何類型的文件?

嘗試時,我總是以初始化錯誤告終:

    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 funktion 更足以完成此任務?

我得到的錯誤信息是:

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 *是一個壞主意。 在官方文檔中有一種更好的解決方案。 但是,我做了兩次更改。

第一次更改:

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); 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);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM