diff --git a/analyzers/tests/SonarAnalyzer.Test/Rules/Hotspots/CreatingHashAlgorithmsTest.cs b/analyzers/tests/SonarAnalyzer.Test/Rules/Hotspots/CreatingHashAlgorithmsTest.cs index 6334ffaf170..a0ababa2356 100644 --- a/analyzers/tests/SonarAnalyzer.Test/Rules/Hotspots/CreatingHashAlgorithmsTest.cs +++ b/analyzers/tests/SonarAnalyzer.Test/Rules/Hotspots/CreatingHashAlgorithmsTest.cs @@ -29,6 +29,7 @@ public class CreatingHashAlgorithmsTest private readonly VerifierBuilder builderCS = new VerifierBuilder().WithBasePath("Hotspots") .AddReferences(MetadataReferenceFacade.SystemSecurityCryptography) .AddAnalyzer(() => new CS.CreatingHashAlgorithms(AnalyzerConfiguration.AlwaysEnabled)); + private readonly VerifierBuilder builderVB = new VerifierBuilder().WithBasePath("Hotspots") .AddReferences(MetadataReferenceFacade.SystemSecurityCryptography) .AddAnalyzer(() => new VB.CreatingHashAlgorithms(AnalyzerConfiguration.AlwaysEnabled)); @@ -39,6 +40,10 @@ public void CreatingHashAlgorithms_CSharp8() => .WithOptions(ParseOptionsHelper.FromCSharp8) .Verify(); + [TestMethod] + public void CreatingHashAlgorithms_VB() => + builderVB.AddPaths("CreatingHashAlgorithms.vb").Verify(); + #if NETFRAMEWORK // HMACRIPEMD160, MD5Cng, RIPEMD160Managed and RIPEMD160 are available only for .Net Framework [TestMethod] @@ -47,14 +52,6 @@ public void CreatingHashAlgorithms_CS_NetFx() => .WithOptions(ParseOptionsHelper.FromCSharp8) .Verify(); -#endif - - [TestMethod] - public void CreatingHashAlgorithms_VB() => - builderVB.AddPaths("CreatingHashAlgorithms.vb").Verify(); - -#if NETFRAMEWORK // HMACRIPEMD160, MD5Cng, RIPEMD160Managed and RIPEMD160 are available only for .Net Framework - [TestMethod] public void CreatingHashAlgorithms_VB_NetFx() => builderVB.AddPaths("CreatingHashAlgorithms.NetFramework.vb").Verify(); @@ -64,12 +61,8 @@ public void CreatingHashAlgorithms_VB_NetFx() => #if NET [TestMethod] - public void CreatingHashAlgorithms_CSharp11() => - builderCS.AddPaths("CreatingHashAlgorithms.CSharp11.cs").WithOptions(ParseOptionsHelper.FromCSharp11).Verify(); - - [TestMethod] - public void CreatingHashAlgorithms_CSharp12() => - builderCS.AddPaths("CreatingHashAlgorithms.CSharp12.cs").WithOptions(ParseOptionsHelper.FromCSharp12).VerifyNoIssues(); + public void CreatingHashAlgorithms_CS_Latest() => + builderCS.AddPaths("CreatingHashAlgorithms.Latest.cs").WithOptions(ParseOptionsHelper.CSharpLatest).Verify(); #endif diff --git a/analyzers/tests/SonarAnalyzer.Test/Rules/SymbolicExecution/HashesShouldHaveUnpredictableSaltTest.cs b/analyzers/tests/SonarAnalyzer.Test/Rules/SymbolicExecution/HashesShouldHaveUnpredictableSaltTest.cs index 0a12aa2f95e..fe3263dc846 100644 --- a/analyzers/tests/SonarAnalyzer.Test/Rules/SymbolicExecution/HashesShouldHaveUnpredictableSaltTest.cs +++ b/analyzers/tests/SonarAnalyzer.Test/Rules/SymbolicExecution/HashesShouldHaveUnpredictableSaltTest.cs @@ -85,48 +85,19 @@ public void HashesShouldHaveUnpredictableSalt_Roslyn_CSharp8() => #if NET [TestMethod] - public void HashesShouldHaveUnpredictableSalt_Roslyn_CSharp8_NetCore() => - roslynCS.AddPaths("HashesShouldHaveUnpredictableSalt.CSharp8.NetCore.cs") - .WithOptions(ParseOptionsHelper.FromCSharp8) - .Verify(); - - [TestMethod] - public void HashesShouldHaveUnpredictableSalt_Sonar_CSharp9() => - sonar.AddPaths("HashesShouldHaveUnpredictableSalt.CSharp9.cs") + public void HashesShouldHaveUnpredictableSalt_Roslyn_CS_Latest() => + roslynCS.AddPaths("HashesShouldHaveUnpredictableSalt.Latest.cs") + .WithOptions(ParseOptionsHelper.CSharpLatest) .WithTopLevelStatements() .Verify(); [TestMethod] - public void HashesShouldHaveUnpredictableSalt_Roslyn_CSharp9() => - roslynCS - .AddPaths("HashesShouldHaveUnpredictableSalt.CSharp9.cs") + public void HashesShouldHaveUnpredictableSalt_Sonar_CS_Latest() => + sonar.AddPaths("HashesShouldHaveUnpredictableSalt.Latest.cs") + .WithOptions(ParseOptionsHelper.CSharpLatest) .WithTopLevelStatements() .Verify(); - [TestMethod] - public void HashesShouldHaveUnpredictableSalt_Sonar_CSharp10() => - sonar.AddPaths("HashesShouldHaveUnpredictableSalt.CSharp10.cs") - .WithOptions(ParseOptionsHelper.FromCSharp10) - .VerifyNoIssues(); - - [TestMethod] - public void HashesShouldHaveUnpredictableSalt_Roslyn_CSharp10() => - roslynCS.AddPaths("HashesShouldHaveUnpredictableSalt.CSharp10.cs") - .WithOptions(ParseOptionsHelper.FromCSharp10) - .Verify(); - - [TestMethod] - public void HashesShouldHaveUnpredictableSalt_Sonar_CSharp11() => - sonar.AddPaths("HashesShouldHaveUnpredictableSalt.CSharp11.cs") - .WithOptions(ParseOptionsHelper.FromCSharp11) - .VerifyNoIssues(); - - [TestMethod] - public void HashesShouldHaveUnpredictableSalt_Roslyn_CSharp11() => - roslynCS.AddPaths("HashesShouldHaveUnpredictableSalt.CSharp11.cs") - .WithOptions(ParseOptionsHelper.FromCSharp11) - .VerifyNoIssues(); - #endif [TestMethod] diff --git a/analyzers/tests/SonarAnalyzer.Test/TestCases/Hotspots/CreatingHashAlgorithms.CSharp11.cs b/analyzers/tests/SonarAnalyzer.Test/TestCases/Hotspots/CreatingHashAlgorithms.CSharp11.cs deleted file mode 100644 index 2354b3fc56c..00000000000 --- a/analyzers/tests/SonarAnalyzer.Test/TestCases/Hotspots/CreatingHashAlgorithms.CSharp11.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.Security.Cryptography; - -namespace Tests.Diagnostics -{ - public class InsecureHashAlgorithm - { - const string part1 = """System.Security.Cryptography"""; - const string part2 = """SHA1"""; - - void RawStringLiterals(byte[] temp) - { - using var SHA1HashAlgorithmWithNamespaceRawStringLiteral = HashAlgorithm.Create("""System.Security.Cryptography.SHA1"""); // Noncompliant - using var SHA1HashAlgorithmWithNamespaceInterpolatedRawStringLiteral = HashAlgorithm.Create($$"""{{part1}}.{{part2}}"""); // Noncompliant - } - - void NewlinesInStringInterpolation() - { - using var SHA1HashAlgorithm = HashAlgorithm.Create($"{part1 + - '.' + - part2}"); // FN (at the moment we validate only constant string) - using var SHA1HashAlgorithmRawString = HashAlgorithm.Create($$"""{{part1 + - '.' + - part2}}"""); // FN (at the moment we validate only constant string) - } - } - - // All the new .NET5 methods should be taken into consideration - // https://github.com/SonarSource/sonar-dotnet/issues/8758 - public class Repro_FN_8758 - { - void Method() - { - var data = new byte[42]; - using var stream = new System.IO.MemoryStream(data); - SHA1.HashData(stream); // FN - SHA1.HashData(data); // FN - } - } -} diff --git a/analyzers/tests/SonarAnalyzer.Test/TestCases/Hotspots/CreatingHashAlgorithms.CSharp12.cs b/analyzers/tests/SonarAnalyzer.Test/TestCases/Hotspots/CreatingHashAlgorithms.CSharp12.cs deleted file mode 100644 index 91349eb952f..00000000000 --- a/analyzers/tests/SonarAnalyzer.Test/TestCases/Hotspots/CreatingHashAlgorithms.CSharp12.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Security.Cryptography; - -class PrimaryConstructor(string ctorParam = "MD5") -{ - void Method(string methodParam = "MD5") - { - var md5Ctor = (HashAlgorithm)CryptoConfig.CreateFromName(ctorParam); // FN - var md5Method = (HashAlgorithm)CryptoConfig.CreateFromName(methodParam); // FN - var lambda = (string lambdaParam = "MD5") => (HashAlgorithm)CryptoConfig.CreateFromName(lambdaParam); // FN - } -} diff --git a/analyzers/tests/SonarAnalyzer.Test/TestCases/Hotspots/CreatingHashAlgorithms.Latest.cs b/analyzers/tests/SonarAnalyzer.Test/TestCases/Hotspots/CreatingHashAlgorithms.Latest.cs new file mode 100644 index 00000000000..c82fcdbd474 --- /dev/null +++ b/analyzers/tests/SonarAnalyzer.Test/TestCases/Hotspots/CreatingHashAlgorithms.Latest.cs @@ -0,0 +1,65 @@ +using System.Security.Cryptography; +using System.Text; + +public class InsecureHashAlgorithm +{ + const string part1 = """System.Security.Cryptography"""; + const string part2 = """SHA1"""; + + void RawStringLiterals(byte[] temp) + { + using var SHA1HashAlgorithmWithNamespaceRawStringLiteral = HashAlgorithm.Create("""System.Security.Cryptography.SHA1"""); // Noncompliant + using var SHA1HashAlgorithmWithNamespaceInterpolatedRawStringLiteral = HashAlgorithm.Create($$"""{{part1}}.{{part2}}"""); // Noncompliant + } + + void NewlinesInStringInterpolation() + { + using var SHA1HashAlgorithm = HashAlgorithm.Create($"{part1 + + '.' + + part2}"); // FN (at the moment we validate only constant string) + using var SHA1HashAlgorithmRawString = HashAlgorithm.Create($$"""{{part1 + + '.' + + part2}}"""); // FN (at the moment we validate only constant string) + } +} + +// All the new .NET5 methods should be taken into consideration +// https://github.com/SonarSource/sonar-dotnet/issues/8758 +public class Repro_FN_8758 +{ + void Method() + { + var data = new byte[42]; + using var stream = new System.IO.MemoryStream(data); + SHA1.HashData(stream); // FN + SHA1.HashData(data); // FN + } +} + +class PrimaryConstructor(string ctorParam = "MD5") +{ + void Method(string methodParam = "MD5") + { + var md5Ctor = (HashAlgorithm)CryptoConfig.CreateFromName(ctorParam); // FN + var md5Method = (HashAlgorithm)CryptoConfig.CreateFromName(methodParam); // FN + var lambda = (string lambdaParam = "MD5") => (HashAlgorithm)CryptoConfig.CreateFromName(lambdaParam); // FN + } +} + +class CSHarp13 +{ + void KMAK_Hashing() + { + using var kmac128 = new Kmac128(new byte[] { 0x01, 0x02, 0x03, 0x04 }); // Compliant + using var kmac256 = new Kmac256(new byte[] { 0x01, 0x02, 0x03, 0x04 }); // Compliant + using var kmacXof128 = new KmacXof128(new byte[] { 0x01, 0x02, 0x03, 0x04 }); // Compliant + using var kmacXof256 = new KmacXof256(new byte[] { 0x01, 0x02, 0x03, 0x04 }); // Compliant + + byte[] data = Encoding.UTF8.GetBytes("KMAK"); + byte[] key = new byte[] { 0x01, 0x02, 0x03, 0x04 }; + byte[] mac128 = Kmac128.HashData(key, data, 200); // Compliant + byte[] mac256 = Kmac256.HashData(key, data, 200); // Compliant + byte[] macXof128 = KmacXof128.HashData(key, data, 200); // Compliant + byte[] macXof256 = KmacXof256.HashData(key, data, 200); // Compliant + } +} diff --git a/analyzers/tests/SonarAnalyzer.Test/TestCases/SymbolicExecution/Roslyn/HashesShouldHaveUnpredictableSalt.CSharp10.cs b/analyzers/tests/SonarAnalyzer.Test/TestCases/SymbolicExecution/Roslyn/HashesShouldHaveUnpredictableSalt.CSharp10.cs deleted file mode 100644 index e4fcd05e66c..00000000000 --- a/analyzers/tests/SonarAnalyzer.Test/TestCases/SymbolicExecution/Roslyn/HashesShouldHaveUnpredictableSalt.CSharp10.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Security.Cryptography; - -public class Sample -{ - public void Examples(byte[] passwordBytes) - { - (var shortSalt, int a) = (new byte[15], 42); - PasswordDeriveBytes aes = new PasswordDeriveBytes(passwordBytes, shortSalt); // Noncompliant - } -} diff --git a/analyzers/tests/SonarAnalyzer.Test/TestCases/SymbolicExecution/Roslyn/HashesShouldHaveUnpredictableSalt.CSharp11.cs b/analyzers/tests/SonarAnalyzer.Test/TestCases/SymbolicExecution/Roslyn/HashesShouldHaveUnpredictableSalt.CSharp11.cs deleted file mode 100644 index 9ff2d4cea44..00000000000 --- a/analyzers/tests/SonarAnalyzer.Test/TestCases/SymbolicExecution/Roslyn/HashesShouldHaveUnpredictableSalt.CSharp11.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Security.Cryptography; -using System.Text; - -public class Sample -{ - public void Examples() - { - const string passwordString = "Secret"; - var passwordBytes = Encoding.UTF8.GetBytes("Secret"); - - var shortSalt = "123456789012345"u8.ToArray(); - - var safeSalt = "1234567890123456"u8.ToArray(); - RandomNumberGenerator.Create().GetNonZeroBytes(safeSalt); - - using var pdb1 = new PasswordDeriveBytes(passwordBytes, shortSalt); // FN - using var pdb2 = new PasswordDeriveBytes(passwordBytes, safeSalt); - - new Rfc2898DeriveBytes(passwordString, shortSalt); // FN - new Rfc2898DeriveBytes(passwordString, safeSalt); - } -} diff --git a/analyzers/tests/SonarAnalyzer.Test/TestCases/SymbolicExecution/Roslyn/HashesShouldHaveUnpredictableSalt.CSharp8.NetCore.cs b/analyzers/tests/SonarAnalyzer.Test/TestCases/SymbolicExecution/Roslyn/HashesShouldHaveUnpredictableSalt.CSharp8.NetCore.cs deleted file mode 100644 index 518b51fd100..00000000000 --- a/analyzers/tests/SonarAnalyzer.Test/TestCases/SymbolicExecution/Roslyn/HashesShouldHaveUnpredictableSalt.CSharp8.NetCore.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Security.Cryptography; - -public interface InterfaceWithMethodImplementation -{ - public void Method(string password) - { - var salt = new byte[16]; - new Rfc2898DeriveBytes(password, salt); // Noncompliant - } -} diff --git a/analyzers/tests/SonarAnalyzer.Test/TestCases/SymbolicExecution/Roslyn/HashesShouldHaveUnpredictableSalt.CSharp9.cs b/analyzers/tests/SonarAnalyzer.Test/TestCases/SymbolicExecution/Roslyn/HashesShouldHaveUnpredictableSalt.Latest.cs similarity index 50% rename from analyzers/tests/SonarAnalyzer.Test/TestCases/SymbolicExecution/Roslyn/HashesShouldHaveUnpredictableSalt.CSharp9.cs rename to analyzers/tests/SonarAnalyzer.Test/TestCases/SymbolicExecution/Roslyn/HashesShouldHaveUnpredictableSalt.Latest.cs index 156b14ab0a8..e1adc506cd1 100644 --- a/analyzers/tests/SonarAnalyzer.Test/TestCases/SymbolicExecution/Roslyn/HashesShouldHaveUnpredictableSalt.CSharp9.cs +++ b/analyzers/tests/SonarAnalyzer.Test/TestCases/SymbolicExecution/Roslyn/HashesShouldHaveUnpredictableSalt.Latest.cs @@ -89,3 +89,69 @@ public partial void Method(byte[] passwordBytes) new PasswordDeriveBytes(passwordBytes, safeSalt); } } + +public interface InterfaceWithMethodImplementation +{ + public void Method(string password) + { + var salt = new byte[16]; + new Rfc2898DeriveBytes(password, salt); // Noncompliant + } +} + +public class Examples +{ + public void CSharp10(byte[] passwordBytes) + { + (var shortSalt, int a) = (new byte[15], 42); + PasswordDeriveBytes aes = new PasswordDeriveBytes(passwordBytes, shortSalt); // Noncompliant + } + + public void CSharp11() + { + const string passwordString = "Secret"; + var passwordBytes = Encoding.UTF8.GetBytes("Secret"); + + var shortSalt = "123456789012345"u8.ToArray(); + + var safeSalt = "1234567890123456"u8.ToArray(); + RandomNumberGenerator.Create().GetNonZeroBytes(safeSalt); + + using var pdb1 = new PasswordDeriveBytes(passwordBytes, shortSalt); // FN + using var pdb2 = new PasswordDeriveBytes(passwordBytes, safeSalt); + + new Rfc2898DeriveBytes(passwordString, shortSalt); // FN + new Rfc2898DeriveBytes(passwordString, safeSalt); + } + + // https://sonarsource.atlassian.net/browse/NET-363 + public void CSharp13_KMAK() + { + const string passwordString = "Secret"; + byte[] key = Encoding.UTF8.GetBytes("fixedKey"); // FN + byte[] input = Encoding.UTF8.GetBytes(passwordString); + byte[] mac = Kmac128.HashData(key, input, outputLength: 32); + + byte[] compliantKey = GenerateRandomKey(); // Compliant + byte[] compliantInput = Encoding.UTF8.GetBytes(passwordString); + byte[] compliantMac = Kmac128.HashData(compliantKey, compliantInput, outputLength: 32); + + using var kmac128 = new Kmac128(new byte[] { 0x01, 0x02, 0x03, 0x04 }); // FN + using var kmac256 = new Kmac256(new byte[] { 0x01, 0x02, 0x03, 0x04 }); // FN + using var kmacXof128 = new KmacXof128(new byte[] { 0x01, 0x02, 0x03, 0x04 }); // FN + using var kmacXof256 = new KmacXof256(new byte[] { 0x01, 0x02, 0x03, 0x04 }); // FN + + var a = Kmac128.HashData(new byte[] { 0x01, 0x02, 0x03, 0x04 }, "Hello"u8.ToArray(), 2); // FN + var b = Kmac256.HashData(new byte[] { 0x01, 0x02, 0x03, 0x04 }, "Hello"u8.ToArray(), 2); // FN + var c = KmacXof128.HashData(new byte[] { 0x01, 0x02, 0x03, 0x04 }, "Hello"u8.ToArray(), 2); // FN + var d = KmacXof256.HashData(new byte[] { 0x01, 0x02, 0x03, 0x04 }, "Hello"u8.ToArray(), 2); // FN + + static byte[] GenerateRandomKey() + { + using var rng = new RNGCryptoServiceProvider(); + byte[] key = new byte[32]; + rng.GetBytes(key); + return key; + } + } +} diff --git a/analyzers/tests/SonarAnalyzer.Test/TestCases/SymbolicExecution/Sonar/HashesShouldHaveUnpredictableSalt.CSharp10.cs b/analyzers/tests/SonarAnalyzer.Test/TestCases/SymbolicExecution/Sonar/HashesShouldHaveUnpredictableSalt.CSharp10.cs deleted file mode 100644 index a8deccfae07..00000000000 --- a/analyzers/tests/SonarAnalyzer.Test/TestCases/SymbolicExecution/Sonar/HashesShouldHaveUnpredictableSalt.CSharp10.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Security.Cryptography; -using System.Text; - -public class Sample -{ - public void Examples(byte[] passwordBytes) - { - (var shortSalt, int a) = (new byte[15], 42); - PasswordDeriveBytes aes = new PasswordDeriveBytes(passwordBytes, shortSalt); // FN - } -} diff --git a/analyzers/tests/SonarAnalyzer.Test/TestCases/SymbolicExecution/Sonar/HashesShouldHaveUnpredictableSalt.CSharp11.cs b/analyzers/tests/SonarAnalyzer.Test/TestCases/SymbolicExecution/Sonar/HashesShouldHaveUnpredictableSalt.CSharp11.cs deleted file mode 100644 index 137be5d1f0b..00000000000 --- a/analyzers/tests/SonarAnalyzer.Test/TestCases/SymbolicExecution/Sonar/HashesShouldHaveUnpredictableSalt.CSharp11.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Security.Cryptography; -using System.Text; - -public class Sample -{ - public void Examples() - { - const string passwordString = "Secret"; - var passwordBytes = Encoding.UTF8.GetBytes("Secret"); - - var shortSalt = "123456789012345"u8.ToArray(); - - var safeSalt = "1234567890123456"u8.ToArray(); - RandomNumberGenerator.Create().GetNonZeroBytes(safeSalt); - - using var pdb1 = new PasswordDeriveBytes(passwordBytes, shortSalt); // FN - using var pdb2 = new PasswordDeriveBytes(passwordBytes, safeSalt); - - new Rfc2898DeriveBytes(passwordString, shortSalt); // FN - new Rfc2898DeriveBytes(passwordString, safeSalt); - } -} diff --git a/analyzers/tests/SonarAnalyzer.Test/TestCases/SymbolicExecution/Sonar/HashesShouldHaveUnpredictableSalt.CSharp9.cs b/analyzers/tests/SonarAnalyzer.Test/TestCases/SymbolicExecution/Sonar/HashesShouldHaveUnpredictableSalt.Latest.cs similarity index 75% rename from analyzers/tests/SonarAnalyzer.Test/TestCases/SymbolicExecution/Sonar/HashesShouldHaveUnpredictableSalt.CSharp9.cs rename to analyzers/tests/SonarAnalyzer.Test/TestCases/SymbolicExecution/Sonar/HashesShouldHaveUnpredictableSalt.Latest.cs index 31fc4b25537..51e4e85ac33 100644 --- a/analyzers/tests/SonarAnalyzer.Test/TestCases/SymbolicExecution/Sonar/HashesShouldHaveUnpredictableSalt.CSharp9.cs +++ b/analyzers/tests/SonarAnalyzer.Test/TestCases/SymbolicExecution/Sonar/HashesShouldHaveUnpredictableSalt.Latest.cs @@ -89,3 +89,29 @@ public partial void Method(byte[] passwordBytes) new PasswordDeriveBytes(passwordBytes, safeSalt); } } + +public class Examples +{ + public void CSharp10(byte[] passwordBytes) + { + (var shortSalt, int a) = (new byte[15], 42); + PasswordDeriveBytes aes = new PasswordDeriveBytes(passwordBytes, shortSalt); // FN + } + + public void CSharp11() + { + const string passwordString = "Secret"; + var passwordBytes = Encoding.UTF8.GetBytes("Secret"); + + var shortSalt = "123456789012345"u8.ToArray(); + + var safeSalt = "1234567890123456"u8.ToArray(); + RandomNumberGenerator.Create().GetNonZeroBytes(safeSalt); + + using var pdb1 = new PasswordDeriveBytes(passwordBytes, shortSalt); // FN + using var pdb2 = new PasswordDeriveBytes(passwordBytes, safeSalt); + + new Rfc2898DeriveBytes(passwordString, shortSalt); // FN + new Rfc2898DeriveBytes(passwordString, safeSalt); + } +}