簡體   English   中英

openssl 加密 memory 泄漏

[英]openssl crypto memory leak

我對 openssl 加密庫有問題,即使在退出 function scope 后進行解密,解密后的字符串也不會從 memory 中刪除。我的代碼:

int crypto::aes_decrypt(const crypto::vector<unsigned char> &data, const crypto::string &key, const crypto::string &iv,
                        crypto::vector<unsigned char> &decrypted) {
    try {
        int len;
        int plaintext_len;
        const auto *dataArr = data.data();
        size_t dataLength = data.size();

        if (key.length() != 32 || iv.length() != 16) {
            return -1;
        }

        auto *plaintext = new unsigned char[dataLength + 16];

        EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
        if (ctx == nullptr) {
            return -2;
        }

        const auto *keyArr = reinterpret_cast<const unsigned char *>(key.data());
        const auto *ivArr = reinterpret_cast<const unsigned char *>(iv.data());

        /*
         * Initialise the decryption operation. IMPORTANT - ensure you use a key
         * and IV size appropriate for your cipher
         * In this example we are using 256-bit AES (i.e. a 256-bit key). The
         * IV size for *most* modes is the same as the block size. For AES this
         * is 128 bits
         */
        if (1 != EVP_CipherInit_ex(ctx, EVP_aes_256_cbc(), nullptr, keyArr, ivArr, 0)) {
            EVP_CIPHER_CTX_free(ctx);
            return -3;
        }

        /*
        * Provide the message to be decrypted, and obtain the plaintext output.
        * EVP_DecryptUpdate can be called multiple times if necessary.
        */
        if (1 != EVP_DecryptUpdate(ctx, plaintext, &len, dataArr, dataLength)) {
            EVP_CIPHER_CTX_free(ctx);
            return -4;
        }

        plaintext_len = len;

        /*
         * Finalise the decryption. Further plaintext bytes may be written at
         * this stage.
         */

        if (1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) {
            EVP_CIPHER_CTX_free(ctx);
            return -5;
        }

        plaintext_len += len;
        decrypted = crypto::vector<unsigned char>(plaintext, plaintext + plaintext_len);

        /* Clean up */
        EVP_CIPHER_CTX_free(ctx);
        free(plaintext);
        return 0;

    } catch (exception &e) {
#ifdef DEBUG_SHARED_LIBRARIES
        cout << "Error while aes decrypting: " << e.what() << endl;
#endif
        return -99;
    }
}
void test() {
    string key = "abcdefghijklmnopabcdefghijklmnop";
    string iv = "1234567890123456";
    string b64 = "82fgiOvXUXrnkGeRsCjKgA==";
    
    vector<unsigned char> decrypted;
    int i = crypto::aes_decrypt(crypto::base64_decode(b64), key, iv, decrypted);
    if (i != 0) {
        cout << "Error: " << i << endl;
        return;
    }

    string dec = {decrypted.begin(), decrypted.end()};

//    cout << "Decrypted raw: " << string_utils::char_array_to_hex(decrypted.data(), decrypted.size()) << endl;
    cout << "Decrypted: " << dec << endl;

    cout << "Click to clear" << endl;
    string input;
    getline(cin, input);
}

我嘗試了很多組合,但字符串和向量仍然相同 - 解密后的字符串仍在 memory

在退出 function scope 之前:

在此處輸入圖像描述

退出function scope后:

在此處輸入圖像描述

在 memory 轉儲中:

在此處輸入圖像描述

和另一個:

在此處輸入圖像描述

有什么建議我該如何處理? 我認為 aes 解密實現有問題,因為在 memory 轉儲中有許多與 openssl 加密庫相關的加密方法

要清理 memory,OpenSSL 提供了OPENSSL_cleanse() function

OPENSSL_cleanse()用一串 0 填充大小為lenptr ...

在釋放 memory 之前,您不能安全地使用諸如memset()之類的函數來清除它 - 允許編譯器優化此類調用,因為根據 C 和 C++ 標准,它們對程序沒有影響。 C 確實在可選的附件 K 中提供了memset_s() function ,這清除 memory:

... 與 memset 不同,對 memset_s function 的任何調用都應嚴格按照( 5.1.2.3 )中描述的抽象機規則進行評估。 也就是說,對 memset_s function 的任何調用都應假定 s 和 n 指示的 memory 將來可以訪問,因此必須包含 c 指示的值。

您還需要小心使用 C++ 容器,例如vector 您無法明確控制此類 C++ 容器使用的 memory,因此無法保證它們不會在 memory 中的某處留下您的敏感數據副本。

暫無
暫無

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

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