Skip to content

Commit 5b50ad8

Browse files
committed
Support for RS384 and RS512 algorithms
1 parent ea23dc4 commit 5b50ad8

File tree

3 files changed

+224
-14
lines changed

3 files changed

+224
-14
lines changed

JwtManager/RsJwt.cs

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@ public class RsJwt : Jwt
1515
{
1616
public string PrivateKey { get; set; }
1717
public string PublicKey { get; set; }
18+
public int KeySize { get; set; }
1819

1920
public override string Sign(string payload)
2021
{
2122
List<string> segments = new List<string>();
22-
var header = new JwtHeader { alg = "RS256", typ = "JWT" };
23+
JwtHeader header = Header;
2324

2425
DateTime issued = DateTime.Now;
2526
DateTime expire = DateTime.Now.AddHours(10);
@@ -39,7 +40,7 @@ public override string Sign(string payload)
3940
var privKeyObj = Asn1Object.FromByteArray(keyBytes);
4041
var privStruct = RsaPrivateKeyStructure.GetInstance((Asn1Sequence)privKeyObj);
4142

42-
ISigner sig = SignerUtilities.GetSigner("SHA256withRSA");
43+
ISigner sig = SignerUtilities.GetSigner(SignerName);
4344

4445
sig.Init(true, new RsaKeyParameters(true, privStruct.Modulus, privStruct.PrivateExponent));
4546

@@ -74,11 +75,10 @@ public override string Validate(string token)
7475
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
7576
rsa.ImportParameters(rsaParameters);
7677

77-
SHA256 sha256 = SHA256.Create();
78-
byte[] hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(header + '.' + payload));
78+
byte[] hash = ComputeHash(header, payload);
7979

8080
RSAPKCS1SignatureDeformatter rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa);
81-
rsaDeformatter.SetHashAlgorithm("SHA256");
81+
rsaDeformatter.SetHashAlgorithm(AlgorithmName);
8282
byte[] tmp = Helpers.Base64Helper.UrlDecode(signature);
8383
if (!rsaDeformatter.VerifySignature(hash, tmp))
8484
{
@@ -87,5 +87,38 @@ public override string Validate(string token)
8787

8888
return payloadJson;
8989
}
90+
91+
private JwtHeader Header
92+
{
93+
get
94+
{
95+
return new JwtHeader { alg = "RS" + KeySize.ToString(), typ = "JWT" };
96+
}
97+
}
98+
99+
private string SignerName
100+
{
101+
get
102+
{
103+
return "SHA" + KeySize.ToString() + "withRSA";
104+
}
105+
}
106+
107+
private string AlgorithmName
108+
{
109+
get
110+
{
111+
return "SHA" + KeySize.ToString();
112+
}
113+
}
114+
115+
private byte[] ComputeHash(string header, string payload)
116+
{
117+
HashAlgorithm sha = HashAlgorithm.Create(AlgorithmName);
118+
119+
if (sha == null) throw new Exception("Given key size is not valid.");
120+
121+
return sha.ComputeHash(Encoding.UTF8.GetBytes(header + '.' + payload));
122+
}
90123
}
91124
}

JwtManagerTests/RsJwtTests.cs

Lines changed: 184 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,26 @@
88
namespace JwtManagerTests
99
{
1010
[TestClass]
11-
public class RsJwtTests
11+
public abstract class RsJwtTests
1212
{
13-
#region Keys
13+
#region Private Members
1414
private static string PrivateKey = string.Empty;
1515
private static string PublicKey = string.Empty;
16+
1617
private static string KeySize = string.Empty;
1718
private static string OpenSslBinPath = string.Empty;
19+
1820
private static string CurrentPath = string.Empty;
1921
#endregion
2022

2123
#region Setup Methods
2224
[ClassInitialize]
23-
public static void ClassInit(TestContext context)
25+
public static void BaseClassInitialize(TestContext context)
2426
{
25-
KeySize = ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location).AppSettings.Settings["KeySize"].Value;
26-
OpenSslBinPath = ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location).AppSettings.Settings["OpenSslBinPath"].Value;
27+
AppSettingsSection AppSettings = ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location).AppSettings;
28+
29+
KeySize = AppSettings.Settings["KeySize"].Value;
30+
OpenSslBinPath = AppSettings.Settings["OpenSslBinPath"].Value;
2731

