Jwt 工具类

依赖包

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
<version>9.4.1</version>
</dependency>
<dependency>
<groupId>com.google.crypto.tink</groupId>
<artifactId>tink</artifactId>
<version>1.2.0-rc2</version>
</dependency>

Jws

JSON Web Signature

对JWT进行签名。给内容加签名的作用前面已经说过了

  • 防止JWT内容被篡改,确保内容的完整性
  • 可以验证该JWT确实签发自当前server

JwsUtils 工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.JWSSigner;
import com.nimbusds.jose.JWSVerifier;
import com.nimbusds.jose.crypto.ECDSASigner;
import com.nimbusds.jose.crypto.ECDSAVerifier;
import com.nimbusds.jose.crypto.Ed25519Signer;
import com.nimbusds.jose.crypto.Ed25519Verifier;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jose.crypto.MACVerifier;
import com.nimbusds.jose.crypto.RSASSASigner;
import com.nimbusds.jose.crypto.RSASSAVerifier;
import com.nimbusds.jose.jwk.Curve;
import com.nimbusds.jose.jwk.ECKey;
import com.nimbusds.jose.jwk.JWK;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.KeyUse;
import com.nimbusds.jose.jwk.OctetKeyPair;
import com.nimbusds.jose.jwk.OctetSequenceKey;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.gen.ECKeyGenerator;
import com.nimbusds.jose.jwk.gen.OctetKeyPairGenerator;
import com.nimbusds.jose.jwk.gen.OctetSequenceKeyGenerator;
import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;

import java.text.MessageFormat;
import java.text.ParseException;

