diff --git a/sdk/src/Core/AWSSDK.Core.NetStandard.csproj b/sdk/src/Core/AWSSDK.Core.NetStandard.csproj
index bddc592d5927..52b3ad551421 100644
--- a/sdk/src/Core/AWSSDK.Core.NetStandard.csproj
+++ b/sdk/src/Core/AWSSDK.Core.NetStandard.csproj
@@ -20,13 +20,10 @@
false
false
+ 9.0
$(NoWarn);CS1591;CA1822
true
True
-
-
-
- 8.0
IL2026,IL2075
diff --git a/sdk/src/Core/Amazon.Util/AWSSDKUtils.cs b/sdk/src/Core/Amazon.Util/AWSSDKUtils.cs
index 085946236e33..231c708d13b9 100644
--- a/sdk/src/Core/Amazon.Util/AWSSDKUtils.cs
+++ b/sdk/src/Core/Amazon.Util/AWSSDKUtils.cs
@@ -20,6 +20,7 @@
using Amazon.Runtime.Internal.Util;
using System;
+using System.Buffers;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
@@ -755,14 +756,32 @@ public static long ConvertTimeSpanToMilliseconds(TimeSpan timeSpan)
/// String version of the data
public static string ToHex(byte[] data, bool lowercase)
{
- StringBuilder sb = new StringBuilder();
-
- for (int i = 0; i < data.Length; i++)
+#if NET8_0_OR_GREATER
+ if (!lowercase)
{
- sb.Append(data[i].ToString(lowercase ? "x2" : "X2", CultureInfo.InvariantCulture));
+ return Convert.ToHexString(data);
}
+#endif
- return sb.ToString();
+#if NETCOREAPP3_1_OR_GREATER
+ return string.Create(data.Length * 2, (data, lowercase), static (chars, state) =>
+ {
+ ToHexString(state.data, chars, state.lowercase);
+ });
+#else
+ char[] chars = ArrayPool.Shared.Rent(data.Length * 2);
+
+ try
+ {
+ ToHexString(data, chars, lowercase);
+
+ return new string(chars, 0, data.Length * 2);
+ }
+ finally
+ {
+ ArrayPool.Shared.Return(chars);
+ }
+#endif
}
///
@@ -1144,6 +1163,23 @@ public static string UrlEncode(int rfcNumber, string data, bool path)
return encoded.ToString();
}
+ private static void ToHexString(Span source, Span destination, bool lowercase)
+ {
+ Func converter = lowercase ? (Func)ToLowerHex : (Func)ToUpperHex;
+
+ for (int i = source.Length - 1; i >= 0; i--)
+ {
+ // Break apart the byte into two four-bit components and
+ // then convert each into their hexadecimal equivalent.
+ byte b = source[i];
+ int hiNibble = b >> 4;
+ int loNibble = b & 0xF;
+
+ destination[i * 2] = converter(hiNibble);
+ destination[i * 2 + 1] = converter(loNibble);
+ }
+ }
+
private static char ToUpperHex(int value)
{
// Maps 0-9 to the Unicode range of '0' - '9' (0x30 - 0x39).
@@ -1154,7 +1190,18 @@ private static char ToUpperHex(int value)
// Maps 10-15 to the Unicode range of 'A' - 'F' (0x41 - 0x46).
return (char)(value - 10 + 'A');
}
-
+
+ private static char ToLowerHex(int value)
+ {
+ // Maps 0-9 to the Unicode range of '0' - '9' (0x30 - 0x39).
+ if (value <= 9)
+ {
+ return (char)(value + '0');
+ }
+ // Maps 10-15 to the Unicode range of 'a' - 'f' (0x61 - 0x66).
+ return (char)(value - 10 + 'a');
+ }
+
internal static string UrlEncodeSlash(string data)
{
if (string.IsNullOrEmpty(data))
@@ -1311,18 +1358,6 @@ public static void Sleep(TimeSpan ts)
Sleep((int)ts.TotalMilliseconds);
}
- ///
- /// Convert bytes to a hex string
- ///
- /// Bytes to convert.
- /// Hexadecimal string representing the byte array.
- public static string BytesToHexString(byte[] value)
- {
- string hex = BitConverter.ToString(value);
- hex = hex.Replace("-", string.Empty);
- return hex;
- }
-
///
/// Convert a hex string to bytes
///
diff --git a/sdk/src/Services/S3/Custom/Internal/AmazonS3ResponseHandler.cs b/sdk/src/Services/S3/Custom/Internal/AmazonS3ResponseHandler.cs
index b9d517ea88cc..d6fa9dcd0c22 100644
--- a/sdk/src/Services/S3/Custom/Internal/AmazonS3ResponseHandler.cs
+++ b/sdk/src/Services/S3/Custom/Internal/AmazonS3ResponseHandler.cs
@@ -191,8 +191,8 @@ private static void CompareHashes(string etag, byte[] hash)
return;
etag = etag.Trim(etagTrimChars);
-
- string hexHash = AWSSDKUtils.BytesToHexString(hash);
+
+ string hexHash = AWSSDKUtils.ToHex(hash, false);
if (!string.Equals(etag, hexHash, StringComparison.OrdinalIgnoreCase))
throw new AmazonClientException("Expected hash not equal to calculated hash");
}
diff --git a/sdk/test/NetStandard/UnitTests/AWSSDK.UnitTests.Custom.NetStandard.csproj b/sdk/test/NetStandard/UnitTests/AWSSDK.UnitTests.Custom.NetStandard.csproj
index 7904f350479b..9cf3acac6a13 100644
--- a/sdk/test/NetStandard/UnitTests/AWSSDK.UnitTests.Custom.NetStandard.csproj
+++ b/sdk/test/NetStandard/UnitTests/AWSSDK.UnitTests.Custom.NetStandard.csproj
@@ -23,10 +23,10 @@ This project file should not be used as part of a release pipeline.
false
false
+ 9.0
CS1591,CS0612,CS0618,NU1701
- true
+ true
true
- 8.0
diff --git a/sdk/test/NetStandard/UnitTests/Core/AWSSDKUtilsTests.cs b/sdk/test/NetStandard/UnitTests/Core/AWSSDKUtilsTests.cs
new file mode 100644
index 000000000000..c7e5574664b4
--- /dev/null
+++ b/sdk/test/NetStandard/UnitTests/Core/AWSSDKUtilsTests.cs
@@ -0,0 +1,28 @@
+using Amazon.Util;
+using System.Text;
+using Xunit;
+
+namespace UnitTests.NetStandard.Core
+{
+ [Trait("Category", "Core")]
+ public class AWSSDKUtilsTests
+ {
+ [Fact]
+ public void ToHexUppercase()
+ {
+ var bytes = Encoding.UTF8.GetBytes("Hello World");
+ var hexString = AWSSDKUtils.ToHex(bytes, false);
+
+ Assert.Equal("48656C6C6F20576F726C64", hexString);
+ }
+
+ [Fact]
+ public void ToHexLowercase()
+ {
+ var bytes = Encoding.UTF8.GetBytes("Hello World");
+ var hexString = AWSSDKUtils.ToHex(bytes, true);
+
+ Assert.Equal("48656c6c6f20576f726c64", hexString);
+ }
+ }
+}
diff --git a/sdk/test/UnitTests/Custom/Util/AWSSDKUtilsTests.cs b/sdk/test/UnitTests/Custom/Util/AWSSDKUtilsTests.cs
index 14201fab0e96..d81f11cc2b45 100644
--- a/sdk/test/UnitTests/Custom/Util/AWSSDKUtilsTests.cs
+++ b/sdk/test/UnitTests/Custom/Util/AWSSDKUtilsTests.cs
@@ -19,6 +19,7 @@
using System.Reflection;
using Moq;
using Amazon.Util.Internal;
+using System.Text;
namespace AWSSDK.UnitTests
{
@@ -164,5 +165,18 @@ public void ConvertFromUnixEpochMilliseconds()
Assert.AreEqual(expectedDateTime, dateTime);
}
+
+ [TestCategory("UnitTest")]
+ [TestCategory("Util")]
+ [DataRow("Hello World", true, "48656c6c6f20576f726c64")]
+ [DataRow("Hello World", false, "48656C6C6F20576F726C64")]
+ [DataTestMethod]
+ public void ToHex(string input, bool lowercase, string expectedResult)
+ {
+ var bytes = Encoding.UTF8.GetBytes(input);
+ var hexString = AWSSDKUtils.ToHex(bytes, lowercase);
+
+ Assert.AreEqual(expectedResult, hexString);
+ }
}
}