the derived nonce on the decryption doesnt match the one generated on the encryption how to fix this?
im trying to generate the nonce from the password and not store it into the encrypted message or anywhere else because of size constraints

you can rewrite the entire functions or just fix it with whatever you find better
the only requirements are keep the arguments as (QByteArray& data, const QByteArray& password)

do not need to use qt anywhere else, keep using openssl for everything

constexpr size_t NONCE_SIZE = 12;
constexpr size_t KEY_SIZE = 32;

std::vector<unsigned char> deriveNonce(const std::vector<unsigned char>& password, 
                                       const std::vector<unsigned char>& salt) {
    std::vector<unsigned char> context;
    context.reserve(password.size() + salt.size());
    context.insert(context.end(), password.begin(), password.end());
    context.insert(context.end(), salt.begin(), salt.end());
    
    unsigned char hash[SHA256_DIGEST_LENGTH];
    SHA256(context.data(), context.size(), hash);
    
    return std::vector<unsigned char>(hash, hash + NONCE_SIZE);
}

bool weakEncrypt(QByteArray& data, const QByteArray& password)
{
    if (data.isEmpty()) 
        return false;
    
    // Generate a salt (first 32 bytes of SHA256 hash of the data)
    unsigned char datahash[SHA256_DIGEST_LENGTH];
    SHA256(reinterpret_cast<const unsigned char*>(data.data()), data.size(), datahash);
    std::vector<unsigned char> salt(datahash, datahash + 32);

    // Derive key from password
    unsigned char key[KEY_SIZE];
    SHA256(reinterpret_cast<const unsigned char*>(password.data()), password.size(), key);

    // Derive nonce
    std::vector<unsigned char> passwordVec(password.begin(), password.end());
    std::vector<unsigned char> nonce = deriveNonce(passwordVec, salt);
    
    // Encrypt with derived nonce
    EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
    if (!ctx) return false;
    if (EVP_EncryptInit_ex(ctx, EVP_chacha20(), nullptr, key, nonce.data()) != 1) {
        EVP_CIPHER_CTX_free(ctx);
        return false;
    }
    QByteArray ciphertext(data.size() + EVP_MAX_BLOCK_LENGTH, 0);
    int ciphertextLen;
    if (EVP_EncryptUpdate(ctx, reinterpret_cast<unsigned char*>(ciphertext.data()), &ciphertextLen, 
                          reinterpret_cast<const unsigned char*>(data.data()), data.size()) != 1) {
        EVP_CIPHER_CTX_free(ctx);
        return false;
    }
    int finalLen;
    if (EVP_EncryptFinal_ex(ctx, reinterpret_cast<unsigned char*>(ciphertext.data()) + ciphertextLen, &finalLen) != 1) {
        EVP_CIPHER_CTX_free(ctx);
        return false;
    }
    ciphertext.resize(ciphertextLen + finalLen);
    EVP_CIPHER_CTX_free(ctx);
    OPENSSL_cleanse(key, sizeof(key));
    data = std::move(ciphertext);
    return true;
}

bool weakDecrypt(QByteArray& data, const QByteArray& password)
{
    if (data.isEmpty()) 
        return false;

    // Generate the same salt as in encryption (first 32 bytes of SHA256 hash of the encrypted data)
    unsigned char datahash[SHA256_DIGEST_LENGTH];
    SHA256(reinterpret_cast<const unsigned char*>(data.data()), data.size(), datahash);
    std::vector<unsigned char> salt(datahash, datahash + 32);

    // Derive nonce
    std::vector<unsigned char> passwordVec(password.begin(), password.end());
    std::vector<unsigned char> nonce = deriveNonce(passwordVec, salt);

    // Derive key from password
    unsigned char key[KEY_SIZE];
    SHA256(reinterpret_cast<const unsigned char*>(password.data()), password.size(), key);

    EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
    if (!ctx) return false;
    if (EVP_DecryptInit_ex(ctx, EVP_chacha20(), nullptr, key, nonce.data()) != 1) {
        EVP_CIPHER_CTX_free(ctx);
        return false;
    }
    QByteArray plaintext(data.size(), 0);
    int plaintextLen;
    if (EVP_DecryptUpdate(ctx, reinterpret_cast<unsigned char*>(plaintext.data()), &plaintextLen, 
                          reinterpret_cast<const unsigned char*>(data.data()), data.size()) != 1) {
        EVP_CIPHER_CTX_free(ctx);
        return false;
    }
    int finalLen;
    if (EVP_DecryptFinal_ex(ctx, reinterpret_cast<unsigned char*>(plaintext.data()) + plaintextLen, &finalLen) != 1) {
        EVP_CIPHER_CTX_free(ctx);
        return false;
    }
    plaintext.resize(plaintextLen + finalLen);
    EVP_CIPHER_CTX_free(ctx);
    OPENSSL_cleanse(key, sizeof(key));
    data = std::move(plaintext);
    return true;
}