/**
* Jws:jwt sign 和 verify
* <ul>
* <li>{@link com.nimbusds.jose.JWSAlgorithm#HS256}
* <li>{@link com.nimbusds.jose.JWSAlgorithm#HS384}
* <li>{@link com.nimbusds.jose.JWSAlgorithm#HS512}
* <li>{@link com.nimbusds.jose.JWSAlgorithm#RS256}
* <li>{@link com.nimbusds.jose.JWSAlgorithm#RS384}
* <li>{@link com.nimbusds.jose.JWSAlgorithm#RS512}
* <li>{@link com.nimbusds.jose.JWSAlgorithm#ES256}
* <li>{@link com.nimbusds.jose.JWSAlgorithm#ES384}
* <li>{@link com.nimbusds.jose.JWSAlgorithm#ES512}
* <li>{@link com.nimbusds.jose.JWSAlgorithm#PS256}
* <li>{@link com.nimbusds.jose.JWSAlgorithm#PS384}
* <li>{@link com.nimbusds.jose.JWSAlgorithm#PS512}
* <li>{@link com.nimbusds.jose.JWSAlgorithm#EdDSA}
* <li>{@link com.nimbusds.jose.JWSAlgorithm#ES256K} (deprecated, non-standard)
* </ul>
*
* @author yangli
*/
public class JwsUtils {

public static String genJwsAlgorithmKey(String keyId, String algorithm) throws JOSEException {
return JwsUtils.genJwsAlgorithmKey(keyId, JWSAlgorithm.parse(algorithm));
}

public static String genJwsAlgorithmKey(String keyId, JWSAlgorithm jwsAlgorithm) throws JOSEException {
String algorithmKey = null;
if (JWSAlgorithm.Family.HMAC_SHA.contains(jwsAlgorithm)) {
int size = Integer.parseInt(jwsAlgorithm.getName().substring(2));
OctetSequenceKey key = new OctetSequenceKeyGenerator(size)
.keyID(keyId)
.keyUse(KeyUse.SIGNATURE)
.algorithm(jwsAlgorithm)
.generate();
algorithmKey = key.toJSONString();
} else if (JWSAlgorithm.Family.RSA.contains(jwsAlgorithm)) {
RSAKey key = new RSAKeyGenerator(2048)
.keyID(keyId)
.keyUse(KeyUse.SIGNATURE)
.algorithm(jwsAlgorithm)
.generate();
algorithmKey = key.toJSONString();
} else if (JWSAlgorithm.Family.EC.contains(jwsAlgorithm)) {
Curve curve = Curve.P_256;
if (jwsAlgorithm.equals(JWSAlgorithm.ES384)) {
curve = Curve.P_384;
} else if (jwsAlgorithm.equals(JWSAlgorithm.ES512)) {
curve = Curve.P_521;
} else if (jwsAlgorithm.equals(JWSAlgorithm.ES256K)) {
// 报错
curve = Curve.P_256K;
}
ECKey key = new ECKeyGenerator(curve)
.keyID(keyId)
.keyUse(KeyUse.SIGNATURE)
.algorithm(jwsAlgorithm)
.generate();
algorithmKey = key.toJSONString();
} else if (JWSAlgorithm.Family.ED.contains(jwsAlgorithm)) {
OctetKeyPair key = new OctetKeyPairGenerator(Curve.Ed25519)
.keyID(keyId)
.keyUse(KeyUse.SIGNATURE)
.algorithm(jwsAlgorithm)
.generate();
algorithmKey = key.toJSONString();
}
if (algorithmKey == null) {
throw new JOSEException(MessageFormat.format("暂不支持 {0} 签名算法", jwsAlgorithm));
}
System.out.println(MessageFormat.format("{0} ---> algorithmKey: {1}", jwsAlgorithm, algorithmKey));
return algorithmKey;
}

public static SignedJWT sign(String jwtClaimsSetString, String algorithmKey) throws JOSEException, ParseException {
return JwsUtils.sign(JWTClaimsSet.parse(jwtClaimsSetString), algorithmKey);
}

public static SignedJWT sign(JWTClaimsSet claims, String algorithmKey) throws JOSEException, ParseException {
JWKSet jwkSet = JWKSet.parse("{\"keys\":[" + algorithmKey + "]}");
JWK jwk = jwkSet.getKeys().get(0);
return JwsUtils.sign(claims, jwk);
}

public static SignedJWT sign(JWTClaimsSet claims, JWK jwk) throws JOSEException, ParseException {
JWSSigner signer = null;
if (jwk instanceof OctetSequenceKey) {
OctetSequenceKey key = (OctetSequenceKey) jwk;
signer = new MACSigner(key);
} else if (jwk instanceof RSAKey) {
RSAKey key = (RSAKey) jwk;
signer = new RSASSASigner(key);
} else if (jwk instanceof ECKey) {
ECKey key = (ECKey) jwk;
signer = new ECDSASigner(key);
} else if (jwk instanceof OctetKeyPair) {
OctetKeyPair key = (OctetKeyPair) jwk;
signer = new Ed25519Signer(key);
}
String name = jwk.getAlgorithm().getName();
if (signer == null) {
throw new JOSEException(MessageFormat.format("签名器为空,或不支持 {0} 签名算法", name));
}
SignedJWT signedJwt = new SignedJWT(new JWSHeader(JWSAlgorithm.parse(name)), claims);
signedJwt.sign(signer);
return signedJwt;
}

public static String serialize(String jwtClaimsSetString, String algorithmKey) throws JOSEException, ParseException {
return JwsUtils.serialize(JWTClaimsSet.parse(jwtClaimsSetString), algorithmKey);
}

public static String serialize(JWTClaimsSet claims, String algorithmKey) throws JOSEException, ParseException {
JWKSet jwkSet = JWKSet.parse("{\"keys\":[" + algorithmKey + "]}");
JWK jwk = jwkSet.getKeys().get(0);
return JwsUtils.serialize(claims, jwk);
}

public static String serialize(JWTClaimsSet claims, JWK jwk) throws JOSEException, ParseException {
SignedJWT signedJwt = JwsUtils.sign(claims, jwk);
return signedJwt.serialize();
}

public static boolean verify(String jwsString, String algorithmKey) throws ParseException, JOSEException {
JWKSet jwkSet = JWKSet.parse("{\"keys\":[" + algorithmKey + "]}");
JWK jwk = jwkSet.getKeys().get(0);
return JwsUtils.verify(SignedJWT.parse(jwsString), jwk);
}

public static boolean verify(SignedJWT signedJwt, JWK jwk) throws ParseException, JOSEException {
JWSVerifier verifier = null;
if (jwk instanceof OctetSequenceKey) {
OctetSequenceKey key = (OctetSequenceKey) jwk;
verifier = new MACVerifier(key);
} else if (jwk instanceof RSAKey) {
RSAKey key = (RSAKey) jwk;
verifier = new RSASSAVerifier(key);
} else if (jwk instanceof ECKey) {
ECKey key = (ECKey) jwk;
verifier = new ECDSAVerifier(key);
} else if (jwk instanceof OctetKeyPair) {
OctetKeyPair key = (OctetKeyPair) jwk;
verifier = new Ed25519Verifier(key.toPublicJWK());
}
if (verifier == null) {
String name = jwk.getAlgorithm().getName();
throw new JOSEException(MessageFormat.format("验证器为空,或不支持 {0} 签名算法", name));
}
return signedJwt.verify(verifier);
}
}

JwsUtilsTest 测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jwt.JWTClaimsSet;
import org.junit.Test;

