@@ -256,24 +256,116 @@ public string GetDigest()
256256
257257 public override string ToString ( )
258258 {
259- string authHeader = AuthHeaders . AUTH_DIGEST_KEY + " " ;
260-
261- authHeader += ( Username != null && Username . Trim ( ) . Length != 0 ) ? AuthHeaders . AUTH_USERNAME_KEY + "=\" " + Username + "\" " : null ;
262- authHeader += ( authHeader . IndexOf ( '=' ) != - 1 ) ? "," + AuthHeaders . AUTH_REALM_KEY + "=\" " + Realm + "\" " : AuthHeaders . AUTH_REALM_KEY + "=\" " + Realm + "\" " ;
263- authHeader += ( Nonce != null ) ? "," + AuthHeaders . AUTH_NONCE_KEY + "=\" " + Nonce + "\" " : null ;
264- authHeader += ( URI != null && URI . Trim ( ) . Length != 0 ) ? "," + AuthHeaders . AUTH_URI_KEY + "=\" " + URI + "\" " : null ;
265- authHeader += ( Response != null && Response . Length != 0 ) ? "," + AuthHeaders . AUTH_RESPONSE_KEY + "=\" " + Response + "\" " : null ;
266- authHeader += ( Cnonce != null ) ? "," + AuthHeaders . AUTH_CNONCE_KEY + "=\" " + Cnonce + "\" " : null ;
267- authHeader += ( NonceCount != 0 ) ? "," + AuthHeaders . AUTH_NONCECOUNT_KEY + "=" + GetPaddedNonceCount ( NonceCount ) : null ;
268- authHeader += ( Qop != null ) ? "," + AuthHeaders . AUTH_QOP_KEY + "=" + Qop : null ;
269- authHeader += ( Opaque != null ) ? "," + AuthHeaders . AUTH_OPAQUE_KEY + "=\" " + Opaque + "\" " : null ;
270-
271- string algorithmID = ( DigestAlgorithm == DigestAlgorithmsEnum . SHA256 ) ? SHA256_ALGORITHM_ID : DigestAlgorithm . ToString ( ) ;
272- authHeader += ( Response != null ) ? "," + AuthHeaders . AUTH_ALGORITHM_KEY + "=" + algorithmID : null ;
273-
274- return authHeader ;
259+ var builder = new ValueStringBuilder ( ) ;
260+
261+ try
262+ {
263+ ToString ( ref builder ) ;
264+
265+ return builder . ToString ( ) ;
266+ }
267+ finally
268+ {
269+ builder . Dispose ( ) ;
270+ }
271+ }
272+
273+ internal void ToString ( ref ValueStringBuilder builder )
274+ {
275+ builder . Append ( AuthHeaders . AUTH_DIGEST_KEY ) ;
276+ builder . Append ( ' ' ) ;
277+
278+ bool hasUsername = ! string . IsNullOrWhiteSpace ( Username ) ;
279+ if ( hasUsername )
280+ {
281+ builder . Append ( AuthHeaders . AUTH_USERNAME_KEY ) ;
282+ builder . Append ( "=\" " ) ;
283+ builder . Append ( Username ) ;
284+ builder . Append ( '"' ) ;
285+ }
286+
287+ builder . Append ( hasUsername ? ',' : '\0 ' ) ;
288+ builder . Append ( AuthHeaders . AUTH_REALM_KEY ) ;
289+ builder . Append ( "=\" " ) ;
290+ builder . Append ( Realm ) ;
291+ builder . Append ( '"' ) ;
292+
293+ if ( Nonce != null )
294+ {
295+ builder . Append ( ',' ) ;
296+ builder . Append ( AuthHeaders . AUTH_NONCE_KEY ) ;
297+ builder . Append ( "=\" " ) ;
298+ builder . Append ( Nonce ) ;
299+ builder . Append ( '"' ) ;
300+ }
301+
302+ if ( ! string . IsNullOrWhiteSpace ( URI ) )
303+ {
304+ builder . Append ( ',' ) ;
305+ builder . Append ( AuthHeaders . AUTH_URI_KEY ) ;
306+ builder . Append ( "=\" " ) ;
307+ builder . Append ( URI ) ;
308+ builder . Append ( '"' ) ;
309+ }
310+
311+ if ( ! string . IsNullOrEmpty ( Response ) )
312+ {
313+ builder . Append ( ',' ) ;
314+ builder . Append ( AuthHeaders . AUTH_RESPONSE_KEY ) ;
315+ builder . Append ( "=\" " ) ;
316+ builder . Append ( Response ) ;
317+ builder . Append ( '"' ) ;
318+ }
319+
320+ if ( Cnonce != null )
321+ {
322+ builder . Append ( ',' ) ;
323+ builder . Append ( AuthHeaders . AUTH_CNONCE_KEY ) ;
324+ builder . Append ( "=\" " ) ;
325+ builder . Append ( Cnonce ) ;
326+ builder . Append ( '"' ) ;
327+ }
328+
329+ if ( NonceCount != 0 )
330+ {
331+ builder . Append ( ',' ) ;
332+ builder . Append ( AuthHeaders . AUTH_NONCECOUNT_KEY ) ;
333+ builder . Append ( '=' ) ;
334+ builder . Append ( GetPaddedNonceCount ( NonceCount ) ) ;
335+ }
336+
337+ if ( Qop != null )
338+ {
339+ builder . Append ( ',' ) ;
340+ builder . Append ( AuthHeaders . AUTH_QOP_KEY ) ;
341+ builder . Append ( '=' ) ;
342+ builder . Append ( Qop ) ;
343+ }
344+
345+ if ( Opaque != null )
346+ {
347+ builder . Append ( ',' ) ;
348+ builder . Append ( AuthHeaders . AUTH_OPAQUE_KEY ) ;
349+ builder . Append ( "=\" " ) ;
350+ builder . Append ( Opaque ) ;
351+ builder . Append ( '"' ) ;
352+ }
353+
354+ if ( Response != null )
355+ {
356+ builder . Append ( ',' ) ;
357+ builder . Append ( AuthHeaders . AUTH_ALGORITHM_KEY ) ;
358+ builder . Append ( '=' ) ;
359+
360+ string algorithmID = ( DigestAlgorithm == DigestAlgorithmsEnum . SHA256 )
361+ ? SHA256_ALGORITHM_ID
362+ : DigestAlgorithm . ToString ( ) ;
363+
364+ builder . Append ( algorithmID ) ;
365+ }
275366 }
276367
368+
277369 public SIPAuthorisationDigest CopyOf ( )
278370 {
279371 var copy = new SIPAuthorisationDigest ( AuthorisationType , Realm , Username , Password , URI , Nonce , RequestType , DigestAlgorithm ) ;
@@ -385,21 +477,21 @@ public static string GetHashHex(DigestAlgorithmsEnum hashAlg, string val)
385477 case DigestAlgorithmsEnum . SHA256 :
386478 using ( var hash = new SHA256CryptoServiceProvider ( ) )
387479 {
388- return hash . ComputeHash ( Encoding . UTF8 . GetBytes ( val ) ) . HexStr ( ) . ToLower ( ) ;
480+ return hash . ComputeHash ( Encoding . UTF8 . GetBytes ( val ) ) . AsSpan ( ) . HexStr ( lowercase : true ) ;
389481 }
390482 // This is commented because RFC8760 does not have an SHA-512 option. Instead it's HSA-512-sess which
391483 // means the SIP request body needs to be included in the digest as well. Including the body will require
392484 // some additional changes that can be done at a later date.
393485 //case DigestAlgorithmsEnum.SHA512:
394486 // using (var hash = new SHA512CryptoServiceProvider())
395487 // {
396- // return hash.ComputeHash(Encoding.UTF8.GetBytes(val)).HexStr().ToLower( );
488+ // return hash.ComputeHash(Encoding.UTF8.GetBytes(val)).HexStr(lowercase: false );
397489 // }
398490 case DigestAlgorithmsEnum . MD5 :
399491 default :
400492 using ( var hash = new MD5CryptoServiceProvider ( ) )
401493 {
402- return hash . ComputeHash ( Encoding . UTF8 . GetBytes ( val ) ) . HexStr ( ) . ToLower ( ) ;
494+ return hash . ComputeHash ( Encoding . UTF8 . GetBytes ( val ) ) . AsSpan ( ) . HexStr ( lowercase : true ) ;
403495 }
404496 }
405497#pragma warning restore SYSLIB0021
0 commit comments