C# RNGCryptoServiceProvider GetBytes(large byte array) vs looping GetBytes(1 byte) - c#

I was wondering if there's a difference in security between the following:
CASE A:
byte[] data = new byte[47];
using(RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider())
{
crypto.GetBytes(data);
}
CASE B:
byte[] data = new byte[47];
using(RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider())
{
for(int i = 0; i < 47; i++)
{
byte[] byte = new byte[1];
crypto.GetBytes(byte);
data[i] = byte;
}
}
I was wondering because I was inspired by the example of MSDN. Which basically checks whether the byte received was fair due to the unfair distribution of using modulo on a limited value. (I was building a random string generator and I don't want to give the characters early in the alphabet the advantage of an unfair distribution)
So basically my question is, is there a difference in security whether I loop "GetBytes" to get N bytes (case b), or use "GetBytes" directly to get N bytes (case a).
Thank you for your time

No, there isn't. The bytes are generated the same way no matter whichever way you get them.

Related

Byte[] to BitArray and back to Byte[]

As the title states, i'm trying to convert a byte array to bit array back to byte array again.
I am aware that Array.CopyTo() takes care of that but the byte array received is not the same as the original one due to how BitArray stores values in LSB.
How do you go about it in C#?
This should do it
static byte[] ConvertToByte(BitArray bits) {
// Make sure we have enough space allocated even when number of bits is not a multiple of 8
var bytes = new byte[(bits.Length - 1) / 8 + 1];
bits.CopyTo(bytes, 0);
return bytes;
}
You can verify it using a simple driver program like below
// test to make sure it works
static void Main(string[] args) {
var bytes = new byte[] { 10, 12, 200, 255, 0 };
var bits = new BitArray(bytes);
var newBytes = ConvertToByte(bits);
if (bytes.SequenceEqual(newBytes))
Console.WriteLine("Successfully converted byte[] to bits and then back to byte[]");
else
Console.WriteLine("Conversion Problem");
}
I know that the OP is aware of the Array.CopyTo solution (which is similar to what I have here), but I don't see why it's causing any Bit order issues. FYI, I am using .NET 4.5.2 to verify it. And hence I have provided the test case to confirm the results
To get a BitArray of byte[] you can simply use the constructor of BitArray:
BitArray bits = new BitArray(bytes);
To get the byte[] of the BitArray there are many possible solutions. I think a very elegant solution is to use the BitArray.CopyTo method. Just create a new array and copy the bits into:
byte[]resultBytes = new byte[(bits.Length - 1) / 8 + 1];
bits.CopyTo(resultBytes, 0);

C# Biginteger for huge number of bits

I would like to know if there is any efficient way to store a big number using C#. I would like to create number consisting of 960 bytes but BigInteger can't hold it. I would be grateful for any advice.
UPDATE: I am using random byte generator to fill up array needed for constructor of BigInteger. For 960 byte array i BigInteger is returning a negative number.
static void Main(string[] args)
{
var arr = new byte[960];
for (int i = 0; i != arr.Length; i++)
{
arr[i] = byte.MaxValue;
}
var big = new BigInteger(arr);
}
is working pretty fine and the result is -1 because the representation of the number is in the two's complement. That means a number with just 1s in binary always resolves to -1 as you can see in the article.
if you add one Length more and set the last element of the array to zero you should get a positive number which represents your binary number (this one byte will not hurt you):
var arr = new byte[961];
arr[arr.Length-1] = 0;
var big2 = new BigInteger(arr);
but then you really should be sure in what format your binary number is and what BigInteger is "reading"

Bit shifting c# what's going on here?

So I'm curious, what exactly is going on here?
static void SetUInt16 (byte [] bytes, int offset, ushort val)
{
bytes [offset] = (byte) ((val & 0x0ff00) >> 8);
bytes [offset + 1] = (byte) (val & 0x0ff);
}
Basically the idea in this code is to set a 16 bit int into a byte buffer at a specific location, but the problem is I'm trying to emulate it using
using(var ms = new MemoryStream())
using(var w = new BinaryWriter(ms))
{
w.Write((ushort)1);
}
I'm expecting to read 1 but instead I'm getting 256. Is this an endianness issue?
The code writes a 16-bit integer in big-endian order. Upper byte is written first. Not the same thing that BinaryWriter does, it writes in little-endian order.
When you decode the data, are you getting 256 when you expect 1? BinaryWriter.Write uses little-endian encoding, your SetUInt16 method is using big-endian.

How to generate a LONG guid?

I would like to generate a long UUID - something like the session key used by gmail. It should be at least 256 chars and no more than 512. It can contain all alpha-numeric chars and a few special chars (the ones below the function keys on the keyboard). Has this been done already or is there a sample out there?
C++ or C#
Update: A GUID is not enough. We already have been seeing collisions and need to remedy this. 512 is the max as of now because it will prevent us from changing stuff that was already shipped.
Update 2: For the guys who are insisting about how unique the GUID is, if someone wants to guess your next session ID, they don't have to compute the combinations for the next 1 trillion years. All they have to do is use constrain the time factor and they will be done in hours.
If your GUIDs are colliding, may I ask how you're generating them?
It is astronomically improbable that GUIDs would collide as they are based on:
60 bits - timestamp during generation
48 bits - computer identifier
14 bits - unique ID
6 bits are fixed
You would have to run the GUID generation on the same machine about 50 times in the exact same instant in time in order to have a 50% chance of collision. Note that instant is measured down to nanoseconds.
Update:
As per your comment "putting GUIDs into a hashtable"... the GetHashCode() method is what is causing the collision, not the GUIDs:
public override int GetHashCode()
{
return ((this._a ^ ((this._b << 0x10) | ((ushort) this._c))) ^ ((this._f << 0x18) | this._k));
}
You can see it returns an int, so if you have more than 2^32 "GUIDs" in the hashtable, you are 100% going to have a collision.
As per your update2 you are correct on Guids are predicable even the msdn references that. here is a method that uses a crptographicly strong random number generator to create the ID.
static long counter; //store and load the counter from persistent storage every time the program loads or closes.
public static string CreateRandomString(int length)
{
long count = System.Threading.Interlocked.Increment(ref counter);
int PasswordLength = length;
String _allowedChars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ23456789";
Byte[] randomBytes = new Byte[PasswordLength];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(randomBytes);
char[] chars = new char[PasswordLength];
int allowedCharCount = _allowedChars.Length;
for (int i = 0; i < PasswordLength; i++)
{
while(randomBytes[i] > byte.MaxValue - (byte.MaxValue % allowedCharCount))
{
byte[] tmp = new byte[1];
rng.GetBytes(tmp);
randomBytes[i] = tmp[0];
}
chars[i] = _allowedChars[(int)randomBytes[i] % allowedCharCount];
}
byte[] buf = new byte[8];
buf[0] = (byte) count;
buf[1] = (byte) (count >> 8);
buf[2] = (byte) (count >> 16);
buf[3] = (byte) (count >> 24);
buf[4] = (byte) (count >> 32);
buf[5] = (byte) (count >> 40);
buf[6] = (byte) (count >> 48);
buf[7] = (byte) (count >> 56);
return Convert.ToBase64String(buf) + new string(chars);
}
EDIT I know there is some biasing because allowedCharCount is not evenly divisible by 255, you can get rid of the bias throwing away and getting a new random number if it lands in the no-mans-land of the remainder.
EDIT2 - This is not guaranteed to be unique, you could hold a static 64 bit(or higher if necessary) monotonic counter encode it to base46 and have that be the first 4-5 characters of the id.
UPDATE - Now guaranteed to be unique
UPDATE 2: Algorithm is now slower but removed biasing.
EDIT: I just ran a test, I wanted to let you know that ToBase64String can return non alphnumeric charaters (like 1 encodes to "AQAAAAAAAAA=") just so you are aware.
New Version:
Taking from Matt Dotson's answer on this page, if you are no so worried about the keyspace you can do it this way and it will run a LOT faster.
public static string CreateRandomString(int length)
{
length -= 12; //12 digits are the counter
if (length <= 0)
throw new ArgumentOutOfRangeException("length");
long count = System.Threading.Interlocked.Increment(ref counter);
Byte[] randomBytes = new Byte[length * 3 / 4];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(randomBytes);
byte[] buf = new byte[8];
buf[0] = (byte)count;
buf[1] = (byte)(count >> 8);
buf[2] = (byte)(count >> 16);
buf[3] = (byte)(count >> 24);
buf[4] = (byte)(count >> 32);
buf[5] = (byte)(count >> 40);
buf[6] = (byte)(count >> 48);
buf[7] = (byte)(count >> 56);
return Convert.ToBase64String(buf) + Convert.ToBase64String(randomBytes);
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < HOW_MUCH_YOU_WANT / 32; i++)
sb.Append(Guid.NewGuid().ToString("N"));
return sb.ToString();
but what for?
The problem here is why, not how. A session ID bigger than a GUID is useless, because it's already big enough to thwart brute force attacks.
If you're concerned about predicting GUID's, don't be. Unlike the earlier, sequential GUID's, V4 GUID's are cryptographically secure, based on RC4. The only exploit I know about depends on having full access to the internal state of the process that's generating the values, so it can't get you anywhere if all you have is a partial sequence of GUID's.
If you're paranoid, generate a GUID, hash it with something like SHA-1, and use that value. However, this is a waste of time. If you're concerned about session hijacking, you should be looking at SSL, not this.
byte[] random = new Byte[384];
//RNGCryptoServiceProvider is an implementation of a random number generator.
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(random);
var sessionId = Convert.ToBase64String(random);
You can replace the "/" and "=" from the base64 encoding to be whatever special characters are acceptable to you.
Base64 encoding creates a string that is 4/3 larger than the byte array (hence the 384 bytes should give you 512 characters).
This should give you orders of magnatude more values than a base16 (hex) encoded guid. 512^16 vs 512^64
Also if you are putting these in sql server, make sure to turn OFF case insensitivity.
There are two really easy ways (C#):
1) Generate a bunch of Guids using Guid.NewGuid().ToString("N"). each GUID will be 32 characters long, so just generate 8 of them and concatenate them to get 256 chars.
2) Create a constant string (const string sChars = "abcdef") of acceptable characters you'd like in your UID. Then in a loop, randomly pick characters from that string by randomly generating a number from 0 to the length of the string of acceptable characters (sChars), and concatenate them in a new string (use stringbuilder to make it more performant, but string will work too).
You may want to check out boost's Uuid Library. It supports a variety of generators, including a random generator that might suit your needs.
I would use some kind of hash of std::time() probably sha512.
ex (using crypto++ for the sha hash + base64 encoding).
#include <iostream>
#include <sstream>
#include <ctime>
#include <crypto++/sha.h>
#include <crypto++/base64.h>
int main() {
std::string digest;
std::stringstream ss("");
ss << std::time(NULL);
// borrowed from http://www.cryptopp.com/fom-serve/cache/50.html
CryptoPP::SHA512 hash;
CryptoPP::StringSource foo(ss.str(), true,
new CryptoPP::HashFilter(hash,
new CryptoPP::Base64Encoder(
new CryptoPP::StringSink(digest))));
std::cout << digest << std::endl;
return 0;
}
https://github.com/bigfatsea/SUID Simple Unique Identifier
Though it's in Java, but can be easily ported to any other language. You may expect duplicated ids on same instance 136 years later, good enough for medium-small projects.
Example:
long id = SUID.id().get();

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