import java.text.MessageFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
* @author yangli
*/
public class JwsUtilsTest {
// Prepare JWT with claims set
private static final JWTClaimsSet claims = new JWTClaimsSet.Builder()
.subject("subject")
.issuer("https://jwt.io")
.expirationTime(new Date(System.currentTimeMillis() + 60 * 1000))
.build();

private static final List<JWSAlgorithm> JWS_ALGORITHM = new ArrayList<>();

static {
JWS_ALGORITHM.addAll(JWSAlgorithm.Family.HMAC_SHA);
JWS_ALGORITHM.addAll(JWSAlgorithm.Family.RSA);

// JWS_ALGORITHM.addAll(JWSAlgorithm.Family.EC);
JWS_ALGORITHM.add(JWSAlgorithm.ES256);
JWS_ALGORITHM.add(JWSAlgorithm.ES384);
JWS_ALGORITHM.add(JWSAlgorithm.ES512);
// JWS_ALGORITHM.add(JWSAlgorithm.ES256K); // 报错

JWS_ALGORITHM.addAll(JWSAlgorithm.Family.ED);
}

@Test
public void testAll() throws ParseException, JOSEException {
String keyId = "ssfds38038";
for (JWSAlgorithm jwsAlgorithm : JWS_ALGORITHM) {
String algorithmKey = JwsUtils.genJwsAlgorithmKey(keyId, jwsAlgorithm);
String jwsString = JwsUtils.serialize(claims, algorithmKey);
boolean verify = JwsUtils.verify(jwsString, algorithmKey);
System.out.println(MessageFormat.format(
"{0} ---> verify: {1}, jwsString: {2}", jwsAlgorithm.getName(), verify, jwsString));
}
}

// @Test
// public void macs() throws JOSEException, ParseException {
// // // Generate random 256-bit (32-byte) shared secret
// // SecureRandom random = new SecureRandom();
// // byte[] sharedSecret = new byte[32];
// // random.nextBytes(sharedSecret);
// // System.out.println(Arrays.toString(sharedSecret));
// // String sharedSecret = "ssddSFFsdfsdfssddSFFsdfsdf123456";
// // String payload = "Hello, world!";
// // System.out.println(Arrays.toString(sharedSecret.getBytes(StandardCharsets.UTF_8)));
// // // Create HMAC signer
// // JWSSigner signer = new MACSigner(sharedSecret);
//
// OctetSequenceKey octKey = new OctetSequenceKeyGenerator(2048)
// .keyID("dfsfs2342342")
// // .keyUse(KeyUse.SIGNATURE)
// .algorithm(JWSAlgorithm.HS256)
// .generate();
// System.out.println(octKey.toJSONString());
// // Create HMAC signer
// JWSSigner signer = new MACSigner(octKey);
//
// // Prepare JWS object with "Hello, world!" payload
// SignedJWT signedJwt = new SignedJWT(new JWSHeader(JWSAlgorithm.HS256), claims);
//
// // Apply the HMAC
// signedJwt.sign(signer);
//
// // To serialize to compact form, produces something like
// String s = signedJwt.serialize();
// System.out.println("jws 加载: " + s);
//
// // To parse the JWS and verify it, e.g. on client-side
// signedJwt = SignedJWT.parse(s);
// System.out.println("jws 解析(Header): " + signedJwt.getHeader());
// System.out.println("jws 解析(Payload): " + signedJwt.getPayload());
// System.out.println("jws 解析(Signature): " + signedJwt.getSignature());
// System.out.println("jws 解析(State): " + signedJwt.getState());
//
// JWSVerifier verifier = new MACVerifier(octKey);
//
// System.out.println("是否验证通过:" + signedJwt.verify(verifier));
//
// }
//
// @Test
// public void rsa() throws JOSEException, ParseException {
// // RSA signatures require a public and private RSA key pair, the public key
// // must be made known to the JWS recipient in order to verify the signatures
// RSAKey rsaKey = new RSAKeyGenerator(2048)
// .keyID("oikleqrk46454jh23k4j")
// .generate();
// RSAKey publicJwk = rsaKey.toPublicJWK();
//
// // Create RSA-signer with the private key
// JWSSigner signer = new RSASSASigner(rsaKey);
//
// SignedJWT signedJwt = new SignedJWT(
// new JWSHeader.Builder(JWSAlgorithm.RS512)
// // .keyID(rsaKey.getKeyID())
// .build(), claims);
//
// // Compute the RSA signature
// signedJwt.sign(signer);
//
// String s = signedJwt.serialize();
// System.out.println("jws 加载: " + s);
//
// // On the consumer side, parse the JWS and verify its RSA signature
// signedJwt = SignedJWT.parse(s);
// System.out.println("jws 解析(Header): " + signedJwt.getHeader());
// System.out.println("jws 解析(Payload): " + signedJwt.getPayload());
// System.out.println("jws 解析(Signature): " + signedJwt.getSignature());
// System.out.println("jws 解析(State): " + signedJwt.getState());
//
// JWSVerifier verifier = new RSASSAVerifier(publicJwk);
//
// System.out.println("是否验证通过:" + signedJwt.verify(verifier));
// }
//
// @Test
// public void ec() throws JOSEException, ParseException {
// // RSA signatures require a public and private RSA key pair, the public key
// // must be made known to the JWS recipient in order to verify the signatures
// ECKey ecKey = new ECKeyGenerator(Curve.P_256)
// .keyID("shfje576463341fdfg")
// .generate();
// System.out.println(ecKey.toJSONString());
// ECKey publicJwk = ecKey.toPublicJWK();
//
// // Create RSA-signer with the private key
// JWSSigner signer = new ECDSASigner(ecKey);
//
// SignedJWT signedJwt = new SignedJWT(
// new JWSHeader.Builder(JWSAlgorithm.ES256)
// // .keyID(ecKey.getKeyID())
// .build(), claims);
//
// // Compute the RSA signature
// signedJwt.sign(signer);
//
// String s = signedJwt.serialize();
// System.out.println("jws 加载: " + s);
//
// // On the consumer side, parse the JWS and verify its RSA signature
// signedJwt = SignedJWT.parse(s);
// System.out.println("jws 解析(Header): " + signedJwt.getHeader());
// System.out.println("jws 解析(Payload): " + signedJwt.getPayload());
// System.out.println("jws 解析(Signature): " + signedJwt.getSignature());
// System.out.println("jws 解析(State): " + signedJwt.getState());
//
// JWSVerifier verifier = new ECDSAVerifier(publicJwk);
//
// System.out.println("是否验证通过:" + signedJwt.verify(verifier));
// }
//
// @Test
// public void ed() throws JOSEException, ParseException {
// // RSA signatures require a public and private RSA key pair, the public key
// // must be made known to the JWS recipient in order to verify the signatures
// OctetKeyPair edKey = new OctetKeyPairGenerator(Curve.Ed25519)
// .keyID("dfsfs2342342")
// .generate();
// System.out.println(edKey.toJSONString());
// OctetKeyPair publicJwk = edKey.toPublicJWK();
//
// // Create RSA-signer with the private key
// JWSSigner signer = new Ed25519Signer(edKey);
//
// SignedJWT signedJwt = new SignedJWT(
// new JWSHeader.Builder(JWSAlgorithm.EdDSA)
// // .keyID(ecKey.getKeyID())
// .build(), claims);
//
// // Compute the RSA signature
// signedJwt.sign(signer);
//
// String s = signedJwt.serialize();
// System.out.println("jws 加载: " + s);
//
// // On the consumer side, parse the JWS and verify its RSA signature
// signedJwt = SignedJWT.parse(s);
// System.out.println("jws 解析(Header): " + signedJwt.getHeader());
// System.out.println("jws 解析(Payload): " + signedJwt.getPayload());
// System.out.println("jws 解析(Signature): " + signedJwt.getSignature());
// System.out.println("jws 解析(State): " + signedJwt.getState());
//
// JWSVerifier verifier = new Ed25519Verifier(publicJwk);
//
// System.out.println("是否验证通过:" + signedJwt.verify(verifier));
// }
}

