Improve CryptoUtils with wrappers for managed implementations of standard hashing...
[NovacoinLibrary.git] / Novacoin / CryptoUtils.cs
index fde2880..12e4bfd 100644 (file)
-\feffusing System;
+\feff/**
+ *  Novacoin classes library
+ *  Copyright (C) 2015 Alex D. (balthazar.ad@gmail.com)
+
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU Affero General Public License as
+ *  published by the Free Software Foundation, either version 3 of the
+ *  License, or (at your option) any later version.
+
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Affero General Public License for more details.
+
+ *  You should have received a copy of the GNU Affero General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+using System;
+using System.IO;
 using System.Security.Cryptography;
 
 namespace Novacoin
 {
     public class CryptoUtils
     {
+        private static SHA1Managed _sha1 = new SHA1Managed();
+        private static SHA256Managed _sha256 = new SHA256Managed();
+        private static RIPEMD160Managed _ripe160 = new RIPEMD160Managed();
+
+        /// <summary>
+        /// Sha1 calculation
+        /// </summary>
+        /// <param name="inputBytes">Bytes to hash</param>
+        /// <returns>Hashing result</returns>
+        public static byte[] ComputeSha1(byte[] inputBytes)
+        {
+            return _sha1.ComputeHash(inputBytes, 0, inputBytes.Length);
+        }
+
+        /// <summary>
+        /// Sha256 calculation
+        /// </summary>
+        /// <param name="inputBytes">Bytes to hash</param>
+        /// <returns>Hashing result</returns>
+        public static byte[] ComputeSha256(byte[] inputBytes)
+        {
+            return _sha256.ComputeHash(inputBytes, 0, inputBytes.Length);
+        }
+
+        /// <summary>
+        /// RIPEMD-160 calculation
+        /// </summary>
+        /// <param name="inputBytes">Bytes to hash</param>
+        /// <returns>Hashing result</returns>
+        public static byte[] ComputeRipeMD160(byte[] inputBytes)
+        {
+            return _ripe160.ComputeHash(inputBytes, 0, inputBytes.Length);
+        }
+
+        /// <summary>
+        /// RipeMD160(Sha256(X)) calculation
+        /// </summary>
+        /// <param name="inputBytes">Bytes to hash</param>
+        /// <returns>Hashing result</returns>
+        public static byte[] ComputeHash160(byte[] inputBytes)
+        {
+            var digest1 = _sha256.ComputeHash(inputBytes, 0, inputBytes.Length);
+            return _ripe160.ComputeHash(digest1, 0, digest1.Length);
+        }
+
+        /// <summary>
+        /// Sha256(Sha256(X)) calculation
+        /// </summary>
+        /// <param name="inputBytes">Bytes to hash</param>
+        /// <returns>Hashing result</returns>
+        public static byte[] ComputeHash256(byte[] dataBytes)
+        {
+            var digest1 = _sha256.ComputeHash(dataBytes, 0, dataBytes.Length);
+            return _sha256.ComputeHash(digest1, 0, digest1.Length);
+        }
+
+        /// <summary>
+        /// Sha256(Sha256(X)) calculation
+        /// </summary>
+        /// <param name="input1">Reference to first half of data</param>
+        /// <param name="input2">Reference to second half of data</param>
+        /// <returns>Hashing result</returns>
+        public static byte[] ComputeHash256(ref byte[] input1, ref byte[] input2)
+        {
+            var buffer = new byte[64];
+
+            input1.CopyTo(buffer, 0);
+            input2.CopyTo(buffer, input1.Length);
+
+            var digest1 = _sha256.ComputeHash(buffer, 0, buffer.Length);
+            return _sha256.ComputeHash(digest1, 0, digest1.Length);
+        }
+
         public static byte[] PBKDF2_Sha256(int dklen, byte[] password, byte[] salt, int iterationCount)
         {
+            /* Init HMAC state. */
             using (var hmac = new HMACSHA256(password))
             {
                 int hashLength = hmac.HashSize / 8;
                 if ((hmac.HashSize & 7) != 0)
+                {
                     hashLength++;
+                }
                 int keyLength = dklen / hashLength;
-                if ((long)dklen > (0xFFFFFFFFL * hashLength) || dklen < 0)
+                if (dklen > (0xFFFFFFFFL * hashLength) || dklen < 0)
+                {
                     throw new ArgumentOutOfRangeException("dklen");
+                }
                 if (dklen % hashLength != 0)
+                {
                     keyLength++;
-                byte[] extendedkey = new byte[salt.Length + 4];
+                }
+                var extendedkey = new byte[salt.Length + 4];
                 Buffer.BlockCopy(salt, 0, extendedkey, 0, salt.Length);
-                using (var ms = new System.IO.MemoryStream())
+                using (var ms = new MemoryStream())
                 {
+                    /* Iterate through the blocks. */
                     for (int i = 0; i < keyLength; i++)
                     {
+                        /* Generate INT(i + 1). */
                         extendedkey[salt.Length] = (byte)(((i + 1) >> 24) & 0xFF);
                         extendedkey[salt.Length + 1] = (byte)(((i + 1) >> 16) & 0xFF);
                         extendedkey[salt.Length + 2] = (byte)(((i + 1) >> 8) & 0xFF);
                         extendedkey[salt.Length + 3] = (byte)(((i + 1)) & 0xFF);
-                        byte[] u = hmac.ComputeHash(extendedkey);
+
+                        /* Compute U_1 = PRF(P, S || INT(i)). */
+                        var u = hmac.ComputeHash(extendedkey);
                         Array.Clear(extendedkey, salt.Length, 4);
-                        byte[] f = u;
+
+                        /* T_i = U_1 ... */
+                        var f = u;
                         for (int j = 1; j < iterationCount; j++)
                         {
+                            /* Compute U_j. */
                             u = hmac.ComputeHash(u);
                             for (int k = 0; k < f.Length; k++)
                             {
+                                /* ... xor U_j ... */
                                 f[k] ^= u[k];
                             }
                         }
+
+                        /* Copy as many bytes as necessary into memory stream. */
                         ms.Write(f, 0, f.Length);
                         Array.Clear(u, 0, u.Length);
                         Array.Clear(f, 0, f.Length);
                     }
-                    byte[] dk = new byte[dklen];
                     ms.Position = 0;
+
+                    /* Initialize result array. */
+                    var dk = new byte[dklen];
+
+                    /* Read key from memory stream. */
                     ms.Read(dk, 0, dklen);
+
                     ms.Position = 0;
                     for (long i = 0; i < ms.Length; i++)
                     {