Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit a3c0e95

Browse files
committed
Improve perf of ToHexStringUpper and DecodeHexString
Reduces allocations and improves throughput.
1 parent 40b1f93 commit a3c0e95

File tree

2 files changed

+40
-39
lines changed
  • src/System.Security.Cryptography.X509Certificates/src

2 files changed

+40
-39
lines changed

src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Helpers.cs

Lines changed: 36 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

44
using System;
5-
using System.Text;
65
using System.Diagnostics;
76
using System.Globalization;
8-
using System.Security.Cryptography;
97

108
namespace Internal.Cryptography
119
{
@@ -16,59 +14,54 @@ public static byte[] CloneByteArray(this byte[] src)
1614
return (byte[])(src.Clone());
1715
}
1816

19-
// Encode a byte array as an upper case hex string.
20-
public static String ToHexStringUpper(this byte[] bytes)
17+
// Encode a byte array as an array of upper-case hex characters.
18+
public static char[] ToHexArrayUpper(this byte[] bytes)
2119
{
22-
StringBuilder sb = new StringBuilder(bytes.Length * 2);
20+
char[] chars = new char[bytes.Length * 2];
21+
int i = 0;
2322
foreach (byte b in bytes)
2423
{
25-
sb.AppendFormat("{0:X2}", b);
24+
chars[i++] = NibbleToHex((byte)(b >> 4));
25+
chars[i++] = NibbleToHex((byte)(b & 0xF));
2626
}
27-
return sb.ToString();
27+
return chars;
28+
}
29+
30+
// Encode a byte array as an upper case hex string.
31+
public static string ToHexStringUpper(this byte[] bytes)
32+
{
33+
return new string(ToHexArrayUpper(bytes));
2834
}
2935

3036
// Decode a hex string-encoded byte array passed to various X509 crypto api. The parsing rules are overly forgiving but for compat reasons,
3137
// they cannot be tightened.
3238
public static byte[] DecodeHexString(this String s)
3339
{
34-
String hexString = DiscardWhiteSpaces(s);
35-
uint cbHex = (uint)hexString.Length / 2;
36-
byte[] hex = new byte[cbHex];
37-
int i = 0;
38-
for (int index = 0; index < cbHex; index++)
40+
int whitespaceCount = 0;
41+
42+
for (int i = 0; i < s.Length; i++)
3943
{
40-
hex[index] = (byte)((HexToByte(hexString[i]) << 4) | HexToByte(hexString[i + 1]));
41-
i += 2;
44+
if (Char.IsWhiteSpace(s[i]))
45+
whitespaceCount++;
4246
}
43-
return hex;
44-
}
4547

46-
private static String DiscardWhiteSpaces(String inputBuffer)
47-
{
48-
return DiscardWhiteSpaces(inputBuffer, 0, inputBuffer.Length);
49-
}
48+
uint cbHex = (uint)(s.Length - whitespaceCount) / 2;
49+
byte[] hex = new byte[cbHex];
5050

51-
private static String DiscardWhiteSpaces(String inputBuffer, int inputOffset, int inputCount)
52-
{
53-
int i, iCount = 0;
54-
for (i = 0; i < inputCount; i++)
51+
for (int index = 0, i = 0; index < cbHex; index++)
5552
{
56-
if (Char.IsWhiteSpace(inputBuffer[inputOffset + i]))
53+
if (Char.IsWhiteSpace(s[i]))
5754
{
58-
iCount++;
55+
i++;
5956
}
60-
}
61-
62-
char[] rgbOut = new char[inputCount - iCount];
63-
iCount = 0;
64-
for (i = 0; i < inputCount; i++)
65-
{
66-
if (!Char.IsWhiteSpace(inputBuffer[inputOffset + i]))
57+
else
6758
{
68-
rgbOut[iCount++] = inputBuffer[inputOffset + i];
59+
hex[index] = (byte)((HexToByte(s[i]) << 4) | HexToByte(s[i + 1]));
60+
i += 2;
6961
}
7062
}
71-
return new String(rgbOut);
63+
64+
return hex;
7265
}
7366

7467
private static byte HexToByte(char val)
@@ -83,6 +76,14 @@ private static byte HexToByte(char val)
8376
return 0xFF;
8477
}
8578

79+
private static char NibbleToHex(byte b)
80+
{
81+
Debug.Assert(b >= 0 && b <= 15);
82+
return (char)(b >= 0 && b <= 9 ?
83+
'0' + b :
84+
'A' + (b - 10));
85+
}
86+
8687
public static bool ContentsEqual(this byte[] a1, byte[] a2)
8788
{
8889
if (a1.Length != a2.Length)
@@ -115,5 +116,3 @@ private static bool IsValidYear(this Calendar calendar, int year, int era)
115116
}
116117
}
117118
}
118-
119-

src/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/X509Certificate.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,8 @@ public virtual String ToString(bool fVerbose)
278278
sb.Append(" ");
279279
byte[] serialNumber = this.GetSerialNumber();
280280
Array.Reverse(serialNumber);
281-
sb.AppendLine(serialNumber.ToHexStringUpper());
281+
sb.Append(serialNumber.ToHexArrayUpper());
282+
sb.AppendLine();
282283

283284
// NotBefore
284285
sb.AppendLine();
@@ -296,7 +297,8 @@ public virtual String ToString(bool fVerbose)
296297
sb.AppendLine();
297298
sb.AppendLine("[Thumbprint]");
298299
sb.Append(" ");
299-
sb.AppendLine(this.GetCertHash().ToHexStringUpper());
300+
sb.Append(this.GetCertHash().ToHexArrayUpper());
301+
sb.AppendLine();
300302

301303
return sb.ToString();
302304
}

0 commit comments

Comments
 (0)