Jwe

JWS是利用签名保证数据内容不会被篡改,但是最终的base64解码之后还是可以看到payload其中的内容。就实际运用中来说,我们的JWT中一般不存放铭感信息。如果搭配OAuth2.0来的话,可能有scope等内容,但其实这些内容被解码之后对我们的影响也几乎没有。

不过,如果想对payload的内容加密,使得数据不会被解码出来,那么这时候就需要JWE-JSON Web Encryption。

这里再提醒一下:

  • Jws是对内容进行签名但是不加密
  • Jwe是对内容进行加密但是不签名
  • Jws 和 Jwe 可以结合使用,先签名再加密,然后先解密再验证签名

JweUtils 工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
import com.nimbusds.jose.EncryptionMethod;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWEAlgorithm;
import com.nimbusds.jose.JWEDecrypter;
import com.nimbusds.jose.JWEEncrypter;
import com.nimbusds.jose.JWEHeader;
import com.nimbusds.jose.JWEObject;
import com.nimbusds.jose.Payload;
import com.nimbusds.jose.crypto.AESDecrypter;
import com.nimbusds.jose.crypto.AESEncrypter;
import com.nimbusds.jose.crypto.DirectDecrypter;
import com.nimbusds.jose.crypto.DirectEncrypter;
import com.nimbusds.jose.crypto.ECDHDecrypter;
import com.nimbusds.jose.crypto.ECDHEncrypter;
import com.nimbusds.jose.crypto.PasswordBasedDecrypter;
import com.nimbusds.jose.crypto.PasswordBasedEncrypter;
import com.nimbusds.jose.crypto.RSADecrypter;
import com.nimbusds.jose.crypto.RSAEncrypter;
import com.nimbusds.jose.jwk.Curve;
import com.nimbusds.jose.jwk.ECKey;
import com.nimbusds.jose.jwk.JWK;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.KeyUse;
import com.nimbusds.jose.jwk.OctetSequenceKey;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.gen.ECKeyGenerator;
import com.nimbusds.jose.jwk.gen.OctetSequenceKeyGenerator;
import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;
import com.nimbusds.jwt.SignedJWT;

