A huge part of cryptography is big numbers. Really big numbers. For example, the SHA-256 cryptographic hash produces a 256-bit thumbprint of any data you give it. Exactly how big is 256-bits?
- 8 bits = 256
- 16 bits = 65536
- 32 bits = 4294967296
- 64 bits = 1.84467E+19
- 128 bits = 3.40282E+38
- 256 bits = 1.15792E+77
So the maximum value for a 256-bit unsigned integer is:
115 792 089 237 316 195 423 570 985 008 687 907 853 269 984 665 640 564 039 457 584 007 913 129 639 936
Unfortunately most programming languages only have 32-bit or at most 64-bit numbers available. So in order to store large numbers like these they require you to make the awkward move to byte arrays or some other complex construct. That isn’t the case with Oxygene.
Oxygene has the BigInteger datatype. BigInteger is an arbitrary length signed integer, so it can be as big as you have memory for, and it can be used like a normal integer.
To include BigInteger support you just need to add a reference to the System.Numerics.dll assembly (part of the .NET 4.0 Framework), add System.Numerics to your uses clause, and you are good to go. Now you can use BigIntegers just like any other data type.
Behind the scenes, BigInteger is actually an object with methods, properties, constructors and operators to make it easier to work with BigIntegers. So instead of using Math.Abs use BigInteger.Abs.
You are probably wondering “What does all of this have to do with cryptography?”. I’m glad you asked. Here is a method to calculate a SHA-256 on a string and return the value as a BigInteger
classmethod Hash.Sha256(text: String): BigInteger;beginusing hash256: SHA256Managed :=new SHA256Managed()dobeginvar bytes := Encoding.UTF8.GetBytes(text);var hash := hash256.ComputeHash(bytes);exitnew BigInteger(hash);end;end; |
Another great place to use BigIntegers is with the cryptographic random number generator. Unlike the random number generator you are used to, the one provided by the RNGCryptoServiceProvider is cryptographically secure – meaning future values cannot be predicted. The RNGCryptoServiceProvider will generate a sequence of bytes of any size, which makes BigIntegers another great fit.
About creating a BigInteger from a byte array: Since a BigInteger is signed, this is just about as likely to result in a negative as a positive number. If you always want a positive number, you can append a zero byte to the end of the byte array, we will do that for our random number routine.
This method will return a BigInteger of the number of bytes specified.
classmethod Rnd.BigRnd(bytes: Cardinal): BigInteger;beginusing rng :=new RNGCryptoServiceProvider dobeginvar tokens :=new Byte[bytes +1];// one extra byte for the sign rng.GetBytes(tokens); tokens[bytes]:=0;// keep the result positiveresult:=new BigInteger(tokens);end;end; |