11using System ;
22using System . Text ;
3- using System . Collections . Generic ;
3+ using System . Globalization ;
44using System . Security . Cryptography ;
5- using Newtonsoft . Json ;
65using Org . BouncyCastle . Math ;
76using Org . BouncyCastle . Crypto . Parameters ;
87using Org . BouncyCastle . Crypto . Signers ;
@@ -42,29 +41,29 @@ internal WebPushSchemeHeadersValues(string authenticationHeaderValueParameter, s
4241
4342 #region Fields
4443 private const string URI_SCHEME_HTTPS = "https" ;
45- private const string AUDIENCE_CLAIM = "aud" ;
46- private const string EXPIRATION_CLAIM = "exp" ;
47- private const string SUBJECT_CLAIM = "sub" ;
48- private const char JWT_SEPARATOR = '.' ;
49-
50- private const string P256ECDSA_PREFIX = "p256ecdsa=" ;
51- private const string VAPID_AUTHENTICATION_HEADER_VALUE_PARAMETER_FORMAT = "t={0}, k={1}" ;
5244
5345 private const int DEFAULT_EXPIRATION = 43200 ;
5446 private const int MAXIMUM_EXPIRATION = 86400 ;
5547
48+ private const string JWT_HEADER = "{\" typ\" :\" JWT\" ,\" alg\" :\" ES256\" }" ;
49+ private const string JWT_SEPARATOR = "." ;
50+ private const string JWT_BODY_AUDIENCE_PART = "{\" aud\" :\" " ;
51+ private const string JWT_BODY_EXPIRATION_PART = "\" ,\" exp\" :" ;
52+ private const string JWT_BODY_SUBJECT_PART = ",\" sub\" :\" " ;
53+ private const string JWT_BODY_WITH_SUBJECT_CLOSING = "\" }" ;
54+ private const string JWT_BODY_WITHOUT_SUBJECT_CLOSING = "}" ;
55+
56+ private const string P256ECDSA_PREFIX = "p256ecdsa=" ;
57+ private const string VAPID_AUTHENTICATION_HEADER_VALUE_PARAMETER_FORMAT = "t={0}, k={1}" ;
58+
5659 private string _subject ;
5760 private string _publicKey ;
5861 private string _privateKey ;
5962 private ECPrivateKeyParameters _privateSigningKey ;
6063 private int _expiration ;
6164
6265 private static readonly DateTime _unixEpoch = new DateTime ( 1970 , 1 , 1 , 0 , 0 , 0 ) ;
63- private static readonly Dictionary < string , string > _jwtHeader = new Dictionary < string , string >
64- {
65- { "typ" , "JWT" } ,
66- { "alg" , "ES256" }
67- } ;
66+ private static readonly string _jwtHeaderSegment = UrlBase64Converter . ToUrlBase64String ( Encoding . UTF8 . GetBytes ( JWT_HEADER ) ) ;
6867 #endregion
6968
7069 #region Properties
@@ -212,25 +211,28 @@ private string GetToken(string audience)
212211 throw new ArgumentException ( nameof ( audience ) , "Audience should be an absolute URL" ) ;
213212 }
214213
215- Dictionary < string , object > jwtBody = GetJwtBody ( audience ) ;
214+ string jwtBodySegment = GetJwtBodySegment ( audience ) ;
216215
217- return GenerateJwtToken ( _jwtHeader , jwtBody ) ;
216+ return GenerateJwtToken ( jwtBodySegment ) ;
218217 }
219218
220- private Dictionary < string , object > GetJwtBody ( string audience )
219+ private string GetJwtBodySegment ( string audience )
221220 {
222- Dictionary < string , object > jwtBody = new Dictionary < string , object >
223- {
224- { AUDIENCE_CLAIM , audience } ,
225- { EXPIRATION_CLAIM , GetAbsoluteExpiration ( _expiration ) }
226- } ;
221+ StringBuilder jwtBodyBuilder = new StringBuilder ( ) ;
222+
223+ jwtBodyBuilder . Append ( JWT_BODY_AUDIENCE_PART ) . Append ( audience )
224+ . Append ( JWT_BODY_EXPIRATION_PART ) . Append ( GetAbsoluteExpiration ( _expiration ) . ToString ( CultureInfo . InvariantCulture ) ) ;
227225
228226 if ( _subject != null )
229227 {
230- jwtBody . Add ( SUBJECT_CLAIM , _subject ) ;
228+ jwtBodyBuilder . Append ( JWT_BODY_SUBJECT_PART ) . Append ( _subject ) . Append ( JWT_BODY_WITH_SUBJECT_CLOSING ) ;
229+ }
230+ else
231+ {
232+ jwtBodyBuilder . Append ( JWT_BODY_WITHOUT_SUBJECT_CLOSING ) ;
231233 }
232234
233- return jwtBody ;
235+ return UrlBase64Converter . ToUrlBase64String ( Encoding . UTF8 . GetBytes ( jwtBodyBuilder . ToString ( ) ) ) ;
234236 }
235237
236238 private static long GetAbsoluteExpiration ( int expirationSeconds )
@@ -240,11 +242,9 @@ private static long GetAbsoluteExpiration(int expirationSeconds)
240242 return ( long ) unixEpochOffset . TotalSeconds + expirationSeconds ;
241243 }
242244
243- private string GenerateJwtToken ( Dictionary < string , string > jwtHeader , Dictionary < string , object > jwtBody )
245+ private string GenerateJwtToken ( string jwtBodySegment )
244246 {
245- string jwtInput = UrlBase64Converter . ToUrlBase64String ( Encoding . UTF8 . GetBytes ( JsonConvert . SerializeObject ( jwtHeader ) ) )
246- + JWT_SEPARATOR
247- + UrlBase64Converter . ToUrlBase64String ( Encoding . UTF8 . GetBytes ( JsonConvert . SerializeObject ( jwtBody ) ) ) ;
247+ string jwtInput = _jwtHeaderSegment + JWT_SEPARATOR + jwtBodySegment ;
248248
249249 byte [ ] jwtInputHash ;
250250 using ( var sha256Hasher = SHA256 . Create ( ) )
0 commit comments