diff --git a/AMWD.Common.Tests/Utilities/CryptographyHelperTests.cs b/AMWD.Common.Tests/Utilities/CryptographyHelperTests.cs new file mode 100644 index 0000000..347cdb3 --- /dev/null +++ b/AMWD.Common.Tests/Utilities/CryptographyHelperTests.cs @@ -0,0 +1,598 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Security.Cryptography; +using System.Text.RegularExpressions; +using AMWD.Common.Tests.Utils; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace AMWD.Common.Tests.Utilities +{ + [TestClass] + public class CryptographyHelperTests + { + private string keyFile; + private CryptographyHelper cryptoHelper; + + [TestInitialize] + public void Initialize() + { + keyFile = Path.GetTempFileName(); + cryptoHelper = new CryptographyHelper(keyFile); + } + + [TestCleanup] + public void Cleanup() + { + File.Delete(keyFile); + } + + #region Static + + #region Encryption + + #region AES + + [TestMethod] + public void ShouldEncryptAesWithoutSalt() // required to test the encryption itself + { + // arrange + using var disposable = CryptographyHelperSaltMock.Create(0); + + byte[] bytes = new byte[] { 0xaf, 0xfe }; + string str = "ABC"; + string password1 = "P@ssw0rd!"; + string password2 = "P@ssw0rd"; + + byte[] expectedBytes = new byte[] { 0x7c, 0x7b, 0x77, 0x56, 0x91, 0x1a, 0xd9, 0xc0, 0x72, 0x70, 0x36, 0x88, 0x9f, 0xb4, 0xb5, 0xbc }; + + // act + byte[] cipherBytes1 = CryptographyHelper.AesEncrypt(bytes, password1); + string cipherStr1 = CryptographyHelper.AesEncrypt(str, password1); + byte[] cipherBytes2 = CryptographyHelper.AesEncrypt(bytes, password2); + string cipherStr2 = CryptographyHelper.AesEncrypt(str, password2); + + // assert + CollectionAssert.AreEqual(expectedBytes, cipherBytes1); + Assert.AreEqual("ueLuhFNpCuYmx8v3hczHtg==", cipherStr1); + + CollectionAssert.AreNotEqual(expectedBytes, cipherBytes2); + Assert.AreNotEqual("ueLuhFNpCuYmx8v3hczHtg==", cipherStr2); + } + + [TestMethod] + public void ShouldDecryptAesWithoutSalt() // required to test the decryption itself + { + // arrange + using var disposable = CryptographyHelperSaltMock.Create(0); + + string cipherStr = "ueLuhFNpCuYmx8v3hczHtg=="; + byte[] cipherBytes = new byte[] { 0x7c, 0x7b, 0x77, 0x56, 0x91, 0x1a, 0xd9, 0xc0, 0x72, 0x70, 0x36, 0x88, 0x9f, 0xb4, 0xb5, 0xbc }; + + string password1 = "P@ssw0rd!"; + string password2 = "P@ssw0rd"; + + byte[] expectedBytes = new byte[] { 0xaf, 0xfe }; + + // act + byte[] plainBytes1 = CryptographyHelper.AesDecrypt(cipherBytes, password1); + string plainStr1 = CryptographyHelper.AesDecrypt(cipherStr, password1); + + try + { + CryptographyHelper.AesDecrypt(cipherBytes, password2); + Assert.Fail(); + } + catch (CryptographicException) + { } + + try + { + CryptographyHelper.AesDecrypt(cipherStr, password2); + Assert.Fail(); + } + catch (CryptographicException) + { } + + // assert + CollectionAssert.AreEqual(expectedBytes, plainBytes1); + Assert.AreEqual("ABC", plainStr1); + } + + [TestMethod] + public void ShouldEncryptDecryptAesBytes() + { + // arrange + byte[] plain = new byte[] { 0xaf, 0xfe }; + string password = "P@ssw0rd!"; + + // act + byte[] cipher1 = CryptographyHelper.AesEncrypt(plain, password); + byte[] cipher2 = CryptographyHelper.AesEncrypt(plain, password); + + byte[] plain1 = CryptographyHelper.AesDecrypt(cipher1, password); + byte[] plain2 = CryptographyHelper.AesDecrypt(cipher2, password); + + // assert + CollectionAssert.AreNotEqual(cipher1, cipher2); + Assert.AreEqual(24, cipher1.Length); + Assert.AreEqual(24, cipher2.Length); + CollectionAssert.AreEqual(plain, plain1); + CollectionAssert.AreEqual(plain, plain2); + } + + [TestMethod] + public void ShouldEncryptDecryptAesString() + { + // arrange + string plain = "ABC"; + string password = "P@ssw0rd!"; + + // act + string cipher1 = CryptographyHelper.AesEncrypt(plain, password); + string cipher2 = CryptographyHelper.AesEncrypt(plain, password); + + string plain1 = CryptographyHelper.AesDecrypt(cipher1, password); + string plain2 = CryptographyHelper.AesDecrypt(cipher2, password); + + // assert + Assert.AreNotEqual(cipher1, cipher2); + Assert.AreEqual(32, cipher1.Length); + Assert.AreEqual(32, cipher2.Length); + Assert.AreEqual(plain, plain1); + Assert.AreEqual(plain, plain2); + } + + #endregion AES + + #region TripleDES + + [TestMethod] + public void ShouldEncryptTdesWithoutSalt() // required to test the encryption itself + { + // arrange + using var disposable = CryptographyHelperSaltMock.Create(0); + + byte[] bytes = new byte[] { 0xaf, 0xfe }; + string str = "ABC"; + string password1 = "P@ssw0rd!"; + string password2 = "P@ssw0rd"; + + byte[] expectedBytes = new byte[] { 0xbf, 0x59, 0x1f, 0x48, 0x69, 0xab, 0x18, 0xc7 }; + + // act + byte[] cipherBytes1 = CryptographyHelper.TripleDesEncrypt(bytes, password1); + string cipherStr1 = CryptographyHelper.TripleDesEncrypt(str, password1); + byte[] cipherBytes2 = CryptographyHelper.TripleDesEncrypt(bytes, password2); + string cipherStr2 = CryptographyHelper.TripleDesEncrypt(str, password2); + + // assert + CollectionAssert.AreEqual(expectedBytes, cipherBytes1); + Assert.AreEqual("1l74soBuuEI=", cipherStr1); + + CollectionAssert.AreNotEqual(expectedBytes, cipherBytes2); + Assert.AreNotEqual("1l74soBuuEI=", cipherStr2); + } + + [TestMethod] + public void ShouldDecryptTdesWithoutSalt() // required to test the decryption itself + { + // arrange + using var disposable = CryptographyHelperSaltMock.Create(0); + + string cipherStr = "1l74soBuuEI="; + byte[] cipherBytes = new byte[] { 0xbf, 0x59, 0x1f, 0x48, 0x69, 0xab, 0x18, 0xc7 }; + + string password1 = "P@ssw0rd!"; + string password2 = "P@ssw0rd"; + + byte[] expectedBytes = new byte[] { 0xaf, 0xfe }; + + // act + byte[] plainBytes1 = CryptographyHelper.TripleDesDecrypt(cipherBytes, password1); + string plainStr1 = CryptographyHelper.TripleDesDecrypt(cipherStr, password1); + + try + { + CryptographyHelper.TripleDesDecrypt(cipherBytes, password2); + Assert.Fail(); + } + catch (CryptographicException) + { } + + try + { + CryptographyHelper.TripleDesDecrypt(cipherStr, password2); + Assert.Fail(); + } + catch (CryptographicException) + { } + + // assert + CollectionAssert.AreEqual(expectedBytes, plainBytes1); + Assert.AreEqual("ABC", plainStr1); + } + + [TestMethod] + public void ShouldEncryptDecryptTdesBytes() + { + // arrange + byte[] plain = new byte[] { 0xaf, 0xfe }; + string password = "P@ssw0rd!"; + + // act + byte[] cipher1 = CryptographyHelper.TripleDesEncrypt(plain, password); + byte[] cipher2 = CryptographyHelper.TripleDesEncrypt(plain, password); + + byte[] plain1 = CryptographyHelper.TripleDesDecrypt(cipher1, password); + byte[] plain2 = CryptographyHelper.TripleDesDecrypt(cipher2, password); + + // assert + CollectionAssert.AreNotEqual(cipher1, cipher2); + Assert.AreEqual(16, cipher1.Length); + Assert.AreEqual(16, cipher2.Length); + CollectionAssert.AreEqual(plain, plain1); + CollectionAssert.AreEqual(plain, plain2); + } + + [TestMethod] + public void ShouldEncryptDecryptTdesString() + { + // arrange + string plain = "ABC"; + string password = "P@ssw0rd!"; + + // act + string cipher1 = CryptographyHelper.TripleDesEncrypt(plain, password); + string cipher2 = CryptographyHelper.TripleDesEncrypt(plain, password); + + string plain1 = CryptographyHelper.TripleDesDecrypt(cipher1, password); + string plain2 = CryptographyHelper.TripleDesDecrypt(cipher2, password); + + // assert + Assert.AreNotEqual(cipher1, cipher2); + Assert.AreEqual(24, cipher1.Length); + Assert.AreEqual(24, cipher2.Length); + Assert.AreEqual(plain, plain1); + Assert.AreEqual(plain, plain2); + } + + #endregion TripleDES + + #endregion Encryption + + #region Hash + + [TestMethod] + public void ShouldReturnMd5Hash() + { + // arrange + string text = "Hello World!"; + byte[] bytes = new byte[] { 0xde, 0xad, 0xbe, 0xef }; + string fileName = Path.GetTempFileName(); + + // act + string textHash = CryptographyHelper.Md5(text); + string bytesHash = CryptographyHelper.Md5(bytes); + + File.WriteAllText(fileName, text); + string fileHash = CryptographyHelper.Md5File(fileName); + File.Delete(fileName); + + // assert + Assert.AreEqual("ed076287532e86365e841e92bfc50d8c", textHash); + Assert.AreEqual("2f249230a8e7c2bf6005ccd2679259ec", bytesHash); + Assert.AreEqual("ed076287532e86365e841e92bfc50d8c", fileHash); + } + + [TestMethod] + public void ShouldReturnSha1Hash() + { + // arrange + string text = "Hello World!"; + byte[] bytes = new byte[] { 0xde, 0xad, 0xbe, 0xef }; + string fileName = Path.GetTempFileName(); + + // act + string textHash = CryptographyHelper.Sha1(text); + string bytesHash = CryptographyHelper.Sha1(bytes); + + File.WriteAllText(fileName, text); + string fileHash = CryptographyHelper.Sha1File(fileName); + File.Delete(fileName); + + // assert + Assert.AreEqual("2ef7bde608ce5404e97d5f042f95f89f1c232871", textHash); + Assert.AreEqual("d78f8bb992a56a597f6c7a1fb918bb78271367eb", bytesHash); + Assert.AreEqual("2ef7bde608ce5404e97d5f042f95f89f1c232871", fileHash); + } + + [TestMethod] + public void ShouldReturnSha256Hash() + { + // arrange + string text = "Hello World!"; + byte[] bytes = new byte[] { 0xde, 0xad, 0xbe, 0xef }; + string fileName = Path.GetTempFileName(); + + // act + string textHash = CryptographyHelper.Sha256(text); + string bytesHash = CryptographyHelper.Sha256(bytes); + + File.WriteAllText(fileName, text); + string fileHash = CryptographyHelper.Sha256File(fileName); + File.Delete(fileName); + + // assert + Assert.AreEqual("7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069", textHash); + Assert.AreEqual("5f78c33274e43fa9de5659265c1d917e25c03722dcb0b8d27db8d5feaa813953", bytesHash); + Assert.AreEqual("7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069", fileHash); + } + + [TestMethod] + public void ShouldReturnSha512Hash() + { + // arrange + string text = "Hello World!"; + byte[] bytes = new byte[] { 0xde, 0xad, 0xbe, 0xef }; + string fileName = Path.GetTempFileName(); + + // act + string textHash = CryptographyHelper.Sha512(text); + string bytesHash = CryptographyHelper.Sha512(bytes); + + File.WriteAllText(fileName, text); + string fileHash = CryptographyHelper.Sha512File(fileName); + File.Delete(fileName); + + // assert + Assert.AreEqual("861844d6704e8573fec34d967e20bcfef3d424cf48be04e6dc08f2bd58c729743371015ead891cc3cf1c9d34b49264b510751b1ff9e537937bc46b5d6ff4ecc8", textHash); + Assert.AreEqual("1284b2d521535196f22175d5f558104220a6ad7680e78b49fa6f20e57ea7b185d71ec1edb137e70eba528dedb141f5d2f8bb53149d262932b27cf41fed96aa7f", bytesHash); + Assert.AreEqual("861844d6704e8573fec34d967e20bcfef3d424cf48be04e6dc08f2bd58c729743371015ead891cc3cf1c9d34b49264b510751b1ff9e537937bc46b5d6ff4ecc8", fileHash); + } + + #endregion Hash + + #region Random + + [TestMethod] + public void ShouldReturnRandomBytes() + { + // arrange + int length1 = 12; + int length2 = 12; + int length3 = 42; + + // act + byte[] bytes1 = CryptographyHelper.GetRandomBytes(length1); + byte[] bytes2 = CryptographyHelper.GetRandomBytes(length2); + byte[] bytes3 = CryptographyHelper.GetRandomBytes(length3); + + // assert + Assert.AreEqual(length1, bytes1.Length); + Assert.AreEqual(length2, bytes2.Length); + Assert.AreEqual(length3, bytes3.Length); + + Assert.IsTrue(bytes1.Length == bytes2.Length); + CollectionAssert.AreNotEqual(bytes1, bytes2); + } + + [TestMethod] + public void ShouldReturnRandomString() + { + // arrange + int length1 = 12; + int length2 = 12; + int length3 = 42; + + // act + string str1 = CryptographyHelper.GetRandomString(length1); + string str2 = CryptographyHelper.GetRandomString(length2); + string str3 = CryptographyHelper.GetRandomString(length3); + + // assert + Assert.AreEqual(length1, str1.Length); + Assert.AreEqual(length2, str2.Length); + Assert.AreEqual(length3, str3.Length); + + Assert.IsTrue(str1.Length == str2.Length); + Assert.IsFalse(str1 == str2); + } + + [TestMethod] + public void ShouldReturnRandomStringWithPool() + { + // arrange + int length = 12; + string pool = "0123456789abcdef"; + + // act + string str1 = CryptographyHelper.GetRandomString(length, pool); + string str2 = CryptographyHelper.GetRandomString(length, pool); + + // assert + Assert.AreEqual(length, str1.Length); + Assert.AreEqual(length, str2.Length); + Assert.IsFalse(str1 == str2); + Assert.IsFalse(Regex.IsMatch(str1, "[^0-9a-f]")); + Assert.IsFalse(Regex.IsMatch(str2, "[^0-9a-f]")); + } + + #endregion Random + + #region Secure probing + + [TestMethod] + public void ShouldTakeSameTimeToCompareString() + { + // arrange + string str1 = "Hello World!"; + string str2 = "Hello World!"; + string str3 = "Hallo World!"; + string str4 = "Hello World?"; + + var sw = new Stopwatch(); + + // act + sw.Start(); + bool compare1 = CryptographyHelper.SecureEquals(str1, str2); + long time1 = sw.ElapsedMilliseconds; + + bool compare2 = CryptographyHelper.SecureEquals(str1, str3); + long time2 = sw.ElapsedMilliseconds; + + bool compare3 = CryptographyHelper.SecureEquals(str1, str4); + long time3 = sw.ElapsedMilliseconds; + sw.Stop(); + + // assert + Assert.IsTrue(compare1); + Assert.IsFalse(compare2); + Assert.IsFalse(compare3); + // max. time delta: 2 ticks per character + Assert.AreEqual(time1, time2); + Assert.AreEqual(time1, time3); + Assert.AreEqual(time2, time3); + } + + [TestMethod] + public void ShouldTakeSameTimeToCompareBytes() + { + // arrange + byte[] bytes1 = CryptographyHelper.GetRandomBytes(200); + byte[] bytes2 = new byte[bytes1.Length]; + byte[] bytes3 = new byte[bytes1.Length]; + byte[] bytes4 = new byte[bytes1.Length]; + + Array.Copy(bytes1, bytes2, bytes1.Length); + Array.Copy(bytes1, bytes3, bytes1.Length); + Array.Copy(bytes1, bytes4, bytes1.Length); + + bytes3[10] = (byte)(bytes1[10] + 1); + bytes4[190] = (byte)(bytes1[190] + 1); + + var sw = new Stopwatch(); + + // act + sw.Start(); + bool compare1 = CryptographyHelper.SecureEquals(bytes1, bytes2); + long time1 = sw.ElapsedMilliseconds; + + bool compare2 = CryptographyHelper.SecureEquals(bytes1, bytes3); + long time2 = sw.ElapsedMilliseconds; + + bool compare3 = CryptographyHelper.SecureEquals(bytes1, bytes4); + long time3 = sw.ElapsedMilliseconds; + sw.Stop(); + + // assert + Assert.IsTrue(compare1); + Assert.IsFalse(compare2); + Assert.IsFalse(compare3); + // max. time delta: 2 ticks per byte + Assert.AreEqual(time1, time2); + Assert.AreEqual(time1, time3); + Assert.AreEqual(time2, time3); + } + + #endregion Secure probing + + #endregion Static + + #region Instance + + [TestMethod] + public void ShouldEncryptAesUsingKeyFile() + { + // arrange + string str = "Hello World!"; + byte[] bytes = CryptographyHelper.GetRandomBytes(32); + + string password = File.ReadAllText(keyFile); + + // act + string cipherStr = cryptoHelper.EncryptAes(str); + byte[] cipherBytes = cryptoHelper.EncryptAes(bytes); + + string plainStr = CryptographyHelper.AesDecrypt(cipherStr, password); + byte[] plainBytes = CryptographyHelper.AesDecrypt(cipherBytes, password); + + // assert + Assert.AreNotEqual(str, cipherStr); + Assert.AreEqual(str, plainStr); + CollectionAssert.AreNotEqual(bytes, cipherBytes); + CollectionAssert.AreEqual(bytes, plainBytes); + } + + [TestMethod] + public void ShouldDecryptAesUsingKeyFile() + { + // arrange + string str = "Hello World!"; + byte[] bytes = CryptographyHelper.GetRandomBytes(32); + + string password = File.ReadAllText(keyFile); + + // act + string cipherStr = CryptographyHelper.AesEncrypt(str, password); + byte[] cipherBytes = CryptographyHelper.AesEncrypt(bytes, password); + + string plainStr = cryptoHelper.DecryptAes(cipherStr); + byte[] plainBytes = cryptoHelper.DecryptAes(cipherBytes); + + // assert + Assert.AreNotEqual(str, cipherStr); + Assert.AreEqual(str, plainStr); + CollectionAssert.AreNotEqual(bytes, cipherBytes); + CollectionAssert.AreEqual(bytes, plainBytes); + } + + [TestMethod] + public void ShouldEncryptTdesUsingKeyFile() + { + // arrange + string str = "Hello World!"; + byte[] bytes = CryptographyHelper.GetRandomBytes(32); + + string password = File.ReadAllText(keyFile); + + // act + string cipherStr = cryptoHelper.EncryptTripleDes(str); + byte[] cipherBytes = cryptoHelper.EncryptTripleDes(bytes); + + string plainStr = CryptographyHelper.TripleDesDecrypt(cipherStr, password); + byte[] plainBytes = CryptographyHelper.TripleDesDecrypt(cipherBytes, password); + + // assert + Assert.AreNotEqual(str, cipherStr); + Assert.AreEqual(str, plainStr); + CollectionAssert.AreNotEqual(bytes, cipherBytes); + CollectionAssert.AreEqual(bytes, plainBytes); + } + + [TestMethod] + public void ShouldDecryptTdesUsingKeyFile() + { + // arrange + string str = "Hello World!"; + byte[] bytes = CryptographyHelper.GetRandomBytes(32); + + string password = File.ReadAllText(keyFile); + + // act + string cipherStr = CryptographyHelper.TripleDesEncrypt(str, password); + byte[] cipherBytes = CryptographyHelper.TripleDesEncrypt(bytes, password); + + string plainStr = cryptoHelper.DecryptTripleDes(cipherStr); + byte[] plainBytes = cryptoHelper.DecryptTripleDes(cipherBytes); + + // assert + Assert.AreNotEqual(str, cipherStr); + Assert.AreEqual(str, plainStr); + CollectionAssert.AreNotEqual(bytes, cipherBytes); + CollectionAssert.AreEqual(bytes, plainBytes); + } + + #endregion Instance + } +} diff --git a/AMWD.Common.Tests/Utilities/DelayedTaskTests.cs b/AMWD.Common.Tests/Utilities/DelayedTaskTests.cs new file mode 100644 index 0000000..ad61841 --- /dev/null +++ b/AMWD.Common.Tests/Utilities/DelayedTaskTests.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace AMWD.Common.Tests.Utilities +{ + [TestClass] + public class DelayedTaskTests + { + // TODO + } +} diff --git a/AMWD.Common.Tests/Utils/CryptographyHelperSaltMock.cs b/AMWD.Common.Tests/Utils/CryptographyHelperSaltMock.cs new file mode 100644 index 0000000..e59c6b9 --- /dev/null +++ b/AMWD.Common.Tests/Utils/CryptographyHelperSaltMock.cs @@ -0,0 +1,27 @@ +using System; +using System.Security.Cryptography; +using ReflectionMagic; + +namespace AMWD.Common.Tests.Utils +{ + [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + internal class CryptographyHelperSaltMock : IDisposable + { + private readonly int saltLength; + + private CryptographyHelperSaltMock(int saltLength) + { + this.saltLength = typeof(CryptographyHelper).AsDynamicType().saltLength; + SetSaltLength(saltLength); + } + + public static IDisposable Create(int saltLength) + => new CryptographyHelperSaltMock(saltLength); + + public void Dispose() + => SetSaltLength(saltLength); + + private static void SetSaltLength(int length) + => typeof(CryptographyHelper).AsDynamicType().saltLength = length; + } +} diff --git a/AMWD.Common.Tests/Utils/TimeZoneInfoLocalMock.cs b/AMWD.Common.Tests/Utils/TimeZoneInfoLocalMock.cs index 1b6d5a9..ff14a14 100644 --- a/AMWD.Common.Tests/Utils/TimeZoneInfoLocalMock.cs +++ b/AMWD.Common.Tests/Utils/TimeZoneInfoLocalMock.cs @@ -4,7 +4,7 @@ using ReflectionMagic; namespace AMWD.Common.Tests.Utils { [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - public class TimeZoneInfoLocalMock : IDisposable + internal class TimeZoneInfoLocalMock : IDisposable { private readonly TimeZoneInfo localTimeZoneInfo; diff --git a/AMWD.Common/Utilities/CryptographyHelper.cs b/AMWD.Common/Utilities/CryptographyHelper.cs index 71a83c7..f5bab86 100644 --- a/AMWD.Common/Utilities/CryptographyHelper.cs +++ b/AMWD.Common/Utilities/CryptographyHelper.cs @@ -9,7 +9,7 @@ namespace System.Security.Cryptography /// public class CryptographyHelper { - private static readonly int saltLength = 8; + private static int saltLength = 8; private readonly string masterKeyFile; @@ -206,6 +206,19 @@ namespace System.Security.Cryptography return ms.ToArray(); } + /// + /// Decrypts a Base64 string using the AES algorithm and a password to an UTF-8 string. + /// + /// The encrypted Base64 encoded string. + /// The password to use for decryption. + /// The decrypted UTF-8 string string. + public static string AesDecrypt(string cipherStr, string password) + { + byte[] cipher = Convert.FromBase64String(cipherStr); + byte[] plain = AesDecrypt(cipher, password); + return Encoding.UTF8.GetString(plain); + } + /// /// Encrypts data using the AES algorithm and a password. /// @@ -234,19 +247,6 @@ namespace System.Security.Cryptography return ms.ToArray(); } - /// - /// Decrypts a Base64 string using the AES algorithm and a password to an UTF-8 string. - /// - /// The encrypted Base64 encoded string. - /// The password to use for decryption. - /// The decrypted UTF-8 string string. - public static string AesDecrypt(string cipherStr, string password) - { - byte[] cipher = Convert.FromBase64String(cipherStr); - byte[] plain = AesDecrypt(cipher, password); - return Encoding.UTF8.GetString(plain); - } - /// /// Encrypts an UTF-8 string using the AES algorithm and a password to a Base64 string. /// @@ -543,29 +543,7 @@ namespace System.Security.Cryptography #endregion Random - #region Probing security - - /// - /// Determines whether two strings are equal in constant time. This method does not stop - /// early if a difference was detected, unless the length differs. - /// - /// The first string. - /// The second string. - /// true, if both strings are equal; otherwise, false. - public static bool SecureEquals(string a, string b) - { - if ((a == null) != (b == null)) - return false; - if (a.Length != b.Length) - return false; - - int differentBits = 0; - for (int i = 0; i < a.Length; i++) - { - differentBits |= a[i] ^ b[i]; - } - return differentBits == 0; - } + #region Secure probing /// /// Determines whether two byte arrays are equal in constant time. This method does not stop @@ -589,7 +567,29 @@ namespace System.Security.Cryptography return differentBits == 0; } - #endregion Probing security + /// + /// Determines whether two strings are equal in constant time. This method does not stop + /// early if a difference was detected, unless the length differs. + /// + /// The first string. + /// The second string. + /// true, if both strings are equal; otherwise, false. + public static bool SecureEquals(string a, string b) + { + if ((a == null) != (b == null)) + return false; + if (a.Length != b.Length) + return false; + + int differentBits = 0; + for (int i = 0; i < a.Length; i++) + { + differentBits |= a[i] ^ b[i]; + } + return differentBits == 0; + } + + #endregion Secure probing #endregion Static methods } diff --git a/AMWD.Common/Utilities/DelayedTask.cs b/AMWD.Common/Utilities/DelayedTask.cs index 8d20124..6fca87d 100644 --- a/AMWD.Common/Utilities/DelayedTask.cs +++ b/AMWD.Common/Utilities/DelayedTask.cs @@ -22,7 +22,7 @@ namespace AMWD.Common.Utilities /// /// The synchronisation object. /// - protected readonly object syncObj = new(); + protected readonly object syncLock = new(); /// /// The exception handler. @@ -122,7 +122,7 @@ namespace AMWD.Common.Utilities /// public void Reset() { - lock (syncObj) + lock (syncLock) { if (!IsWaitingToRun && !IsRunning) { @@ -149,7 +149,7 @@ namespace AMWD.Common.Utilities public void Cancel() { TaskCompletionSourceWrapper localTcs = null; - lock (syncObj) + lock (syncLock) { IsWaitingToRun = false; nextRunPending = false; @@ -172,7 +172,7 @@ namespace AMWD.Common.Utilities /// true, if an execution was started; otherwise, false. public bool ExecutePending() { - lock (syncObj) + lock (syncLock) { if (!IsWaitingToRun && !IsRunning) { @@ -197,7 +197,7 @@ namespace AMWD.Common.Utilities /// An awaiter instance. public TaskAwaiter GetAwaiter() { - lock (syncObj) + lock (syncLock) { return tcs.Task.GetAwaiter(); } @@ -211,7 +211,7 @@ namespace AMWD.Common.Utilities { get { - lock (syncObj) + lock (syncLock) { return tcs.Task; } @@ -273,7 +273,7 @@ namespace AMWD.Common.Utilities /// Unused. protected void OnTimerCallback(object state) { - lock (syncObj) + lock (syncLock) { if (!IsWaitingToRun) { @@ -304,7 +304,7 @@ namespace AMWD.Common.Utilities catch (Exception ex) { exception = ex; - lock (syncObj) + lock (syncLock) { runAgain = false; IsRunning = false; @@ -320,7 +320,7 @@ namespace AMWD.Common.Utilities } finally { - lock (syncObj) + lock (syncLock) { runAgain = nextRunPending; IsRunning = runAgain; @@ -484,7 +484,7 @@ namespace AMWD.Common.Utilities /// An awaiter instance. public new TaskAwaiter GetAwaiter() { - lock (syncObj) + lock (syncLock) { var myTcs = (TaskCompletionSourceWrapper)tcs; var myTask = (Task)myTcs.Task; @@ -499,7 +499,7 @@ namespace AMWD.Common.Utilities { get { - lock (syncObj) + lock (syncLock) { var myTcs = (TaskCompletionSourceWrapper)tcs; var myTask = (Task)myTcs.Task; diff --git a/AMWD.Common/Utilities/NetworkHelper.cs b/AMWD.Common/Utilities/NetworkHelper.cs index 8896468..b52f1d7 100644 --- a/AMWD.Common/Utilities/NetworkHelper.cs +++ b/AMWD.Common/Utilities/NetworkHelper.cs @@ -10,6 +10,7 @@ namespace AMWD.Common.Utilities /// /// Provides some network utils. /// + [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public static class NetworkHelper { /// @@ -49,7 +50,6 @@ namespace AMWD.Common.Utilities /// The interface name to resolve. /// An address family to use (available: and ). /// The resolved es or an empty list. - [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] // not possible to define interfaces on unit tests public static List ResolveInterface(string interfaceName, AddressFamily addressFamily = default) { if (string.IsNullOrWhiteSpace(interfaceName))