RNGCryptoServiceProvider to get a random 256 bit integer in c# - c#

I am trying to generate a 256 bit integer in c# using RNGCryptoServiceProvider. My code is:
// 256 bits random number
byte[] random = new Byte[32];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(random); Debug.WriteLine(BitConverter.ToUInt64(random,0));
return BitConverter.ToUInt64(random,0);
However, the output are integers like 6958393268188363168, which is not 77 digits long. Any ideas? Thanks

Related

How to determine number of characters that GetNonZeroBytes & Pbkdf2 will produce, so I can configure size of database field that will hold this value?

I am exploring cryptographic technique to create the salt and hash passwords.
Sample 1:
// generate a 128-bit salt using a cryptographically strong random sequence of nonzero values
byte[] pSalt = new byte[128 / 8];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetNonZeroBytes(pSalt);
}
string strSalt = Convert.ToBase64String(pSalt)
Sample 2:
// derive a 256-bit subkey (use HMACSHA256 with 100,000 iterations)
var pHash = KeyDerivation.Pbkdf2(
password: password,
salt: Convert.FromBase64String(pSalt),
prf: KeyDerivationPrf.HMACSHA256,
iterationCount: 100000,
numBytesRequested: 256 / 8);
string strHash = Convert.ToBase64String(pHash)
For both the strings (strSalt and strHash) from samples above, can we deterministically conclude the size (number of characters) in the final string?
Base64 encodes 6 bits in one character, so to encode N bit, you need N/6 characters (round up if required).
The .NET method Convert.ToBase64String will append additional padding characters (=) to make the length a multiple of 4, so if you use this method, round up to the next multiple of 4.
Convert.ToBase64String(new byte[128/8]).Length will be 24.
Convert.ToBase64String(new byte[256/8]).Length will be 44.

Decrypt using public key, RSA and Bouncy castle

I need to decrypt a signature hash using RSA. I've got a hexadecimal string of 288 characters long which is a general public key from an institution. It represents hexadecimal bytes, so 144 bytes total.
The first 8 bytes are the so called CAR. Which is used for identification. The next 128 bytes are the Modulus N. And the next 8 bytes are the exponent E.
I've never worked with cryptography before so go easy on me. I'm using C# and the Bouncy Castle library for the decryption algorithms. Now, If I understand correctly, a 1024 bit modulus and 64 bits exponent is not strange. I currently have this bit of code:
public byte[] rsa_decrypt(byte[] data)
{
var N = PublicKey.ToCharArray().Slice(16,256);
var E = PublicKey.ToCharArray().Slice(272,16);
RsaEngine rsa = new RsaEngine();
Org.BouncyCastle.Math.BigInteger modulus = new Org.BouncyCastle.Math.BigInteger(new string(N).Insert(0,"00"),16);
Console.WriteLine(modulus);
Org.BouncyCastle.Math.BigInteger exponent = new Org.BouncyCastle.Math.BigInteger(new string(E).Insert(0,"00"),16);
Console.WriteLine(exponent);
RsaKeyParameters x = new RsaKeyParameters(false,modulus,exponent);
var eng = new Pkcs1Encoding(new RsaEngine());
eng.Init(false,x);
return eng.ProcessBlock(data,0,data.Length);
}
The Slice<T>(this T[],offset,length) method is just a small thing I wrote to cut arrays in pieces, nothing special and it works. The insertion of the "00" in the string is because the string could otherwise be interpreted as unsigned I believe.
When I run this code I get the exception
Unhandled exception. Org.BouncyCastle.Crypto.InvalidCipherTextException: block incorrect at Org.BouncyCastle.Crypto.Encodings.Pkcs1Encoding.DecodeBlock(Byte[] input, Int32 inOff, Int32 inLen) at Org.BouncyCastle.Crypto.Encodings.Pkcs1Encoding.ProcessBlock(Byte[] input, Int32 inOff, Int32 length)
Obviously I'm doing something wrong. Can anybody tell me what I'm doing wrong, why I'm doing it wrong, and most preferably, what I should be doing. Again, never worked with crypto algorithms or this library ever before.

C# A random BigInt generator

I'm about to implement the DSA algorithm, but there is a problem:
choose "p", a prime number with L bits, where 512 <= L <= 1024 and L is a multiple of 64
How can I implement a random generator of that number? Int64 has "only" 63 bits length.
You can generate a random number with n bits using this code:
var rng = new RNGCryptoServiceProvider();
byte[] bytes = new byte[n / 8];
rng.GetBytes(bytes);
BigInteger p = new BigInteger(bytes);
The result is, of course, random and not necessarily a prime.
The BigInteger class was introduced in the .NET 4.0 Framework.
For generating large prime numbers, Wikipedia says:
For the large primes used in cryptography, it is usual to use a modified form of sieving: a randomly-chosen range of odd numbers of the desired size is sieved against a number of relatively small odd primes (typically all primes less than 65,000). The remaining candidate primes are tested in random order with a standard primality test such as the Miller-Rabin primality test for probable primes.
So you could do something like this:
var p = Enumerable.Range(0, numberOfCandidates)
.Select(i => RandomOddNumber(bits))
.Where(x => !primesLessThan65000.Contains(x))
.Where(x => PrimalityTest(x))
.FirstOrDefault();

How to generate a cryptographically secure Double between 0 and 1?

