From what you have described, it sounds like your system works as follows:
- Consult the system clock to find a 32-bit seed $s$.
- Use
System.Random
to generate a passphrase $p = G(s)$. (Here $G$ is shorthand for whatever computation happens inside System.Random
.)
- Hash the passphrase with PBKDF(2?) into output $x = H(p, \sigma)$, where $\sigma$ is a salt known to the adversary. (Here $H$ is shorthand for PBKDF2.)
Do other stuff with $x$. Let's assume you expose $x$ so that we can focus on what the adversary will do; the adversary wins if they can find $p$ or $s$ and predict everything else that is derived from them.
(In practical terms, maybe you actually derive a key $k = H(p, \sigma)$ and then expose some other function $x = f(k)$ of $k$, but that doesn't substantively change the analysis—we can just fold $f$ into ‘$H$’ and go on as before.)
Let's set aside the flaws in the System.Random
algorithm for the moment—there are only at most $2^{32}$ distinct outputs, so in the best case for the defender and the worst case for the attacker, there are $2^{32}$ distinct possible values of $p$, uniformly distributed.
A sensible adversary will probably treat $G$ and $H$ as black boxes and try to find $s$. The naive brute force approach is to enumerate every candidate 32-bit seed $s^*$ and check whether $x = H(G(s), \sigma)$. This costs about $2^{32}$ (four billion) times the cost of evaluating $G$, which is negligible (maybe a few hundred CPU cycles), plus the cost of evaluating $H$, which depends on the PBKDF2 parameters and dominates the cost.
You didn't specify what hash function or how many PBKDF2 iterations, but let's say you picked 1000 iterations of PBKDF2-HMAC-SHA256. My laptop computes about 5 000 000 SHA-256 hashes per second on a single CPU (measured by openssl speed sha256
with the 16-byte inputs), which is about 2 500 000 HMAC-SHA256 hashes per second, or about 2 500 password guesses per second. My laptop also has eight CPUs, so actually it can make about 20 000 guesses per second. With the naive brute force attack on PBKDF2-HMAC-SHA256 on the laptop I happen to be typing on, it should take about two days at my laptop's full power draw to find $s$ and $p$.
That's without any hardware acceleration: Intel's SHA-256 CPU instructions would presumably speed it up—and therefore reduce the cost—by a factor of about four, giving an answer in a few hours. The computation uses essentially no memory or data-dependent memory access patterns, so it can fruitfully be moved to a GPU for further speedups without even leaving the comfort of my personal laptop. Getting an answer in a few seconds is not hard to imagine if you have a modest cluster of GPUs to throw at the problem, like you could rent at Amazon.
In practice, the adversary actually probably doesn't just have one target $x = H(G(s), \sigma)$ to attack: they probably have many targets $x_1 = H(G(s_1), \sigma_1),$ $\dots,$ $x_t = H(G(s_t), \sigma_t)$ to attack, and they win if they break the first of any of the $t$ targets. (Once you get a foothold into a network, it is often easy to springboard from there to many other places in the network.) If you didn't choose a distinct salt $\sigma_i$ for each user, then an adversary could also reduce this (rather low!) cost by a factor of $t$ as long as they parallelize the attack $n \geq t^2$ ways, recovering the seed in the cost $2^{32}\!/t$ and in the time $2^{32}\!/nt$ by using a parallel rainbow table search[1].
Of course, this analysis is isolated from the rest of the details of your application. There may be other ways to break it. For example, if the adversary knows what time you seeded System.Random
they can narrow the search space down considerably. If you have a distinct salt per user, how did you choose the salt? If you chose it from System.Random
verbatim, it may be possible to recover the System.Random
seed from the salt and find the passphrase without an even moderately expensive search at all.
What cryptographers will tell you is that if the password has high enough min-entropy, then your system will not be breakable in certain particular ways if you use certain cryptography.
What cryptographers will generally not do is lift a finger to break your pet project, because it's a lot of trouble to find a ‘feasible’ attack, and negligible reward—unless they actually get a specific reward from your system because they are the adversary trying to exploit your users, in which case they aren't going to share their findings with you.
Cryptographers only bother attacking real systems in the wild when they are particularly high-value, like TLS, and particularly many users might be at particularly high risk because of shoddy choices like RC4 that the engineers drag their feet about changing, despite the fact that RC4 was broken within 48 hours of its publication[2] and cryptanalysts kept finding worse[3] and worse[4] problems in it. That's why cryptanalysts bothered studying the specific use of RC4 in WPA and TLS[5][6][7], for example. The same thing happened with bespoke kooky constructions in SSH, TLS, and PGP[8].
Don't be the engineer responsible for making a shoddy cryptographic decision that will inspire cryptanalysts to poke holes in your system years down the road. Follow cryptographers' advice the first time around, to save the cryptanalysts' effort and to let them focus on cryptosystems that will be broadly used like NIST PQC, to improve security for everyone. If you're not sure whether the use of System.Random
will ruin your security, assume that it will and promptly replace it by something better in order to give confidence to your users.
System.Random
is also flawed as a general-purpose PRNG. It fails basic statistical uniformity tests. For example,Next(1431655765)
has a 66% chance of returning an even number. $\endgroup$