im trying to decrypt data that have been encrypted with c++ openssl, the data have been encrypted this way:


inline bool mediumEncrypt(QByteArray& data, QByteArray& password)
{
    VM_S_START //C357

    // Generate the password with the pre-defined size of the byteArray
    RAND_bytes(reinterpret_cast<unsigned char*>(password.data()), password.size());
	
    // Generate a random salt
    unsigned char randomByte;
    RAND_bytes(&randomByte, 1);
    int saltSize = 16 + (randomByte % 6); // Random size between 16 and 21
    std::vector<unsigned char> salt(saltSize);
    RAND_bytes(salt.data(), saltSize);

    // Use PBKDF2 for key derivation
    std::vector<unsigned char> key(32);
    std::vector<unsigned char> iv(12);  // 12 bytes for GCM
    if (PKCS5_PBKDF2_HMAC(reinterpret_cast<const char*>(password.data()), password.size(),
                          salt.data(), salt.size(),
                          3000, EVP_sha256(),
                          key.size(), key.data()) != 1) {
        return false;
    }
    RAND_bytes(iv.data(), iv.size());

    // Encrypt the password
    weakEncrypt2(password);

    // Initialize encryption (using AES-256-GCM)
    EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
    if (!ctx) return false;

    if (EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), nullptr, key.data(), iv.data()) != 1) {
        EVP_CIPHER_CTX_free(ctx);
        return false;
    }
    OPENSSL_cleanse(key.data(), key.size());

    // Compress
	data = qCompress(data, 9);

    // Start encryption
    std::vector<unsigned char> encryptedData(data.size() + EVP_CIPHER_block_size(EVP_aes_256_gcm()));
    int encryptedLength = 0;

    if (EVP_EncryptUpdate(ctx, encryptedData.data(), &encryptedLength, 
                          reinterpret_cast<const unsigned char*>(data.constData()), data.size()) != 1) {
        EVP_CIPHER_CTX_free(ctx);
        return false;
    }

    OPENSSL_cleanse(data.data(), data.size());
    data.clear();

    int finalLength = 0;
    if (EVP_EncryptFinal_ex(ctx, encryptedData.data() + encryptedLength, &finalLength) != 1) {
        EVP_CIPHER_CTX_free(ctx);
        return false;
    }

    encryptedData.resize(encryptedLength + finalLength);

    // Get the authentication tag
    std::vector<unsigned char> tag(16);
    if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag.data()) != 1) {
        EVP_CIPHER_CTX_free(ctx);
        return false;
    }

    EVP_CIPHER_CTX_free(ctx);

    // Generate random string to prepend
    RAND_bytes(&randomByte, 1);
    int prependStrSize = 6 + (randomByte % 6); // Random size between 6 and 11
    std::vector<unsigned char> prependStr(prependStrSize);
    RAND_bytes(prependStr.data(), prependStrSize);

    // Combine all parts
    data.append(prependStr);
    data.append(salt);
    data.append(iv);
    data.append(encryptedData);
    data.append(tag);

    OPENSSL_cleanse(salt.data(), salt.size());
    OPENSSL_cleanse(iv.data(), iv.size());
    OPENSSL_cleanse(encryptedData.data(), encryptedData.size());
	OPENSSL_cleanse(prependStr.data(), prependStr.size());
    OPENSSL_cleanse(tag.data(), tag.size());

    encryptedData.clear();

    VM_S_END //C357

    return true;
}

im decrypting it from nodejs javascript this way:

function loaderMediumDecrypt(data, password, decryptFail)
{
    try
    {
        if (!data || data.length === 0 || !password || password.length === 0)
            return decryptFail[data] = "lmd"

        const decodedData = data
        const IV_SIZE     = 12 // GCM uses 12-byte IV
        const TAG_SIZE    = 16
        const ITERATIONS  = 3000

        for (let prependLen = 6; prependLen <= 11; ++prependLen)
        {
            for (let saltLen = 16; saltLen <= 21; ++saltLen)
            {
                if (decodedData.length < prependLen + saltLen + IV_SIZE + TAG_SIZE)
                    continue

                const salt = decodedData.slice(prependLen, prependLen + saltLen)
                const iv   = decodedData.slice(prependLen + saltLen, prependLen + saltLen + IV_SIZE)
                const tag  = decodedData.slice(-TAG_SIZE)

                // Derive key using PBKDF2
                let key
                try
                {
                    key = crypto.pbkdf2Sync(password, salt, ITERATIONS, 32, 'sha256')
                } catch (err)
                {
                    continue
                }

                // Initialize decryption
                let decipher
                try
                {
                    decipher = crypto.createDecipheriv('aes-256-gcm', key, iv)
                    decipher.setAuthTag(tag)
                } catch (err)
                {
                    continue
                }

                // Decrypt
                let decrypted
                try
                {
                    decrypted = Buffer.concat(
                        [decipher.update(decodedData.slice(prependLen + saltLen + IV_SIZE, -TAG_SIZE)), 
                         decipher.final()])
                } catch (err)
                {
                    continue
                }

                // If we've reached here, decryption was successful
                let decryptedString = decrypted //.toString('utf8')
                decryptedString     = decryptedString.slice(4)                     // Remove Qt's 4-byte header
                decryptedString     = decryptedString.inflateSync(decryptedString) // Decompress using inflateSync since qCompress uses zlib's compress

                try {
                    return JSON.parse(decryptedString);
                } catch (error) {
                    return decryptedString;
                }
            }
        }
    } 
    catch (err)
    {
    }
	
	
	it sucessfully reach "// If we've reached here, decryption was successful"
	but its failing to decompress the data, how to decompress it?