Сбой EVP_DecryptFinal_ex с кодом возврата 0 - PullRequest
1 голос
/ 28 февраля 2020

Я пытаюсь расшифровать данные, используя метод openssl AES GCM. Однако это всегда не удается с кодом возврата 0.

Я выполнил поиск по переполнению стека и вижу много вопросов, опубликованных по той же проблеме. Но ни один из предложенных ответов не сработал для меня.

Следовательно, снова задаю тот же вопрос.

Вот код, который я пытаюсь использовать

int gcm_encrypt(std::vector<uint8_t>& key, std::vector<uint8_t>& plainText, std::vector<uint8_t>& encData)
{
    unsigned char iv[AES_BLOCK_SIZE] = {'T', 'H', 'I', 'S', 'I', 'S', 'S', 'E', 'C', 'R', 'E', 'T', 'K', 'E', 'Y', 'Y'};
    unsigned char tag[AES_BLOCK_SIZE] = {0};
    int encDataLen = plainText.size() + EVP_CIPHER_block_size(EVP_aes_256_gcm()) + sizeof(tag);
    unsigned char* et = (unsigned char*) calloc(encDataLen, sizeof(unsigned char));

    std::cout << "Plain text Len: " << plainText.size() << std::endl;
    std::cout << "Tag Len: " << sizeof(tag) << std::endl;
    std::cout << "Cipher block Len: " << EVP_CIPHER_block_size(EVP_aes_256_gcm()) << std::endl;
    std::cout << "et Len: " << encDataLen << std::endl;

    EVP_CIPHER_CTX* ctx;

    int len;

    int ciphertext_len;

    /* Create and initialise the context */
    if (!(ctx = EVP_CIPHER_CTX_new()))
    {
        std::cout << "Failed to initialized ctx -1" << std::endl;
        return 0;
    }

    /* Initialise the encryption operation. */
    if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
    {
        std::cout << "Failed to init encrypt ctx -2" << std::endl;
        return 0;
    }

    /*
    * Set IV length if default 12 bytes (96 bits) is not appropriate
    */
    if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, sizeof(iv), NULL))
    {
        std::cout << "Failed to init encrypt ctx -3" << std::endl;
        return 0;
    }

    /* Initialise key and IV */
    if (1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key.data(), iv))
    {
        std::cout << "Failed to init encrypt ctx -4" << std::endl;
        return 0;
    }
    EVP_CIPHER_CTX_set_padding(ctx, 0);

    /*
    * Provide any AAD data. This can be called zero or more times as
    * required
    */
    /*if (1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len))
    {
    std::cout << "Failed to init encrypt ctx" << std::endl;
    return 0;
    }*/

    /*
    * 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, et, &len, plainText.data(), plainText.size()))
    {
        std::cout << "Failed to init encrypt ctx -5" << std::endl;
        return 0;
    }
    ciphertext_len = len;
    std::cout << "1. Encrypted text len : " << ciphertext_len << std::endl;

    /*
    * 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, et, &len))
    {
        std::cout << "Failed to init encrypt ctx -6" << std::endl;
        return 0;
    }
    ciphertext_len += len;

    /* Get the tag */
    if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
    {
        std::cout << "Failed to init encrypt ctx -7" << std::endl;
        return 0;
    }

    /* Clean up */
    EVP_CIPHER_CTX_free(ctx);

    std::cout << "2. ciphertext_len : " << ciphertext_len << std::endl;

    auto it = encData.begin();
    int l = encDataLen - ciphertext_len - sizeof(tag);
    encData.insert(it, et, et + ciphertext_len);
    encData.insert(encData.end(), tag, tag + sizeof(tag));
    for (auto i = 0; i < l; i++)
        encData.push_back(0);
    printf("Vector size after copying encData: %ld\n", encData.size());
    free(et);

    return encData.size();
}

Выше код выполняет шифрование наряду с заполнением и маркировкой. Как только шифрование выполнено, я пишу зашифрованные данные + тег + заполнение в выходной буфер. Это правильно? Или я должен только записать только зашифрованные данные в выходной буфер.

Код для расшифровки, как показано ниже

int gcm_decrypt(std::vector<uint8_t> cipherText, std::vector<uint8_t> key, std::vector<uint8_t> plaintext)
{
    EVP_CIPHER_CTX* ctx;
    int len;
    int plaintext_len;
    int ret;

    unsigned char iv[AES_BLOCK_SIZE] = {'T', 'H', 'I', 'S', 'I', 'S', 'S', 'E', 'C', 'R', 'E', 'T', 'K', 'E', 'Y', 'Y'};
    unsigned char tag[AES_BLOCK_SIZE] = {0};
    int encDataLen = cipherText.size() + EVP_CIPHER_block_size(EVP_aes_256_gcm()) + sizeof(tag);

    unsigned char* pt = (unsigned char*) calloc(encDataLen, sizeof(unsigned char));

    /* Create and initialise the context */
    if (!(ctx = EVP_CIPHER_CTX_new()))
    {
        std::cout << "Failed to initialize ctx -1" << std::endl;
        return 0;
    }

    /* Initialise the decryption operation. */
    if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
    {
        std::cout << "Failed to initialize ctx -2" << std::endl;
        return 0;
    }
    /* Set IV length. Not necessary if this is 12 bytes (96 bits) */
    if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, sizeof(iv), NULL))
    {
        std::cout << "Failed to initialize ctx -3" << std::endl;
        return 0;
    }

    /* Initialise key and IV */
    if (!EVP_DecryptInit_ex(ctx, NULL, NULL, key.data(), iv))
    {
        std::cout << "Failed to initialize ctx -4" << std::endl;
        return 0;
    }

    /*
    * Provide any AAD data. This can be called zero or more times as
    * required
    */
    /*if (!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len))
    {
    std::cout << "Failed to initialize ctx" << std::endl;
    return 0;
    }*/

    /*
    * Provide the message to be decrypted, and obtain the plaintext output.
    * EVP_DecryptUpdate can be called multiple times if necessary
    */
    EVP_CIPHER_CTX_set_padding(ctx, 0);
    ret = EVP_DecryptUpdate(ctx, pt, &len, cipherText.data(), cipherText.size());
    std::cout << "DecryptUpdate ret: " << ret << std::endl;
    if (!ret)
    {
        std::cout << "Failed to initialize ctx -5" << std::endl;
        return 0;
    }
    plaintext_len = len;

    /* Set expected tag value. Works in OpenSSL 1.0.1d and later */
    ret = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag);
    std::cout << "Set Tag ret: " << ret << std::endl;
    if (ret != 1)
    {
        std::cout << "Failed to initialize ctx -6" << std::endl;
        return 0;
    }

    /*
    * Finalise the decryption. A positive return value indicates success,
    * anything else is a failure - the plaintext is not trustworthy.
    */
    std::cout << "Len of plain text decoded till now: " << plaintext_len << std::endl;
    ret = EVP_DecryptFinal_ex(ctx, pt + len, &len);
    ERR_print_errors_fp(stderr);
    std::cout << "DecryptFinal_ex ret: " << ret << std::endl;

    /* Clean up */
    EVP_CIPHER_CTX_free(ctx);
    free(pt);

    if (ret > 0)
    {
        /* Success */
        plaintext_len += len;
        return plaintext_len;
    }
    else
    {
        /* Verify failed */
        return -1;
    }
}
...