diff --git a/csharp/ql/src/experimental/Security Features/CWE-759/HashWithoutSalt.cs b/csharp/ql/src/experimental/Security Features/CWE-759/HashWithoutSalt.cs new file mode 100644 index 00000000000..309d2e0d785 --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/CWE-759/HashWithoutSalt.cs @@ -0,0 +1,65 @@ +public class Test +{ + private const int SaltSize = 32; + + // BAD - Hash without a salt. + public static String HashPassword(string password, string strAlgName ="SHA256") + { + IBuffer passBuff = CryptographicBuffer.ConvertStringToBinary(password, BinaryStringEncoding.Utf8); + HashAlgorithmProvider algProvider = HashAlgorithmProvider.OpenAlgorithm(strAlgName); + IBuffer hashBuff = algProvider.HashData(passBuff); + return CryptographicBuffer.EncodeToBase64String(hashBuff); + } + + // GOOD - Hash with a salt. + public static string HashPassword2(string password, string salt, string strAlgName ="SHA256") + { + // Concatenate the salt with the password. + IBuffer passBuff = CryptographicBuffer.ConvertStringToBinary(password+salt, BinaryStringEncoding.Utf8); + HashAlgorithmProvider algProvider = HashAlgorithmProvider.OpenAlgorithm(strAlgName); + IBuffer hashBuff = algProvider.HashData(passBuff); + return CryptographicBuffer.EncodeToBase64String(hashBuff); + } + + // BAD - Hash without a salt. + public static string HashPassword(string password) + { + SHA256 sha256Hash = SHA256.Create(); + byte[] passBytes = System.Text.Encoding.ASCII.GetBytes(password); + byte[] hashBytes = sha256Hash.ComputeHash(passBytes); + return Convert.ToBase64String(hashBytes); + } + + // GOOD - Hash with a salt. + public static string HashPassword2(string password) + { + byte[] passBytes = System.Text.Encoding.ASCII.GetBytes(password); + byte[] saltBytes = GenerateSalt(); + + // Add the salt to the hash. + byte[] rawSalted = new byte[passBytes.Length + saltBytes.Length]; + passBytes.CopyTo(rawSalted, 0); + saltBytes.CopyTo(rawSalted, passBytes.Length); + + //Create the salted hash. + SHA256 sha256 = SHA256.Create(); + byte[] saltedPassBytes = sha256.ComputeHash(rawSalted); + + // Add the salt value to the salted hash. + byte[] dbPassword = new byte[saltedPassBytes.Length + saltBytes.Length]; + saltedPassBytes.CopyTo(dbPassword, 0); + saltBytes.CopyTo(dbPassword, saltedPassBytes.Length); + + return Convert.ToBase64String(dbPassword); + } + + public static byte[] GenerateSalt() + { + using (var rng = new RNGCryptoServiceProvider()) + { + var randomNumber = new byte[SaltSize]; + rng.GetBytes(randomNumber); + return randomNumber; + } + } +} diff --git a/csharp/ql/src/experimental/Security Features/CWE-759/HashWithoutSalt.ql b/csharp/ql/src/experimental/Security Features/CWE-759/HashWithoutSalt.ql index 6f57b5ae03c..07711e5f1f6 100644 --- a/csharp/ql/src/experimental/Security Features/CWE-759/HashWithoutSalt.ql +++ b/csharp/ql/src/experimental/Security Features/CWE-759/HashWithoutSalt.ql @@ -11,24 +11,25 @@ import csharp import semmle.code.csharp.dataflow.TaintTracking import DataFlow::PathGraph -/** The C# class `System.Security.Cryptography.SHA...` other than the weak `SHA1`. */ -class SHA extends RefType { - SHA() { this.getQualifiedName().regexpMatch("System\\.Security\\.Cryptography\\.SHA\\d{2,3}") } -} - +/** The C# class `Windows.Security.Cryptography.Core.HashAlgorithmProvider`. */ class HashAlgorithmProvider extends RefType { HashAlgorithmProvider() { this.hasQualifiedName("Windows.Security.Cryptography.Core", "HashAlgorithmProvider") } } +/** The C# class `System.Security.Cryptography.HashAlgorithm`. */ +class HashAlgorithm extends RefType { + HashAlgorithm() { this.hasQualifiedName("System.Security.Cryptography", "HashAlgorithm") } +} + /** - * The method `ComputeHash()` declared in `System.Security.Cryptography.SHA...` and + * The method `ComputeHash()` declared in `System.Security.Cryptography.HashAlgorithm` and * the method `HashData()` declared in `Windows.Security.Cryptography.Core.HashAlgorithmProvider`. */ class HashMethod extends Method { HashMethod() { - this.getDeclaringType() instanceof SHA and + this.getDeclaringType() instanceof HashAlgorithm and this.hasName("ComputeHash") or this.getDeclaringType() instanceof HashAlgorithmProvider and