// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. using System.IO; using System.Security.Cryptography; using System.Text; using Xunit; using Assert = Microsoft.TestCommon.AssertEx; namespace System.Web.Helpers.Test { /// ///This is a test class for CryptoTest and is intended ///to contain all CryptoTest Unit Tests /// public class CryptoTest { [Fact] public void SHA256HashTest_ReturnsValidData() { string data = "foo bar"; string expected = "FBC1A9F858EA9E177916964BD88C3D37B91A1E84412765E29950777F265C4B75"; string actual; actual = Crypto.SHA256(data); Assert.Equal(expected, actual); actual = Crypto.Hash(Encoding.UTF8.GetBytes(data)); Assert.Equal(expected, actual); } [Fact] public void GenerateSaltTest() { string salt = Crypto.GenerateSalt(); salt = Crypto.GenerateSalt(64); Assert.Equal(24, Crypto.GenerateSalt().Length); Assert.Equal(12, Crypto.GenerateSalt(8).Length); Assert.Equal(88, Crypto.GenerateSalt(64).Length); Assert.Equal(44, Crypto.GenerateSalt(32).Length); } [Fact] public void HashPassword_PasswordGeneration() { // Act - call helper directly string generatedHash = Crypto.HashPassword("my-password"); byte[] salt = new byte[16]; Buffer.BlockCopy(Convert.FromBase64String(generatedHash), 1, salt, 0, 16); // extract salt from generated hash // Act - perform PBKDF2 directly string generatedHash2; using (var ms = new MemoryStream()) { using (var bw = new BinaryWriter(ms)) { using (var deriveBytes = new Rfc2898DeriveBytes("my-password", salt, iterations: 1000)) { bw.Write((byte)0x00); // version identifier bw.Write(salt); // salt bw.Write(deriveBytes.GetBytes(32)); // subkey } generatedHash2 = Convert.ToBase64String(ms.ToArray()); } } // Assert Assert.Equal(generatedHash2, generatedHash); } [Fact] public void HashPassword_RoundTripping() { // Act & assert string password = "ImPepper"; Assert.True(Crypto.VerifyHashedPassword(Crypto.HashPassword(password), password)); Assert.False(Crypto.VerifyHashedPassword(Crypto.HashPassword(password), "ImSalt")); Assert.False(Crypto.VerifyHashedPassword(Crypto.HashPassword("Impepper"), password)); } [Fact] public void VerifyHashedPassword_CorrectPassword_ReturnsTrue() { // Arrange string hashedPassword = "ALyuoraY/cIWD1hjo+K81/pf83qo6Q6T+UBYcXN9P3A9WHLvEY10f+lwW5qPG6h9xw=="; // this is for 'my-password' // Act bool retVal = Crypto.VerifyHashedPassword(hashedPassword, "my-password"); // Assert Assert.True(retVal); } [Fact] public void VerifyHashedPassword_IncorrectPassword_ReturnsFalse() { // Arrange string hashedPassword = "ALyuoraY/cIWD1hjo+K81/pf83qo6Q6T+UBYcXN9P3A9WHLvEY10f+lwW5qPG6h9xw=="; // this is for 'my-password' // Act bool retVal = Crypto.VerifyHashedPassword(hashedPassword, "some-other-password"); // Assert Assert.False(retVal); } [Fact] public void VerifyHashedPassword_InvalidPasswordHash_ReturnsFalse() { // Arrange string hashedPassword = "AAECAw=="; // this is an invalid password hash // Act bool retVal = Crypto.VerifyHashedPassword(hashedPassword, "hello-world"); // Assert Assert.False(retVal); } [Fact] public void MD5HashTest_ReturnsValidData() { string data = "foo bar"; string expected = "327B6F07435811239BC47E1544353273"; string actual; actual = Crypto.Hash(data, algorithm: "md5"); Assert.Equal(expected, actual); actual = Crypto.Hash(Encoding.UTF8.GetBytes(data), algorithm: "MD5"); Assert.Equal(expected, actual); } [Fact] public void SHA1HashTest_ReturnsValidData() { string data = "foo bar"; string expected = "3773DEA65156909838FA6C22825CAFE090FF8030"; string actual; actual = Crypto.SHA1(data); Assert.Equal(expected, actual); actual = Crypto.Hash(Encoding.UTF8.GetBytes(data), algorithm: "sha1"); Assert.Equal(expected, actual); } [Fact] public void SHA1HashTest_WithNull_ThrowsException() { Assert.Throws(() => Crypto.SHA1((string)null)); Assert.Throws(() => Crypto.Hash((byte[])null, algorithm: "SHa1")); } [Fact] public void SHA256HashTest_WithNull_ThrowsException() { Assert.Throws(() => Crypto.SHA256((string)null)); Assert.Throws(() => Crypto.Hash((byte[])null, algorithm: "sHa256")); } [Fact] public void MD5HashTest_WithNull_ThrowsException() { Assert.Throws(() => Crypto.Hash((string)null, algorithm: "mD5")); Assert.Throws(() => Crypto.Hash((byte[])null, algorithm: "mD5")); } [Fact] public void HashWithUnknownAlg_ThrowsException() { Assert.Throws(() => Crypto.Hash("sdflksd", algorithm: "hao"), "The hash algorithm 'hao' is not supported, valid values are: sha256, sha1, md5"); } } }