Openssl EVP "EVP_CTRL_GCM_GET_TAG" falla

Sep 02 2020

Estoy usando Openssl EVP en C ++. De alguna manera, la etiqueta falla. Mi código:

int do_crypt(FILE *in, FILE *out){
    unsigned char inbuf[1024], aadbuf[1024], outbuf[1024 + EVP_MAX_BLOCK_LENGTH];
    int inlen, lenbuf, unused, outlen;
    EVP_CIPHER_CTX *ctx;

    unsigned char key[] = "0123456789abcdeF";
    unsigned char iv[] = "123456788765";
    unsigned char tag[16];

    ctx = EVP_CIPHER_CTX_new();
    EVP_CIPHER_CTX_init(ctx);
    EVP_CipherInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL, do_encrypt);
    EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, sizeof(iv), NULL);

    OPENSSL_assert(EVP_CIPHER_CTX_key_length(ctx) == 16);
    OPENSSL_assert(EVP_CIPHER_CTX_iv_length(ctx) == 12);
    EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, 1);
    
    FILE * aad_f = fopen("aad.txt", "rb");
    
    for(;;){
        size_t a = fread(aadbuf, 1, 1024, aad_f);
        lenbuf = int(a);
        
        if (lenbuf <= 0) break;
        EVP_CipherUpdate(ctx, NULL, &unused, aadbuf, lenbuf);
     }
    /* Input text */
    for(;;){
        size_t a = fread(inbuf, 1, 1024, in);
        inlen = int(a);
        if (inlen <= 0) break;
        EVP_CipherUpdate(ctx, outbuf, &outlen, inbuf, inlen);
        fwrite(outbuf, 1, outlen, out);
        }
    
    EVP_CipherFinal_ex(ctx, outbuf, &outlen);
    EVP_CIPHER_CTX_free(ctx);
    fwrite(outbuf, 1, outlen, out);
    
    if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag)){
         cout << "error get tag" << endl;
         return 0;
   }
        FILE * tag_f = fopen("tag.txt", "wb");
        fwrite(tag, 1, sizeof(tag), tag_f);
        cout << tag << endl;
    }
    return 0;
    
    }

¿Pero por qué? Todas las demás funciones de EVP funcionan bien. ¿Qué extraño? ¿Tengo que llamar a otra función? En lugar de la etiqueta, se ha escrito @ \ 267 * en el archivo tag.txt.

Respuestas

Topaco Sep 01 2020 at 23:30

Hay dos errores en el código:

  • Dado que sizeofse utiliza para determinar la longitud del IV, también se cuenta el terminador 0 y se determina la longitud 13 incorrecta. En lugar de sizeof, se strlendebe aplicar, que devuelve el valor correcto 12.
  • El contexto se libera antes de que se determine la etiqueta, EVP_CIPHER_CTX_freees decir, se llama antes EVP_CIPHER_CTX_ctrl. Este orden debe invertirse.

Con estos cambios, se crearán el texto cifrado y la etiqueta correctos.

Tenga en cuenta que el par de llave fija / IV solo se puede utilizar para realizar pruebas. En la práctica, un par clave / IV solo se puede usar una vez, especialmente para GCM.