Skip to content

Commit 351cda2

Browse files
committed
add sign method. Refactor key parameter type
1 parent de7f6b2 commit 351cda2

12 files changed

Lines changed: 203 additions & 112 deletions

File tree

lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package com.auth0.jwt.algorithms;
22

3+
import com.auth0.jwt.exceptions.SignatureGenerationException;
34
import com.auth0.jwt.exceptions.SignatureVerificationException;
45

5-
import java.security.PublicKey;
6+
import java.security.interfaces.ECKey;
7+
import java.security.interfaces.RSAKey;
68

79
/**
810
* The Algorithm class represents an algorithm to be used in the Signing or Verification process of a Token.
@@ -15,37 +17,37 @@ public abstract class Algorithm {
1517
/**
1618
* Creates a new Algorithm instance using SHA256withRSA. Tokens specify this as "RS256".
1719
*
18-
* @param publicKey the key to use in the verify instance.
20+
* @param key the key to use in the verify or signing instance.
1921
* @return a valid RSA256 Algorithm.
2022
*/
21-
public static Algorithm RSA256(PublicKey publicKey) {
22-
return new RSAAlgorithm("RS256", "SHA256withRSA", publicKey);
23+
public static Algorithm RSA256(RSAKey key) {
24+
return new RSAAlgorithm("RS256", "SHA256withRSA", key);
2325
}
2426

2527
/**
2628
* Creates a new Algorithm instance using SHA384withRSA. Tokens specify this as "RS384".
2729
*
28-
* @param publicKey the key to use in the verify instance.
30+
* @param key the key to use in the verify or signing instance.
2931
* @return a valid RSA384 Algorithm.
3032
*/
31-
public static Algorithm RSA384(PublicKey publicKey) {
32-
return new RSAAlgorithm("RS384", "SHA384withRSA", publicKey);
33+
public static Algorithm RSA384(RSAKey key) {
34+
return new RSAAlgorithm("RS384", "SHA384withRSA", key);
3335
}
3436

3537
/**
3638
* Creates a new Algorithm instance using SHA512withRSA. Tokens specify this as "RS512".
3739
*
38-
* @param publicKey the key to use in the verify instance.
40+
* @param key the key to use in the verify or signing instance.
3941
* @return a valid RSA512 Algorithm.
4042
*/
41-
public static Algorithm RSA512(PublicKey publicKey) {
42-
return new RSAAlgorithm("RS512", "SHA512withRSA", publicKey);
43+
public static Algorithm RSA512(RSAKey key) {
44+
return new RSAAlgorithm("RS512", "SHA512withRSA", key);
4345
}
4446

4547
/**
4648
* Creates a new Algorithm instance using HmacSHA256. Tokens specify this as "HS256".
4749
*
48-
* @param secret the secret to use in the verify instance.
50+
* @param secret the secret to use in the verify or signing instance.
4951
* @return a valid HMAC256 Algorithm.
5052
*/
5153
public static Algorithm HMAC256(String secret) {
@@ -55,7 +57,7 @@ public static Algorithm HMAC256(String secret) {
5557
/**
5658
* Creates a new Algorithm instance using HmacSHA384. Tokens specify this as "HS384".
5759
*
58-
* @param secret the secret to use in the verify instance.
60+
* @param secret the secret to use in the verify or signing instance.
5961
* @return a valid HMAC384 Algorithm.
6062
*/
6163
public static Algorithm HMAC384(String secret) {
@@ -65,7 +67,7 @@ public static Algorithm HMAC384(String secret) {
6567
/**
6668
* Creates a new Algorithm instance using HmacSHA512. Tokens specify this as "HS512".
6769
*
68-
* @param secret the secret to use in the verify instance.
70+
* @param secret the secret to use in the verify or signing instance.
6971
* @return a valid HMAC512 Algorithm.
7072
*/
7173
public static Algorithm HMAC512(String secret) {
@@ -75,31 +77,31 @@ public static Algorithm HMAC512(String secret) {
7577
/**
7678
* Creates a new Algorithm instance using SHA256withECDSA. Tokens specify this as "ES256".
7779
*
78-
* @param publicKey the key to use in the verify instance.
80+
* @param key the key to use in the verify or signing instance.
7981
* @return a valid ECDSA256 Algorithm.
8082
*/
81-
public static Algorithm ECDSA256(PublicKey publicKey) {
82-
return new ECDSAAlgorithm("ES256", "SHA256withECDSA", 32, publicKey);
83+
public static Algorithm ECDSA256(ECKey key) {
84+
return new ECDSAAlgorithm("ES256", "SHA256withECDSA", 32, key);
8385
}
8486

8587
/**
8688
* Creates a new Algorithm instance using SHA384withECDSA. Tokens specify this as "ES384".
8789
*
88-
* @param publicKey the key to use in the verify instance.
90+
* @param key the key to use in the verify or signing instance.
8991
* @return a valid ECDSA384 Algorithm.
9092
*/
91-
public static Algorithm ECDSA384(PublicKey publicKey) {
92-
return new ECDSAAlgorithm("ES384", "SHA384withECDSA", 48, publicKey);
93+
public static Algorithm ECDSA384(ECKey key) {
94+
return new ECDSAAlgorithm("ES384", "SHA384withECDSA", 48, key);
9395
}
9496

9597
/**
9698
* Creates a new Algorithm instance using SHA512withECDSA. Tokens specify this as "ES512".
9799
*
98-
* @param publicKey the key to use in the verify instance.
100+
* @param key the key to use in the verify or signing instance.
99101
* @return a valid ECDSA512 Algorithm.
100102
*/
101-
public static Algorithm ECDSA512(PublicKey publicKey) {
102-
return new ECDSAAlgorithm("ES512", "SHA512withECDSA", 66, publicKey);
103+
public static Algorithm ECDSA512(ECKey key) {
104+
return new ECDSAAlgorithm("ES512", "SHA512withECDSA", 66, key);
103105
}
104106

105107
public static Algorithm none() {
@@ -141,4 +143,6 @@ public String toString() {
141143
* @throws SignatureVerificationException if the Token's Signature is invalid.
142144
*/
143145
public abstract void verify(String[] jwtParts) throws SignatureVerificationException;
146+
147+
public abstract byte[] sign(byte[] headerAndPayloadBytes) throws SignatureGenerationException;
144148
}

lib/src/main/java/com/auth0/jwt/algorithms/CryptoHelper.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@
77
class CryptoHelper {
88

99
boolean verifyMacFor(String algorithm, byte[] secretBytes, byte[] contentBytes, byte[] signatureBytes) throws NoSuchAlgorithmException, InvalidKeyException {
10+
return MessageDigest.isEqual(createMacFor(algorithm, secretBytes, contentBytes), signatureBytes);
11+
}
12+
13+
byte[] createMacFor(String algorithm, byte[] secretBytes, byte[] contentBytes) throws NoSuchAlgorithmException, InvalidKeyException {
1014
final Mac mac = Mac.getInstance(algorithm);
1115
mac.init(new SecretKeySpec(secretBytes, algorithm));
12-
byte[] result = mac.doFinal(contentBytes);
13-
return MessageDigest.isEqual(result, signatureBytes);
16+
return mac.doFinal(contentBytes);
1417
}
1518

1619
boolean verifySignatureFor(String algorithm, PublicKey publicKey, byte[] contentBytes, byte[] signatureBytes) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
@@ -19,4 +22,11 @@ boolean verifySignatureFor(String algorithm, PublicKey publicKey, byte[] content
1922
s.update(contentBytes);
2023
return s.verify(signatureBytes);
2124
}
25+
26+
byte[] createSignatureFor(String algorithm, PrivateKey privateKey, byte[] contentBytes) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
27+
final Signature s = Signature.getInstance(algorithm);
28+
s.initSign(privateKey);
29+
s.update(contentBytes);
30+
return s.sign();
31+
}
2232
}

lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,50 @@
11
package com.auth0.jwt.algorithms;
22

3+
import com.auth0.jwt.exceptions.SignatureGenerationException;
34
import com.auth0.jwt.exceptions.SignatureVerificationException;
45
import org.apache.commons.codec.binary.Base64;
56

6-
import java.security.InvalidKeyException;
7-
import java.security.NoSuchAlgorithmException;
8-
import java.security.PublicKey;
9-
import java.security.SignatureException;
7+
import java.security.*;
8+
import java.security.interfaces.ECKey;
9+
import java.security.interfaces.ECPrivateKey;
10+
import java.security.interfaces.ECPublicKey;
1011

1112
class ECDSAAlgorithm extends Algorithm {
1213

1314
private final CryptoHelper crypto;
1415
private final int ecNumberSize;
15-
private final PublicKey publicKey;
16+
private final ECKey key;
1617

17-
ECDSAAlgorithm(CryptoHelper crypto, String id, String algorithm, int ecNumberSize, PublicKey publicKey) {
18+
ECDSAAlgorithm(CryptoHelper crypto, String id, String algorithm, int ecNumberSize, ECKey key) {
1819
super(id, algorithm);
19-
if (publicKey == null) {
20-
throw new IllegalArgumentException("The PublicKey cannot be null");
20+
if (key == null) {
21+
throw new IllegalArgumentException("The ECKey cannot be null");
2122
}
2223
this.ecNumberSize = ecNumberSize;
23-
this.publicKey = publicKey;
24+
this.key = key;
2425
this.crypto = crypto;
2526
}
2627

27-
ECDSAAlgorithm(String id, String algorithm, int ecNumberSize, PublicKey publicKey) {
28-
this(new CryptoHelper(), id, algorithm, ecNumberSize, publicKey);
28+
ECDSAAlgorithm(String id, String algorithm, int ecNumberSize, ECKey key) {
29+
this(new CryptoHelper(), id, algorithm, ecNumberSize, key);
2930
}
3031

31-
PublicKey getPublicKey() {
32-
return publicKey;
32+
ECKey getKey() {
33+
return key;
3334
}
3435

3536
@Override
3637
public void verify(String[] jwtParts) throws SignatureVerificationException {
38+
if (!(key instanceof ECPublicKey)) {
39+
throw new IllegalArgumentException("The given ECKey is not an ECPublicKey.");
40+
}
3741
try {
3842
String content = String.format("%s.%s", jwtParts[0], jwtParts[1]);
3943
byte[] signature = Base64.decodeBase64(jwtParts[2]);
4044
if (!isDERSignature(signature)) {
4145
signature = JOSEToDER(signature);
4246
}
43-
boolean valid = crypto.verifySignatureFor(getDescription(), publicKey, content.getBytes(), signature);
47+
boolean valid = crypto.verifySignatureFor(getDescription(), (ECPublicKey) key, content.getBytes(), signature);
4448

4549
if (!valid) {
4650
throw new SignatureVerificationException(this);
@@ -50,6 +54,18 @@ public void verify(String[] jwtParts) throws SignatureVerificationException {
5054
}
5155
}
5256

57+
@Override
58+
public byte[] sign(byte[] headerAndPayloadBytes) throws SignatureGenerationException {
59+
try {
60+
if (!(key instanceof ECPrivateKey)) {
61+
throw new IllegalArgumentException("The given ECKey is not a ECPrivateKey.");
62+
}
63+
return crypto.createSignatureFor(getDescription(), (PrivateKey) key, headerAndPayloadBytes);
64+
} catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException | IllegalArgumentException e) {
65+
throw new SignatureGenerationException(this, e);
66+
}
67+
}
68+
5369
private boolean isDERSignature(byte[] signature) {
5470
// DER Structure: http://crypto.stackexchange.com/a/1797
5571
// Should begin with 0x30 and have exactly the expected length

lib/src/main/java/com/auth0/jwt/algorithms/HMACAlgorithm.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.auth0.jwt.algorithms;
22

3+
import com.auth0.jwt.exceptions.SignatureGenerationException;
34
import com.auth0.jwt.exceptions.SignatureVerificationException;
45
import org.apache.commons.codec.binary.Base64;
56

@@ -43,4 +44,13 @@ public void verify(String[] jwtParts) throws SignatureVerificationException {
4344
}
4445
}
4546

47+
@Override
48+
public byte[] sign(byte[] headerAndPayloadBytes) throws SignatureGenerationException {
49+
try {
50+
return crypto.createMacFor(getDescription(), secret.getBytes(), headerAndPayloadBytes);
51+
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
52+
throw new SignatureGenerationException(this, e);
53+
}
54+
}
55+
4656
}

lib/src/main/java/com/auth0/jwt/algorithms/NoneAlgorithm.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.auth0.jwt.algorithms;
22

3+
import com.auth0.jwt.exceptions.SignatureGenerationException;
34
import com.auth0.jwt.exceptions.SignatureVerificationException;
45

56
class NoneAlgorithm extends Algorithm {
@@ -14,4 +15,9 @@ public void verify(String[] jwtParts) throws SignatureVerificationException {
1415
throw new SignatureVerificationException(this);
1516
}
1617
}
18+
19+
@Override
20+
public byte[] sign(byte[] headerAndPayloadBytes) throws SignatureGenerationException {
21+
return new byte[0];
22+
}
1723
}
Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,45 @@
11
package com.auth0.jwt.algorithms;
22

3+
import com.auth0.jwt.exceptions.SignatureGenerationException;
34
import com.auth0.jwt.exceptions.SignatureVerificationException;
45
import org.apache.commons.codec.binary.Base64;
56

6-
import java.security.InvalidKeyException;
7-
import java.security.NoSuchAlgorithmException;
8-
import java.security.PublicKey;
9-
import java.security.SignatureException;
7+
import java.security.*;
8+
import java.security.interfaces.RSAKey;
9+
import java.security.interfaces.RSAPrivateKey;
10+
import java.security.interfaces.RSAPublicKey;
1011

1112
class RSAAlgorithm extends Algorithm {
1213

13-
private final PublicKey publicKey;
14+
private final RSAKey key;
1415
private CryptoHelper crypto;
1516

16-
RSAAlgorithm(CryptoHelper crypto, String id, String algorithm, PublicKey publicKey) {
17+
RSAAlgorithm(CryptoHelper crypto, String id, String algorithm, RSAKey key) {
1718
super(id, algorithm);
18-
if (publicKey == null) {
19-
throw new IllegalArgumentException("The PublicKey cannot be null");
19+
if (key == null) {
20+
throw new IllegalArgumentException("The RSAKey cannot be null");
2021
}
21-
this.publicKey = publicKey;
22+
this.key = key;
2223
this.crypto = crypto;
2324
}
2425

25-
RSAAlgorithm(String id, String algorithm, PublicKey publicKey) {
26-
this(new CryptoHelper(), id, algorithm, publicKey);
26+
RSAAlgorithm(String id, String algorithm, RSAKey key) {
27+
this(new CryptoHelper(), id, algorithm, key);
2728
}
2829

29-
PublicKey getPublicKey() {
30-
return publicKey;
30+
RSAKey getKey() {
31+
return key;
3132
}
3233

3334
@Override
3435
public void verify(String[] jwtParts) throws SignatureVerificationException {
36+
if (!(key instanceof PublicKey)) {
37+
throw new IllegalArgumentException("The given RSAKey is not a RSAPublicKey.");
38+
}
3539
try {
3640
String content = String.format("%s.%s", jwtParts[0], jwtParts[1]);
3741
byte[] signature = Base64.decodeBase64(jwtParts[2]);
38-
boolean valid = crypto.verifySignatureFor(getDescription(), publicKey, content.getBytes(), signature);
42+
boolean valid = crypto.verifySignatureFor(getDescription(), (RSAPublicKey) key, content.getBytes(), signature);
3943

4044
if (!valid) {
4145
throw new SignatureVerificationException(this);
@@ -44,4 +48,16 @@ public void verify(String[] jwtParts) throws SignatureVerificationException {
4448
throw new SignatureVerificationException(this, e);
4549
}
4650
}
51+
52+
@Override
53+
public byte[] sign(byte[] headerAndPayloadBytes) throws SignatureGenerationException {
54+
try {
55+
if (!(key instanceof PrivateKey)) {
56+
throw new IllegalArgumentException("The given RSAKey is not a RSAPrivateKey.");
57+
}
58+
return crypto.createSignatureFor(getDescription(), (RSAPrivateKey) key, headerAndPayloadBytes);
59+
} catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException | IllegalArgumentException e) {
60+
throw new SignatureGenerationException(this, e);
61+
}
62+
}
4763
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.auth0.jwt.exceptions;
2+
3+
public class JWTCreationException extends RuntimeException {
4+
public JWTCreationException(String message) {
5+
this(message, null);
6+
}
7+
8+
public JWTCreationException(String message, Throwable cause) {
9+
super(message, cause);
10+
}
11+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.auth0.jwt.exceptions;
2+
3+
import com.auth0.jwt.algorithms.Algorithm;
4+
5+
public class SignatureGenerationException extends JWTCreationException {
6+
public SignatureGenerationException(Algorithm algorithm, Throwable cause) {
7+
super("The Token's Signature couldn't be generated when signing using the Algorithm: " + algorithm, cause);
8+
}
9+
}

0 commit comments

Comments
 (0)