2832
CurrentPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
2933
string commands = string.Format(@"{0}openssl genrsa -out private{1}.key {1}
@@ -50,13 +54,13 @@ public static void ClassInit(TestContext context)
5054
}
5155

5256
[TestInitialize]
53-
public void Initialize() { }
57+
public void BaseTestInitialize() { }
5458

5559
[TestCleanup]
56-
public void Cleanup() { }
60+
public void BaseTestCleanup() { }
5761

5862
[ClassCleanup]
59-
public static void ClassCleanup()
63+
public static void BaseClassCleanup()
6064
{
6165
File.Delete(string.Format("{0}\\private{1}.key", CurrentPath, KeySize));
6266
File.Delete(string.Format("{0}\\public{1}.pem", CurrentPath, KeySize));
@@ -77,6 +81,7 @@ public void SignData()
7781
{
7882
JwtManager.RsJwt jwt = new JwtManager.RsJwt
7983
{
84+
KeySize = HashKeySize(),
8085
PrivateKey = PrivateKey
8186
};
8287

@@ -92,13 +97,14 @@ public void ValidateData()
9297
string data = "{a:1,b:2}";
9398
JwtManager.RsJwt signJwt = new JwtManager.RsJwt
9499
{
100+
KeySize = HashKeySize(),
95101
PrivateKey = PrivateKey
96102
};
97103
string signedData = signJwt.Sign(data);
98104

99105
JwtManager.RsJwt jwt = new JwtManager.RsJwt
100106
{
101-
PrivateKey = PrivateKey,
107+
KeySize = HashKeySize(),
102108
PublicKey = PublicKey
103109
};
104110
string validatedData = jwt.Validate(signedData);
@@ -112,6 +118,7 @@ public void ValidateInvalidData()
112118
Exception e = null;
113119
JwtManager.RsJwt jwt = new JwtManager.RsJwt
114120
{
121+
KeySize = HashKeySize(),
115122
PublicKey = PublicKey
116123
};
117124

@@ -136,6 +143,7 @@ public void SignInvalidPrivateKey()
136143
Exception e = null;
137144
JwtManager.RsJwt jwt = new JwtManager.RsJwt
138145
{
146+
KeySize = HashKeySize(),
139147
PrivateKey = PrivateKey + "a"
140148
};
141149

@@ -159,6 +167,7 @@ public void ValidateInvalidPublicKey()
159167
Exception e = null;
160168
JwtManager.RsJwt jwt = new JwtManager.RsJwt
161169
{
170+
KeySize = HashKeySize(),
162171
PublicKey = PublicKey + "a"
163172
};
164173

@@ -182,10 +191,12 @@ public void ValidateOtherPublicKey1()
182191
Exception e = null;
183192
JwtManager.RsJwt sJwt = new JwtManager.RsJwt
184193
{
194+
KeySize = HashKeySize(),
185195
PrivateKey = PrivateKey
186196
};
187197
JwtManager.RsJwt vJwt = new JwtManager.RsJwt
188198
{
199+
KeySize = HashKeySize(),
189200
PrivateKey = PrivateKey
190201
};
191202

@@ -210,6 +221,7 @@ public void ValidateOtherPublicKey2()
210221
Exception e = null;
211222
JwtManager.RsJwt sJwt = new JwtManager.RsJwt
212223
{
224+
KeySize = HashKeySize(),
213225
PublicKey = PublicKey
214226
};
215227

@@ -225,5 +237,168 @@ public void ValidateOtherPublicKey2()
225237

226238
Assert.IsNotNull(e, "An exception should be thrown");
227239
}
240+
241+
[TestMethod]
242+
public void SignDataWithInvalidHashAlgorithm()
243+
{
244+
Exception e = null;
245+
JwtManager.RsJwt jwt = new JwtManager.RsJwt
246+
{
247+
KeySize = 555,
248+
PrivateKey = PrivateKey
249+
};
250+
251+
try
252+
{
253+
string data = "{a:1,b:2}";
254+
string signedData = jwt.Sign(data);
255+
}
256+
catch (Exception ex)
257+
{
258+
e = ex;
259+
}
260+
261+
262+
Assert.IsNotNull(e, "An exception should be thrown");
263+
Assert.AreEqual(e.Message, "Signer SHA555WITHRSA not recognised.");
264+
}
265+
266+
[TestMethod]
267+
public void ValidateWithInvalidHashAlgorithm()
268+
{
269+
Exception e = null;
270+
JwtManager.RsJwt sJwt = new JwtManager.RsJwt
271+
{
272+
KeySize = HashKeySize(),
273+
PrivateKey = PrivateKey
274+
};
275+
JwtManager.RsJwt vJwt = new JwtManager.RsJwt
276+
{
277+
KeySize = 555,
278+
PublicKey = PublicKey
279+
};
280+
281+
try
282+
{
283+
string data = "{a:1,b:2}";
284+
string signedData = sJwt.Sign(data);
285+
Assert.IsNull(e, "An exception should not be thrown here");
286+
string validatedData = vJwt.Validate(signedData);
287+
}
288+
catch (Exception ex)
289+
{
290+
e = ex;
291+
}
292+
293+
Assert.IsNotNull(e, "An exception should be thrown");
294+
Assert.AreEqual(e.Message, "Given key size is not valid.");
295+
}
296+
297+
protected abstract int HashKeySize();
298+
}
299+
300+
[TestClass]
301+
public class Rs256Tests : RsJwtTests
302+
{
303+
#region Setup Methods
304+
[ClassInitialize]
305+
public static void ClassInit(TestContext context)
306+
{
307+
BaseClassInitialize(context);
308+
}
309+
310+
[TestInitialize]
311+
public void Initialize()
312+
{
313+
BaseTestInitialize();
314+
}
315+
316+
[TestCleanup]
317+
public void Cleanup()
318+
{
319+
BaseTestCleanup();
320+
}
321+
322+
[ClassCleanup]
323+
public static void ClassCleanup()
324+
{
325+
BaseClassCleanup();
326+
}
327+
#endregion
328+
329+
protected override int HashKeySize()
330+
{
331+
return 256;
332+
}
333+
}
334+
335+
[TestClass]
336+
public class Rs384Tests : RsJwtTests
337+
{
338+
#region Setup Methods
339+
[ClassInitialize]
340+
public static void ClassInit(TestContext context)
341+
{
342+
BaseClassInitialize(context);
343+
}
344+
345+
[TestInitialize]
346+
public void Initialize()
347+
{
348+
BaseTestInitialize();
349+
}
350+
351+
[TestCleanup]
352+
public void Cleanup()
353+
{
354+
BaseTestCleanup();
355+
}
356+
357+
[ClassCleanup]
358+
public static void ClassCleanup()
359+
{
360+
BaseClassCleanup();
361+
}
362+
#endregion
363+
364+
protected override int HashKeySize()
365+
{
366+
return 384;
367+
}
368+
}
369+
370+
[TestClass]
371+
public class Rs512Tests : RsJwtTests
372+
{
373+
#region Setup Methods
374+
[ClassInitialize]
375+
public static void ClassInit(TestContext context)
376+
{
377+
BaseClassInitialize(context);
378+
}
379+
380+
[TestInitialize]
381+
public void Initialize()
382+
{
383+
BaseTestInitialize();
384+
}
385+
386+
[TestCleanup]
387+
public void Cleanup()
388+
{
389+
BaseTestCleanup();
390+
}
391+
392+
[ClassCleanup]
393+
public static void ClassCleanup()
394+
{
395+
BaseClassCleanup();
396+
}
397+
#endregion
398+
399+
protected override int HashKeySize()
400+
{
401+
return 512;
402+
}
228403
}
229404
}

Readme.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ using Newtonsoft.Json;
1818

1919
JwtManager.RsJwt jwt = new JwtManager.RsJwt
2020
{
21+
KeySize = 256, // This can be also 384 or 512
2122
PrivateKey = PrivateKey
2223
};
2324

@@ -32,6 +33,7 @@ using Newtonsoft.Json;
3233

3334
JwtManager.RsJwt jwt = new JwtManager.RsJwt
3435
{
36+
KeySize = 256, // This can be also 384 or 512
3537
PublicKey = PublicKey
3638
};
3739

0 commit comments

Comments
 (0)