import java.text.MessageFormat;
import java.text.ParseException;

/**
* Jwe:jwt encrypt 和 decrypt
* <p>
* 加密算法
* <ul>
* <li>{@link com.nimbusds.jose.JWEAlgorithm#DIR}
* <li>{@link com.nimbusds.jose.JWEAlgorithm#RSA_OAEP_256}
* <li>{@link com.nimbusds.jose.JWEAlgorithm#RSA_OAEP} (deprecated)
* <li>{@link com.nimbusds.jose.JWEAlgorithm#RSA1_5} (deprecated)
* <li>{@link com.nimbusds.jose.JWEAlgorithm#A128KW}
* <li>{@link com.nimbusds.jose.JWEAlgorithm#A192KW}
* <li>{@link com.nimbusds.jose.JWEAlgorithm#A256KW}
* <li>{@link com.nimbusds.jose.JWEAlgorithm#A128GCMKW}
* <li>{@link com.nimbusds.jose.JWEAlgorithm#A192GCMKW}
* <li>{@link com.nimbusds.jose.JWEAlgorithm#A256GCMKW}
* <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_ES}
* <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_ES_A128KW}
* <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_ES_A192KW}
* <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_ES_A256KW}
* <li>{@link com.nimbusds.jose.JWEAlgorithm#PBES2_HS256_A128KW}
* <li>{@link com.nimbusds.jose.JWEAlgorithm#PBES2_HS384_A192KW}
* <li>{@link com.nimbusds.jose.JWEAlgorithm#PBES2_HS512_A256KW}
* </ul>
*
* <p>
* 加密方法
* <ul>
* <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256} (requires 256 bit key)
* <li>{@link com.nimbusds.jose.EncryptionMethod#A192CBC_HS384} (requires 384 bit key)
* <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512} (requires 512 bit key)
* <li>{@link com.nimbusds.jose.EncryptionMethod#A128GCM} (requires 128 bit key)
* <li>{@link com.nimbusds.jose.EncryptionMethod#A192GCM} (requires 192 bit key)
* <li>{@link com.nimbusds.jose.EncryptionMethod#A256GCM} (requires 256 bit key)
* <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256_DEPRECATED} (deprecated, requires 256 bit key)
* <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512_DEPRECATED} (deprecated, requires 512 bit key)
* </ul>
*
* @author yangli
*/
public class JweUtils {

public static String genJweAlgorithmKey(String keyId, String jweAlgorithmName, String encryptionMethod) throws JOSEException {
return JweUtils.genJweAlgorithmKey(keyId, JWEAlgorithm.parse(jweAlgorithmName), EncryptionMethod.parse(encryptionMethod));
}

public static String genJweAlgorithmKey(String keyId, JWEAlgorithm jweAlgorithm, EncryptionMethod encryptionMethod) throws JOSEException {
String algorithmKey = null;
if (jweAlgorithm.equals(JWEAlgorithm.DIR)) {
if (encryptionMethod.equals(EncryptionMethod.A128CBC_HS256_DEPRECATED)
|| encryptionMethod.equals(EncryptionMethod.A256CBC_HS512_DEPRECATED)) {
throw new JOSEException(MessageFormat.format(
"{0} 加解密算法暂不支持 {1} 加密方法", jweAlgorithm.getName(), encryptionMethod.getName()));
}
int size = 0;
if (
// EncryptionMethod.A128CBC_HS256 (requires 256 bit key)
encryptionMethod.equals(EncryptionMethod.A128CBC_HS256)
// EncryptionMethod.A256GCM (requires 256 bit key)
|| encryptionMethod.equals(EncryptionMethod.A256GCM)
// EncryptionMethod.A128CBC_HS256_DEPRECATED (requires 256 bit key)
|| encryptionMethod.equals(EncryptionMethod.A128CBC_HS256_DEPRECATED)) {
size = 256;
} else if (encryptionMethod.equals(EncryptionMethod.A192CBC_HS384)) {
// EncryptionMethod.A192CBC_HS384 (requires 384 bit key)
size = 384;
} else if (
// EncryptionMethod.A256CBC_HS512 (requires 512 bit key)
encryptionMethod.equals(EncryptionMethod.A256CBC_HS512)
// EncryptionMethod.A256CBC_HS512_DEPRECATED (requires 512 bit key)
|| encryptionMethod.equals(EncryptionMethod.A256CBC_HS512_DEPRECATED)) {
size = 512;
} else if (encryptionMethod.equals(EncryptionMethod.A128GCM)) {
// EncryptionMethod.A128GCM (requires 128 bit key)
size = 128;
} else if (encryptionMethod.equals(EncryptionMethod.A192GCM)) {
// EncryptionMethod.A192GCM (requires 192 bit key)
size = 192;
}
// The Content Encryption Key length must be 128 bits (16 bytes), 192 bits (24 bytes), 256 bits (32 bytes), 384 bits (48 bytes) or 512 bites (64 bytes)
OctetSequenceKey key = new OctetSequenceKeyGenerator(size)
.keyID(keyId)
.keyUse(KeyUse.ENCRYPTION)
.algorithm(jweAlgorithm)
.generate();
algorithmKey = key.toJSONString();
} else if (JWEAlgorithm.Family.RSA.contains(jweAlgorithm)) {
RSAKey key = new RSAKeyGenerator(2048)
.keyID(keyId)
.keyUse(KeyUse.ENCRYPTION)
.algorithm(jweAlgorithm)
.generate();
algorithmKey = key.toJSONString();
} else if (JWEAlgorithm.Family.AES_KW.contains(jweAlgorithm)) {
int size = Integer.parseInt(jweAlgorithm.getName().substring(1, 4));
// The Key Encryption Key length must be 128 bits (16 bytes), 192 bits (24 bytes) or 256 bits (32 bytes)
OctetSequenceKey key = new OctetSequenceKeyGenerator(size)
.keyID(keyId)
.keyUse(KeyUse.ENCRYPTION)
.algorithm(jweAlgorithm)
.generate();
algorithmKey = key.toJSONString();
} else if (JWEAlgorithm.Family.AES_GCM_KW.contains(jweAlgorithm)) {
int size = Integer.parseInt(jweAlgorithm.getName().substring(1, 4));
// The Key Encryption Key length must be 128 bits (16 bytes), 192 bits (24 bytes) or 256 bits (32 bytes)
OctetSequenceKey key = new OctetSequenceKeyGenerator(size)
.keyID(keyId)
.keyUse(KeyUse.ENCRYPTION)
.algorithm(jweAlgorithm)
.generate();
algorithmKey = key.toJSONString();
} else if (JWEAlgorithm.Family.ECDH_ES.contains(jweAlgorithm)) {
if (jweAlgorithm.equals(JWEAlgorithm.ECDH_ES)) {
if (encryptionMethod.equals(EncryptionMethod.A128CBC_HS256_DEPRECATED)
|| encryptionMethod.equals(EncryptionMethod.A256CBC_HS512_DEPRECATED)) {
throw new JOSEException(MessageFormat.format(
"{0} 加解密算法暂不支持 {1} 加密方法", jweAlgorithm.getName(), encryptionMethod.getName()));
}
}
Curve curve = Curve.P_256;
ECKey key = new ECKeyGenerator(curve)
.keyID(keyId)
.keyUse(KeyUse.ENCRYPTION)
.algorithm(jweAlgorithm)
.generate();
algorithmKey = key.toJSONString();
} else if (JWEAlgorithm.Family.PBES2.contains(jweAlgorithm)) {
// OctetSequenceKey key = new OctetSequenceKeyGenerator(2048)
// .keyID(keyId)
// .keyUse(KeyUse.ENCRYPTION)
// .algorithm(jweAlgorithm)
// .generate();
// algorithmKey = key.toJSONString();
algorithmKey = UUID.generate().toString();
}
if (algorithmKey == null) {
throw new JOSEException(MessageFormat.format("暂不支持 {0} 加解密算法", jweAlgorithm));
}
System.out.println(MessageFormat.format("{0} ---> algorithmKey: {1}", jweAlgorithm, algorithmKey));
return algorithmKey;
}

public static JWEObject encrypt(String jwsString, String jweAlgorithmName, String algorithmKey, String encryptionMethod) throws JOSEException, ParseException {
return JweUtils.encrypt(SignedJWT.parse(jwsString), JWEAlgorithm.parse(jweAlgorithmName), algorithmKey, EncryptionMethod.parse(encryptionMethod));
}

public static JWEObject encrypt(SignedJWT signedJwt, JWEAlgorithm jweAlgorithm, String algorithmKey, EncryptionMethod encryptionMethod) throws JOSEException, ParseException {
JWEEncrypter jweEncrypter = null;
if (JWEAlgorithm.Family.PBES2.contains(jweAlgorithm)) {
jweEncrypter = new PasswordBasedEncrypter(algorithmKey, 8, 1000);
} else {
JWKSet jwkSet = JWKSet.parse("{\"keys\":[" + algorithmKey + "]}");
JWK jwk = jwkSet.getKeys().get(0);
if (jweAlgorithm.equals(JWEAlgorithm.DIR)) {
OctetSequenceKey key = (OctetSequenceKey) jwk;
jweEncrypter = new DirectEncrypter(key);
} else if (JWEAlgorithm.Family.RSA.contains(jweAlgorithm)) {
RSAKey key = (RSAKey) jwk;
jweEncrypter = new RSAEncrypter(key);
} else if (JWEAlgorithm.Family.AES_KW.contains(jweAlgorithm)) {
OctetSequenceKey key = (OctetSequenceKey) jwk;
jweEncrypter = new AESEncrypter(key);
} else if (JWEAlgorithm.Family.AES_GCM_KW.contains(jweAlgorithm)) {
OctetSequenceKey key = (OctetSequenceKey) jwk;
jweEncrypter = new AESEncrypter(key);
} else if (JWEAlgorithm.Family.ECDH_ES.contains(jweAlgorithm)) {
ECKey key = (ECKey) jwk;
jweEncrypter = new ECDHEncrypter(key);
}
}
if (jweEncrypter == null) {
throw new JOSEException(MessageFormat.format("暂不支持 {0} 加解密算法", jweAlgorithm));
}
// Create JWE object with signed JWT as payload
JWEObject jweObject = new JWEObject(
// new JWEHeader.Builder(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A256GCM)
new JWEHeader.Builder(jweAlgorithm, encryptionMethod)
// required to indicate nested JWT
.contentType("JWT")
.build(), new Payload(signedJwt));
jweObject.encrypt(jweEncrypter);
return jweObject;
}

public static String serialize(String jwsString, String jweAlgorithmName, String algorithmKey, String encryptionMethod) throws JOSEException, ParseException {
JWEObject encrypt = JweUtils.encrypt(jwsString, jweAlgorithmName, algorithmKey, encryptionMethod);
return encrypt.serialize();
}

public static String serialize(SignedJWT signedJwt, JWEAlgorithm jweAlgorithm, String algorithmKey, EncryptionMethod encryptionMethod) throws JOSEException, ParseException {
JWEObject encrypt = JweUtils.encrypt(signedJwt, jweAlgorithm, algorithmKey, encryptionMethod);
return encrypt.serialize();
}

public static String decrypt(String jweString, String jweAlgorithmName, String algorithmKey) throws ParseException, JOSEException {
return JweUtils.decrypt(JWEObject.parse(jweString), JWEAlgorithm.parse(jweAlgorithmName), algorithmKey);
}

public static String decrypt(JWEObject jweObject, JWEAlgorithm jweAlgorithm, String algorithmKey) throws ParseException, JOSEException {
JWEDecrypter jweDecrypter = null;
if (JWEAlgorithm.Family.PBES2.contains(jweAlgorithm)) {
jweDecrypter = new PasswordBasedDecrypter(algorithmKey);
} else {
JWKSet jwkSet = JWKSet.parse("{\"keys\":[" + algorithmKey + "]}");
JWK jwk = jwkSet.getKeys().get(0);
if (jweAlgorithm.equals(JWEAlgorithm.DIR)) {
OctetSequenceKey key = (OctetSequenceKey) jwk;
jweDecrypter = new DirectDecrypter(key);
} else if (JWEAlgorithm.Family.RSA.contains(jweAlgorithm)) {
RSAKey key = (RSAKey) jwk;
jweDecrypter = new RSADecrypter(key);
} else if (JWEAlgorithm.Family.AES_KW.contains(jweAlgorithm)) {
OctetSequenceKey key = (OctetSequenceKey) jwk;
jweDecrypter = new AESDecrypter(key);
} else if (JWEAlgorithm.Family.AES_GCM_KW.contains(jweAlgorithm)) {
OctetSequenceKey key = (OctetSequenceKey) jwk;
jweDecrypter = new AESDecrypter(key);
} else if (JWEAlgorithm.Family.ECDH_ES.contains(jweAlgorithm)) {
ECKey key = (ECKey) jwk;
jweDecrypter = new ECDHDecrypter(key);
}
}
if (jweDecrypter == null) {
throw new JOSEException(MessageFormat.format("暂不支持 {0} 加解密算法", jweAlgorithm));
}
jweObject.decrypt(jweDecrypter);
return jweObject.getPayload().toSignedJWT().serialize();
}
}

