Beispiel #1
0
        public void TestRfc2898DeriveBytes()
        {
            byte[] password = new byte[20];
            byte[] salt = new byte[20];
            int bytes = 64;

            for (int iterations = 1000; iterations <= 10000; iterations += 1000)
            {
                Tester.RandomGenerator.NextBytes(password);
                Tester.RandomGenerator.NextBytes(salt);

                using (PBKDF2<HMACSHA1> pbkdf2 = new PBKDF2<HMACSHA1>(password, salt, iterations))
                using (Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(password, salt, iterations))
                {
                    byte[] pbkdf2Bytes = pbkdf2.GetBytes(bytes);
                    byte[] rfc2898Bytes = rfc2898.GetBytes(bytes);

                    Assert.AreEqual(bytes, rfc2898Bytes.Length);
                    Assert.AreEqual(bytes, pbkdf2Bytes.Length);

                    for (int i = 0; i < bytes; i++)
                        Assert.AreEqual(rfc2898Bytes[i], pbkdf2Bytes[i]);
                }
            }
        }
Beispiel #2
0
		public static void TestPBKDF2()
		{
			PBKDF2 kg;
			byte[] DK;

			byte[] tv1 = new byte[] { 0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71, 0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06, 0x2f, 0xe0, 0x37, 0xa6 };
			kg = new PBKDF2(Encoding.Default.GetBytes("password"), Encoding.Default.GetBytes("salt"), 1);
			DK = kg.GetBytes(20);
			Assert.AreEqual(DK, tv1);

			byte[] tv2 = new byte[] { 0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c, 0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0, 0xd8, 0xde, 0x89, 0x57 };
			kg = new PBKDF2(Encoding.Default.GetBytes("password"), Encoding.Default.GetBytes("salt"), 2);
			DK = kg.GetBytes(20);
			Assert.AreEqual(DK, tv2);

			byte[] tv3 = new byte[] { 0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a, 0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0, 0x65, 0xa4, 0x29, 0xc1 };
			kg = new PBKDF2(Encoding.Default.GetBytes("password"), Encoding.Default.GetBytes("salt"), 4096);
			DK = kg.GetBytes(20);
			Assert.AreEqual(DK, tv3);

			byte[] tv4 = new byte[] { 0x2f, 0x25, 0x5b, 0x3a, 0x95, 0x46, 0x3c, 0x76, 0x62, 0x1f, 0x06, 0x80, 0xa2, 0xb3, 0x35, 0xad, 0x90, 0x3b, 0x85, 0xde };
			kg = new PBKDF2(Encoding.Default.GetBytes("VXFr[24c=6(D8He"), Encoding.Default.GetBytes("salt"), 1000);
			DK = kg.GetBytes(20);
			Assert.AreEqual(DK, tv4);
		}
Beispiel #3
0
        public string Hash(string password, string userSalt)
        {
            using (SHA512 alg = SHA512.Create())
            {
                // _hashArraySize is always a power of 2
                int bitmask = _memoryBlocks - 1;

                // we have a single running hash, but then we combine it with "randomly"-selected cells from the array
                var combinedHash = new byte[(MULTIPLIER + 1) * PasswordHasher.DigestSize];  /* add one because we'll store the running hash there */

            #if DEBUG
                _hashes = new List<string>();
                _visitCounts = new int[_memoryBlocks];
                _hashesPerCell = new List<string>[_memoryBlocks];
                _hashToCells = new Dictionary<string, int[]>();

                for (int i = 0; i < _hashesPerCell.Length; i++ )
                    _hashesPerCell[i] = new List<string>();
            #endif

                byte[] hash = new byte[PasswordHasher.DigestSize];  // the running hash

                // PBKDF2-HMAC-SHA512 the user's password with (system salt + user salt) and use it to fill _hashArray
                var pbkdf2 = new PBKDF2<HMACSHA512>(Encoding.ASCII.GetBytes(password), Encoding.ASCII.GetBytes(_systemSalt + userSalt ?? ""), 1);
                var bytes = pbkdf2.GetBytes(_fillAmount + PasswordHasher.DigestSize);

                /* initialize the running hash to what comes out of PBKDF2 after the _hashArray is filled */
                Buffer.BlockCopy(bytes, _fillAmount, hash, 0, PasswordHasher.DigestSize);

                int blockStart = 0;
                int[] blockStarts = new int[MULTIPLIER];

                // We only PBKDF2 enough for 1/16th of the _hashArray, so duplicate that "_fillAmount" 16 times
                for (var i = 0; i < MULTIPLIER; i++)
                {
                    Buffer.BlockCopy(bytes, 0, _hashArray, blockStart, _fillAmount);
                    blockStart += _fillAmount;
                }

            #if DEBUG
                _originalArray = new byte[_hashArray.Length];
                Buffer.BlockCopy(_hashArray, 0, _originalArray, 0, _hashArray.Length);
            #endif

                // now "randomly mix up" the hash array
                for (int i = 0; i < _mixingIterations; i++)
                {
            #if DEBUG
                    AddHash(hash);
            #endif
                    int combinedHashEnd = PasswordHasher.DigestSize;

                    // combine the running hash with...
                    Buffer.BlockCopy(hash, 0, combinedHash, 0, PasswordHasher.DigestSize);

                    // ..."randomly"-selected cells in the hash array
                    for (int m = 0; m < MULTIPLIER; m++ )
                    {
                        // create a random int from bytes in the running hash and interpret the int as which cell to get a hash from.
                        // Since hashes are 64 bytes long and ints are 4 bytes, we can only get 16 random indexes from the hash,
                        // which is why MULTIPLIER is 16.
                        int nextIndex = (hash[m * 4] + (hash[m * 4 + 1] << 8) + (hash[m * 4 + 2] << 16) +
                            (hash[m * 4 + 3] << 24)) & bitmask;

                        // add that selected hash to the combined hash
                        blockStarts[m] = blockStart = nextIndex * PasswordHasher.DigestSize;
                        Buffer.BlockCopy(_hashArray, blockStart, combinedHash, combinedHashEnd, PasswordHasher.DigestSize);
                        combinedHashEnd += PasswordHasher.DigestSize;
            #if DEBUG
                        _visitCounts[nextIndex]++;
            #endif
                    }

                    // update the running hash
                    hash = alg.ComputeHash(combinedHash);

            #if DEBUG
                    var base64hash = Convert.ToBase64String(hash);
                    _hashToCells[base64hash] = new int[MULTIPLIER];
            #endif

                    for (int m = 0; m < MULTIPLIER; m++)
                    {
                        blockStart = blockStarts[m];
                        // xor the selected hash with the running hash so that the hash array is constantly being modified
                        for (int b = 0; b < PasswordHasher.DigestSize; b++)
                            _hashArray[blockStart + b] ^= hash[b];
            #if DEBUG
                        int hashIndex = blockStart / PasswordHasher.DigestSize;
                        _hashesPerCell[hashIndex].Add(base64hash);
                        _hashToCells[base64hash][m] = hashIndex;
            #endif
                    }
                }

                return Convert.ToBase64String(alg.ComputeHash(_hashArray, 0, MemoryUsage));
            }
        }