How do i approach file encryption using encrypt-then-mac? I'm programming a cryptographic application that encrypts files, locked with the password the user supplies. It's not intended to be used in production. It's a project for me to learn more about encryption.

I have programmed the encryption part already, it's in C# and i'm using CBC as cipher mode.

I want to add authentication to my encryption and i plan on doing that by using CBC + HMAC(SHA256). I know that i have to HMAC the IV + Ciphertext. And yes i know BouncyCastle has an API that offers GCM(which is probably preferred over using CBC + HMAC), but the API's barely have any documentation and i read that CBC + HMAC is probably just as secure if done correctly. KeePass(Keepass) uses it too.

However i'm not sure how to go about generating keys for the HMAC and the encryption itself. If i understand correctly it's always best-practice to use different keys for different operations (and rightly so).
I'm currently encrypting the file content with a key that is generated by deriving a 256 bit key with the PKBDF2 algorithm(which takes a salt and does 10.000 iterations), but i need a key for the HMAC too. What is the best way to go about generating a key?

If you notice any mistakes and/or misconceptions in this post please tell me.
Derive a 256-bit master key from your password using a password-based key derivation function like scrypt or argon2.

(Don't use PBKDF2 if you can use newer better alternatives that take advantage of memory, not just time, to drive up the adversary's costs.)
Derive subkeys for each purpose using HKDF-SHA256 with a distinct info parameter.

You can feed this master key to HKDF-Expand as the initial keying material (IKM) with some additional salt, but that step isn't necessary if the master key is already derived by a salted PBKDF; you can also use this master key directly with HKDF-Extract as the pseudorandom key (PRK).
Generate known-answer test vectors for the scheme you think you're implementing, using another tool (e.g., write it in C with OpenSSL), so that you can do a self-test when you run your C# program to confirm that it's doing the same computation.
Consider copying the behavior of the scrypt file encryption tool, which has a simple file format and makes it easy to generate test vectors and confirm you're interoperating with another implementation of a good, secure protocol.