diff --git a/src/ConfigCatClient/Evaluation/RolloutEvaluator.cs b/src/ConfigCatClient/Evaluation/RolloutEvaluator.cs index ea53e7db..1053b502 100644 --- a/src/ConfigCatClient/Evaluation/RolloutEvaluator.cs +++ b/src/ConfigCatClient/Evaluation/RolloutEvaluator.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; +using System.Text; using ConfigCat.Client.Utils; using ConfigCat.Client.Versioning; @@ -475,7 +476,7 @@ private static bool EvaluateSensitiveTextEquals(string text, string? comparisonV { EnsureComparisonValue(comparisonValue); - var hash = HashComparisonValue(text.AsSpan(), configJsonSalt, contextSalt); + var hash = HashComparisonValue(text, configJsonSalt, contextSalt); return hash.Equals(hexString: comparisonValue.AsSpan()) ^ negate; } @@ -499,7 +500,7 @@ private static bool EvaluateSensitiveIsOneOf(string text, string[]? comparisonVa { EnsureComparisonValue(comparisonValues); - var hash = HashComparisonValue(text.AsSpan(), configJsonSalt, contextSalt); + var hash = HashComparisonValue(text, configJsonSalt, contextSalt); for (var i = 0; i < comparisonValues.Length; i++) { @@ -540,6 +541,8 @@ private static bool EvaluateSensitiveTextSliceEqualsAnyOf(string text, string[]? { EnsureComparisonValue(comparisonValues); + var textUtf8Bytes = Encoding.UTF8.GetBytes(text); + for (var i = 0; i < comparisonValues.Length; i++) { var item = EnsureComparisonValue(comparisonValues[i]); @@ -555,12 +558,12 @@ private static bool EvaluateSensitiveTextSliceEqualsAnyOf(string text, string[]? break; // execution should never get here (this is just for keeping the compiler happy) } - if (text.Length < sliceLength) + if (textUtf8Bytes.Length < sliceLength) { continue; } - var slice = startsWith ? text.AsSpan(0, sliceLength) : text.AsSpan(text.Length - sliceLength); + var slice = startsWith ? textUtf8Bytes.AsSpan(0, sliceLength) : textUtf8Bytes.AsSpan(textUtf8Bytes.Length - sliceLength); var hash = HashComparisonValue(slice, configJsonSalt, contextSalt); if (hash.Equals(hexString: hash2)) @@ -693,7 +696,7 @@ private static bool EvaluateSensitiveArrayContainsAnyOf(string[] array, string[] for (var i = 0; i < array.Length; i++) { - var hash = HashComparisonValue(array[i].AsSpan(), configJsonSalt, contextSalt); + var hash = HashComparisonValue(array[i], configJsonSalt, contextSalt); for (var j = 0; j < comparisonValues.Length; j++) { @@ -822,9 +825,32 @@ private bool EvaluateSegmentCondition(SegmentCondition condition, ref EvaluateCo return result; } - private static byte[] HashComparisonValue(ReadOnlySpan value, string configJsonSalt, string contextSalt) + private static byte[] HashComparisonValue(ReadOnlySpan value, string configJsonSalt, string contextSalt) + { + var valueLength = value.Length; + var configJsonSaltLength = Encoding.UTF8.GetByteCount(configJsonSalt); + var contextSaltLength = Encoding.UTF8.GetByteCount(contextSalt); + var bytes = new byte[valueLength + configJsonSaltLength + contextSaltLength]; + + value.CopyTo(bytes); + Encoding.UTF8.GetBytes(configJsonSalt, 0, configJsonSalt.Length, bytes, valueLength); + Encoding.UTF8.GetBytes(contextSalt, 0, contextSalt.Length, bytes, valueLength + configJsonSaltLength); + + return bytes.Sha256(); + } + + private static byte[] HashComparisonValue(string value, string configJsonSalt, string contextSalt) { - return string.Concat(value.ToConcatenable(), configJsonSalt, contextSalt).Sha256(); + var valueLength = Encoding.UTF8.GetByteCount(value); + var configJsonSaltLength = Encoding.UTF8.GetByteCount(configJsonSalt); + var contextSaltLength = Encoding.UTF8.GetByteCount(contextSalt); + var bytes = new byte[valueLength + configJsonSaltLength + contextSaltLength]; + + Encoding.UTF8.GetBytes(value, 0, valueLength, bytes, 0); + Encoding.UTF8.GetBytes(configJsonSalt, 0, configJsonSalt.Length, bytes, valueLength); + Encoding.UTF8.GetBytes(contextSalt, 0, contextSalt.Length, bytes, valueLength + configJsonSaltLength); + + return bytes.Sha256(); } private static string EnsureConfigJsonSalt([NotNull] string? value) diff --git a/src/ConfigCatClient/Extensions/StringExtensions.cs b/src/ConfigCatClient/Extensions/StringExtensions.cs index 56f43ac7..27bc2461 100644 --- a/src/ConfigCatClient/Extensions/StringExtensions.cs +++ b/src/ConfigCatClient/Extensions/StringExtensions.cs @@ -16,29 +16,13 @@ public static byte[] Sha1(this string text) #endif } - public static byte[] Sha256(this string text) + public static byte[] Sha256(this byte[] bytes) { - var textBytes = Encoding.UTF8.GetBytes(text); #if NET5_0_OR_GREATER - return SHA256.HashData(textBytes); + return SHA256.HashData(bytes); #else using var hash = SHA256.Create(); - return hash.ComputeHash(textBytes); -#endif - } - - public static -#if NET5_0_OR_GREATER - ReadOnlySpan -#else - string -#endif - ToConcatenable(this ReadOnlySpan s) - { -#if NET5_0_OR_GREATER - return s; -#else - return s.ToString(); + return hash.ComputeHash(bytes); #endif }