The right way to generate an IV for CBC mode is with a cryptographically secure random generator. There are cases where a non-random IV is ok, but unless you've carefully analyzed your system to be sure that you fall into these cases, you should go with a random IV. There are very few situations where using a non-random IV would have any benefit anyway, so go with a random IV.
I'm not familiar with the C# API, but given that the documentation of GenerateIV
states that it “generates a random initialization vector (IV) to use for the algorithm”, it appears to be a valid way to generate an IV for CBC (but CreateEncryptor
does the same job already).
Taking the hash of these random bytes is strictly speaking a risk, because it reduces the entropy of the IV: cryptographic hashes are not known to be surjective. (I assume you mean a cryptographic hash such as SHA-256; a non-cryptographic hash would definitely be problematic.) However, I don't think there is any concrete problem with that: in practice, I think it's harmless.
Appending some random bytes and hashing repeatedly again should be equally safe. However, it's needless complexity. Needless complexity should raise alarm bells in any security context. This increases the risk of an implementation bug, such as leaking confidential data (not a big concern here though, as the IV doesn't need to be confidential, but it would be a definite consideration if you were generating a key), overwriting data due to a buffer overflow or incorrect pointer calculation, getting the iteration count to 0 when at least one iteration is necessary, etc.
The second method you propose is definitely not safe without the extra hashing-with-random step. MAC addresses and time are predictable, and CBC requires an unpredictable IV. The attacks against CBC with a predictable IV don't apply to all systems (they rely on the adversary being able to submit messages for encryption), but why take a risk? In addition, MAC addresses and time are not necessarily unique: think cloned virtual machines, multithreaded programs, fast process that serves two clients in the same clock tick, etc.
With the extra hashing-with-random step, starting from the MAC address and time should be indistinguishable from random, provided that enough random data is injected. But we're back to the complexity problem: how sure are you that you're getting it right?
If the reason for this extra complexity is “to make it more random”… random doesn't work that way. You can't make random more random just by messing with it, there's a serious risk that you'll mess it up and make it less random.
Doing anything other than taking a random IV (e.g. with GenerateIV
) increases maintenance cost (starting with the time you're spending now worrying about it), reduces performance, and increases risk. So just use a random IV.
If deploying an updated version of the code is expensive, this isn't a critical problem. (If the IV was just MAC+time, it may or may not be critical depending on the overall system.) But it should be fixed in the code base and deployed with the next normal release.