JweUtilsTest 测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import com.nimbusds.jose.EncryptionMethod;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWEAlgorithm;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import org.junit.Before;
import org.junit.Test;

import java.text.MessageFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
* @author yangli
*/
public class JweUtilsTest {
private static final String KEY_ID = "1234567890abcdef";
// Prepare JWT with claims set
private static final JWTClaimsSet claims = new JWTClaimsSet.Builder()
.subject("subject")
.issuer("https://jwt.io")
.expirationTime(new Date(System.currentTimeMillis() + 60 * 1000))
.build();

private static final List<JWEAlgorithm> JWE_ALGORITHMS = new ArrayList<>();
private static final List<EncryptionMethod> METHODS = new ArrayList<>();

private String jwsAlgorithmKey;
private String jwsString;

static {
// 加密算法
JWE_ALGORITHMS.add(JWEAlgorithm.DIR);
JWE_ALGORITHMS.addAll(JWEAlgorithm.Family.RSA);
JWE_ALGORITHMS.addAll(JWEAlgorithm.Family.AES_KW);
JWE_ALGORITHMS.addAll(JWEAlgorithm.Family.AES_GCM_KW);
JWE_ALGORITHMS.addAll(JWEAlgorithm.Family.ECDH_ES);
JWE_ALGORITHMS.addAll(JWEAlgorithm.Family.PBES2);
// 加密方法
METHODS.add(EncryptionMethod.A128CBC_HS256);
METHODS.add(EncryptionMethod.A192CBC_HS384);
METHODS.add(EncryptionMethod.A256CBC_HS512);
METHODS.add(EncryptionMethod.A128GCM);
METHODS.add(EncryptionMethod.A192GCM);
METHODS.add(EncryptionMethod.A256GCM);
// 已经废弃
// METHODS.add(EncryptionMethod.A128CBC_HS256_DEPRECATED);
// METHODS.add(EncryptionMethod.A256CBC_HS512_DEPRECATED);
}

@Before
public void sign() throws JOSEException, ParseException {
String jwsAlgorithmName = JWSAlgorithm.HS256.getName();
jwsAlgorithmKey = JwsUtils.genJwsAlgorithmKey(KEY_ID, jwsAlgorithmName);
SignedJWT signedJwt = JwsUtils.sign(claims, jwsAlgorithmKey);
jwsString = signedJwt.serialize();
boolean verify = JwsUtils.verify(jwsString, jwsAlgorithmKey);
System.out.println(MessageFormat.format("{0} ---> verify: {1}, jwsString: {2}", jwsAlgorithmName, verify, jwsString));
}

@Test
public void testAll() {
String id = "sdfsfsdf";
for (JWEAlgorithm jweAlgorithm : JWE_ALGORITHMS) {
String algorithm = jweAlgorithm.getName();
for (EncryptionMethod method : METHODS) {
System.out.println("---------------------------------------------------------------------------------");
String encryptionMethod = method.getName();
try {
// jwe 加解密
String algorithmKey = JweUtils.genJweAlgorithmKey(id, algorithm, encryptionMethod);
String jweString = JweUtils.serialize(jwsString, algorithm, algorithmKey, encryptionMethod);
String decrypt = JweUtils.decrypt(jweString, algorithm, algorithmKey);
System.out.println(MessageFormat.format(
"{0}.{1} ---> jweString: {2}", algorithm, encryptionMethod, jweString));
System.out.println(MessageFormat.format(
"{0}.{1} ---> jwsString: {2}", algorithm, encryptionMethod, decrypt));

// jws 验证签名
boolean verify = JwsUtils.verify(decrypt, jwsAlgorithmKey);
System.out.println(MessageFormat.format(
"{0}.{1} ---> verify: {2}", algorithm, encryptionMethod, verify));
SignedJWT signedJwt = SignedJWT.parse(decrypt);
System.out.println(MessageFormat.format(
"{0}.{1} ---> jwtClaimsSet: {2}", algorithm, encryptionMethod, signedJwt.getJWTClaimsSet().toString()));
} catch (Exception e) {
System.err.println(MessageFormat.format(
"{0}.{1} ---> messge: {2}", algorithm, encryptionMethod, e.getMessage()));
}
}
}
}
}
  • 本文作者: forever杨
  • 本文链接: https://blog.yl-online.top/posts/d239ec2e.html
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。如果文章内容对你有用,请记录到你的笔记中。本博客站点随时会停止服务,请不要收藏、转载!