Would XOR'ing two Argon2 keys add extra security? When a user registers on the app, they need to provide a password they create and we provide them with a randomly generated passphrase (e.g. Apple Cat Ladder Fire). We then use Libsodium's crypto_pwhash() to generate a key for both the user's password and the generated passphrase.

Since most users will use a low entropy password, the goal was to combine it with a higher entropy source to derive a master key using the crypto_kdf_derive_from_key() function. This master key only exists to wrap/unwrap the user's private key.

I was wondering if XOR'ing these two keys actually has any benefit or am I chasing my own tail?

I also added the XOR function I wrote in Kotlin (There isn't a native implementation that I'm aware of) to see if I'm actually XOR'ing the keys properly.

fun xorKeys(keyOne:ByteArray, keyTwo:ByteArray): ByteArray {
    // Check to make sure both keys are the same size
    if (keyOne.size != keyTwo.size)
        throw Throwable("Key sizes don't match")

    // Create a new key handle
    var newKey = ByteArray(keyOne.size)

    // XOR individual bytes
    for (i in keyOne.indices) {
        newKey[i] = keyOne[i] xor keyTwo[i]
    }

    // Return the new key
    return newKey
}
That sounds convoluted.

The server-generated passphrase is essentially an extension to the client password. So you may just concatenate both (with a proper delimiter, or with their respective sizes being included) and hash the whole thing.

Also, from a usability perspective, the passphrase is inconvenient (and useless when using a password manager). You may use the user's email address as an extension instead.