+3  A: 

1) If it's cryptographically secure, which it's supposed to be, then this sort of guessing should not be feasible.

2) On a side note, I suggest removing the JIT instantiation in the static property annd instead doing the following:

protected static readonly RandomNumberGenerator _rng = new RNGCryptoServiceProvider();
Steven Sudit
+2  A: 

The CSP based RNG in CLR is just a wrapper around CryptGenRandom. Like all CSP functions, they work around a HCRYPTPROV context handle. If I remember correctly the very first thing the provider does when entering the 'context' is to acquire a critical section that protects the 'context'. So while the function is most likely stable across threads, you really should use a separate one for each thread to avoid contention.

Update

According to this MSDN Magazine the CLR may use an instance buffer instead of a stack one, making the RNGCryptoServiceProvider unsafe across threads in future implementations:

Note that, as currently implemented in the .NET Framework 2.0, the parameterless constructor of RNGCryptoServiceProvider creates thread-safe instances. As such, we could have created our private member to instead have been a private static member, and in doing so not have to create a new RNGCryptoServiceProvider instance for each instance of CryptoRandom. However, this thread-safety is not currently documented nor is it in any way baked into the class's contract or interface. Given that, we haven't relied on it for our implementation.

Note that this use is not related to the native API thread safety, the buffer issue is a CLR wrapper issue. Also, if you use the RNGCryptoServiceProvider constructor that takes a byte[], then is unsafe for sure.

Remus Rusanu
+1 for important details.
Steven Sudit