I know how to generate a random number between 0 and 1 using the NextDouble method of the pseudo-random number generator.
var rng1 = new System.Random();
var random1 = rng1.NextDouble(); // generates a random double between 0 and 1.0
And I know how to fill a random byte array using the cryptographically secure random number generator.
Byte[] bytes = new Byte[8];
var rng2 = new System.Security.Cryptography.RNGCryptoServiceProvider();
rng2.GetBytes(bytes); // generates 8 random bytes
But how can I convert the byte-array output of RNGCryptoServiceProvider into a random number uniformly distributed between 0 (inclusive) and 1 (exclusive)?
It appears to me that the solutions so far will have uneven distribution due to taking the inverse. For an even distribution I'd think you want something like this.
// Step 1: fill an array with 8 random bytes
var rng = new RNGCryptoServiceProvider();
var bytes = new Byte[8];
rng.GetBytes(bytes);
// Step 2: bit-shift 11 and 53 based on double's mantissa bits
var ul = BitConverter.ToUInt64(bytes, 0) / (1 << 11);
Double d = ul / (Double)(1UL << 53);
Note that you can't just divide the UInt64 into UInt64.MaxValue, because a double doesn't have enough bits, and there's no way to get unique outputs for all your inputs. So you can/must throw some bits away.
Well, I would not call a 64-bit random number "cryptographically secure" - you'd want a lot more bits than that to be "cryptographically secure". But anyway, you could do something like this:
var bytes = // assume this contains 8 bytes of random numbers
long l = BitConverter.ToInt64(bytes);
double d = Math.Abs(1 / (double)l);
Since RNGCryptoServiceProvider is obsolete in .NET 6
https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.rngcryptoserviceprovider?view=net-6.0
if you want "real" NextDouble you can use RandomNumberGenerator like this
How to get NextDouble from cryptogaphy random RandomNumberGenerator

Generate random values in C#

How can I generate random Int64 and UInt64 values using the Random class in C#?
This should do the trick. (It's an extension method so that you can call it just as you call the normal Next or NextDouble methods on a Random object).
public static Int64 NextInt64(this Random rnd)
{
var buffer = new byte[sizeof(Int64)];
rnd.NextBytes(buffer);
return BitConverter.ToInt64(buffer, 0);
}
Just replace Int64 with UInt64 everywhere if you want unsigned integers instead and all should work fine.
Note: Since no context was provided regarding security or the desired randomness of the generated numbers (in fact the OP specifically mentioned the Random class), my example simply deals with the Random class, which is the preferred solution when randomness (often quantified as information entropy) is not an issue. As a matter of interest, see the other answers that mention RNGCryptoServiceProvider (the RNG provided in the System.Security namespace), which can be used almost identically.
Use Random.NextBytes() and BitConverter.ToInt64 / BitConverter.ToUInt64.
// Assume rng refers to an instance of System.Random
byte[] bytes = new byte[8];
rng.NextBytes(bytes);
long int64 = BitConverter.ToInt64(bytes, 0);
ulong uint64 = BitConverter.ToUInt64(bytes, 0);
Note that using Random.Next() twice, shifting one value and then ORing/adding doesn't work. Random.Next() only produces non-negative integers, i.e. it generates 31 bits, not 32, so the result of two calls only produces 62 random bits instead of the 64 bits required to cover the complete range of Int64/UInt64. (Guffa's answer shows how to do it with three calls to Random.Next() though.)
Here you go, this uses the crytpo services (not the Random class), which is (theoretically) a better RNG then the Random class. You could easily make this an extension of Random or make your own Random class where the RNGCryptoServiceProvider is a class-level object.
using System.Security.Cryptography;
public static Int64 NextInt64()
{
var bytes = new byte[sizeof(Int64)];
RNGCryptoServiceProvider Gen = new RNGCryptoServiceProvider();
Gen.GetBytes(bytes);
return BitConverter.ToInt64(bytes , 0);
}
You can use bit shift to put together a 64 bit random number from 31 bit random numbers, but you have to use three 31 bit numbers to get enough bits:
long r = rnd.Next();
r <<= 31;
r |= rnd.Next();
r <<= 31;
r |= rnd.Next();
I always use this to get my random seed (error checking removed for brevity):
m_randomURL = "https://www.random.org/cgi-bin/randnum?num=1&min=1&max=1000000000";
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(m_randomURL);
StreamReader stIn = new StreamReader(req.GetResponse().GetResponseStream());
Random rand = new Random(Convert.ToInt32(stIn.ReadToEnd()));
random.org uses atmospheric noise to generate the randomness and is apparently used for lotteries and such.
You don't say how you're going to use these random numbers...keep in mind that values returned by Random are not "cryptographically secure" and they shouldn't be used for things involving (big) secrets or (lots of) money.
You could create a byte array, fill it with random data and then convert it to long (Int64) or ulong (UInt64).
byte[] buffer = new byte[sizeof(Int64)];
Random random = new Random();
random.NextBytes(buffer);
long signed = BitConverter.ToInt64(buffer, 0);
random.NextBytes(buffer);
long unsigned = BitConverter.ToUInt64(buffer, 0);
Another answer with RNGCryptoServiceProvider instead of Random. Here you can see how to remove the MSB so the result is always positive.
public static Int64 NextInt64()
{
var buffer = new byte[8];
new RNGCryptoServiceProvider().GetBytes(buffer);
return BitConverter.ToInt64(buffer, 0) & 0x7FFFFFFFFFFFFFFF;
}
As of .NET 6, the Random class has a method for generating a random long.
var r = new Random();
long randomLong = r.NextInt64();
Random r=new Random();
int j=r.next(1,23);
Console.WriteLine(j);

Categories

Resources