1
2
3
4 package com.microsoft.azure.keyvault.webkey;
5
6 import java.io.IOException;
7 import java.math.BigInteger;
8 import java.security.GeneralSecurityException;
9 import java.security.KeyFactory;
10 import java.security.KeyPair;
11 import java.security.KeyPairGenerator;
12 import java.security.NoSuchAlgorithmException;
13 import java.security.PrivateKey;
14 import java.security.Provider;
15 import java.security.PublicKey;
16 import java.security.Security;
17 import java.security.interfaces.ECPrivateKey;
18 import java.security.interfaces.ECPublicKey;
19 import java.security.interfaces.RSAPrivateCrtKey;
20 import java.security.interfaces.RSAPublicKey;
21 import java.security.spec.ECGenParameterSpec;
22 import java.security.spec.ECParameterSpec;
23 import java.security.spec.ECPoint;
24 import java.security.spec.ECPrivateKeySpec;
25 import java.security.spec.ECPublicKeySpec;
26 import java.security.spec.EllipticCurve;
27 import java.security.spec.RSAPrivateCrtKeySpec;
28 import java.security.spec.RSAPrivateKeySpec;
29 import java.security.spec.RSAPublicKeySpec;
30 import java.util.Arrays;
31 import java.util.HashSet;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Set;
35
36 import javax.crypto.SecretKey;
37 import javax.crypto.spec.SecretKeySpec;
38
39 import com.fasterxml.jackson.annotation.JsonAutoDetect;
40 import com.fasterxml.jackson.annotation.JsonIgnore;
41 import com.fasterxml.jackson.annotation.JsonProperty;
42 import com.fasterxml.jackson.core.JsonGenerationException;
43 import com.fasterxml.jackson.databind.JsonMappingException;
44 import com.fasterxml.jackson.databind.ObjectMapper;
45 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
46 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
47 import com.google.common.base.Objects;
48 import com.google.common.collect.ImmutableMap;
49
50
51
52
53 @JsonAutoDetect(getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY, setterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY)
54 public class JsonWebKey {
55
56
57
58
59 @JsonProperty(value = "kid")
60 private String kid;
61
62
63
64
65
66 @JsonProperty(value = "kty")
67 private JsonWebKeyType kty;
68
69
70
71
72 @JsonProperty(value = "key_ops")
73 private List<JsonWebKeyOperation> keyOps;
74
75
76
77
78 @JsonProperty(value = "n")
79 private byte[] n;
80
81
82
83
84 @JsonProperty(value = "e")
85 private byte[] e;
86
87
88
89
90 @JsonProperty(value = "d")
91 private byte[] d;
92
93
94
95
96 @JsonProperty(value = "dp")
97 private byte[] dp;
98
99
100
101
102 @JsonProperty(value = "dq")
103 private byte[] dq;
104
105
106
107
108 @JsonProperty(value = "qi")
109 private byte[] qi;
110
111
112
113
114 @JsonProperty(value = "p")
115 private byte[] p;
116
117
118
119
120 @JsonProperty(value = "q")
121 private byte[] q;
122
123
124
125
126 @JsonProperty(value = "k")
127 private byte[] k;
128
129
130
131
132 @JsonProperty(value = "key_hsm")
133 private byte[] t;
134
135
136
137
138
139 @JsonProperty(value = "crv")
140 private JsonWebKeyCurveName crv;
141
142
143
144
145 @JsonProperty(value = "x")
146 private byte[] x;
147
148
149
150
151 @JsonProperty(value = "y")
152 private byte[] y;
153
154
155
156
157
158
159 @JsonProperty("kid")
160 public String kid() {
161 return this.kid;
162 }
163
164
165
166
167
168
169
170
171 public JsonWebKey withKid(String kid) {
172 this.kid = kid;
173 return this;
174 }
175
176
177
178
179
180
181 @JsonProperty("kty")
182 public JsonWebKeyType kty() {
183 return this.kty;
184 }
185
186
187
188
189
190
191
192
193 public JsonWebKey withKty(JsonWebKeyType kty) {
194 this.kty = kty;
195 return this;
196 }
197
198
199
200
201
202
203 @JsonProperty("key_ops")
204 public List<JsonWebKeyOperation> keyOps() {
205 return this.keyOps;
206 }
207
208
209
210
211
212
213
214
215 public JsonWebKey withKeyOps(List<JsonWebKeyOperation> keyOps) {
216 this.keyOps = keyOps;
217 return this;
218 }
219
220
221
222
223
224
225 @JsonProperty("n")
226 @JsonSerialize(using = Base64UrlJsonSerializer.class)
227 @JsonDeserialize(using = Base64UrlJsonDeserializer.class)
228 public byte[] n() {
229 return ByteExtensions.clone(this.n);
230 }
231
232
233
234
235
236
237
238
239 public JsonWebKey withN(byte[] n) {
240 this.n = ByteExtensions.clone(n);
241 return this;
242 }
243
244
245
246
247
248
249 @JsonProperty("e")
250 @JsonSerialize(using = Base64UrlJsonSerializer.class)
251 @JsonDeserialize(using = Base64UrlJsonDeserializer.class)
252 public byte[] e() {
253 return ByteExtensions.clone(this.e);
254 }
255
256
257
258
259
260
261
262
263 public JsonWebKey withE(byte[] e) {
264 this.e = ByteExtensions.clone(e);
265 return this;
266 }
267
268
269
270
271
272
273 @JsonProperty("d")
274 @JsonSerialize(using = Base64UrlJsonSerializer.class)
275 @JsonDeserialize(using = Base64UrlJsonDeserializer.class)
276 public byte[] d() {
277 return ByteExtensions.clone(this.d);
278 }
279
280
281
282
283
284
285
286
287 public JsonWebKey withD(byte[] d) {
288 this.d = ByteExtensions.clone(d);
289 return this;
290 }
291
292
293
294
295
296
297 @JsonProperty("dp")
298 @JsonSerialize(using = Base64UrlJsonSerializer.class)
299 @JsonDeserialize(using = Base64UrlJsonDeserializer.class)
300 public byte[] dp() {
301 return ByteExtensions.clone(this.dp);
302 }
303
304
305
306
307
308
309
310
311 public JsonWebKey withDp(byte[] dp) {
312 this.dp = ByteExtensions.clone(dp);
313 return this;
314 }
315
316
317
318
319
320
321 @JsonProperty("dq")
322 @JsonSerialize(using = Base64UrlJsonSerializer.class)
323 @JsonDeserialize(using = Base64UrlJsonDeserializer.class)
324 public byte[] dq() {
325 return ByteExtensions.clone(this.dq);
326 }
327
328
329
330
331
332
333
334
335 public JsonWebKey withDq(byte[] dq) {
336 this.dq = ByteExtensions.clone(dq);
337 return this;
338 }
339
340
341
342
343
344
345 @JsonProperty("qi")
346 @JsonSerialize(using = Base64UrlJsonSerializer.class)
347 @JsonDeserialize(using = Base64UrlJsonDeserializer.class)
348 public byte[] qi() {
349 return ByteExtensions.clone(this.qi);
350 }
351
352
353
354
355
356
357
358
359 public JsonWebKey withQi(byte[] qi) {
360 this.qi = ByteExtensions.clone(qi);
361 return this;
362 }
363
364
365
366
367
368
369 @JsonProperty("p")
370 @JsonSerialize(using = Base64UrlJsonSerializer.class)
371 @JsonDeserialize(using = Base64UrlJsonDeserializer.class)
372 public byte[] p() {
373 return ByteExtensions.clone(this.p);
374 }
375
376
377
378
379
380
381
382
383 public JsonWebKey withP(byte[] p) {
384 this.p = ByteExtensions.clone(p);
385 return this;
386 }
387
388
389
390
391
392
393 @JsonProperty("q")
394 @JsonSerialize(using = Base64UrlJsonSerializer.class)
395 @JsonDeserialize(using = Base64UrlJsonDeserializer.class)
396 public byte[] q() {
397 return ByteExtensions.clone(this.q);
398 }
399
400
401
402
403
404
405
406
407 public JsonWebKey withQ(byte[] q) {
408 this.q = ByteExtensions.clone(q);
409 return this;
410 }
411
412
413
414
415
416
417 @JsonProperty("k")
418 @JsonSerialize(using = Base64UrlJsonSerializer.class)
419 @JsonDeserialize(using = Base64UrlJsonDeserializer.class)
420 public byte[] k() {
421 return ByteExtensions.clone(this.k);
422 }
423
424
425
426
427
428
429
430
431 public JsonWebKey withK(byte[] k) {
432 this.k = ByteExtensions.clone(k);
433 return this;
434 }
435
436
437
438
439
440
441 @JsonProperty("key_hsm")
442 @JsonSerialize(using = Base64UrlJsonSerializer.class)
443 @JsonDeserialize(using = Base64UrlJsonDeserializer.class)
444 public byte[] t() {
445 return ByteExtensions.clone(this.t);
446 }
447
448
449
450
451
452
453
454
455 public JsonWebKey withT(byte[] t) {
456 this.t = ByteExtensions.clone(t);
457 return this;
458 }
459
460 @Override
461 public String toString() {
462 ObjectMapper mapper = new ObjectMapper();
463 try {
464 return mapper.writeValueAsString(this);
465 } catch (JsonGenerationException e) {
466 throw new IllegalStateException(e);
467 } catch (JsonMappingException e) {
468 throw new IllegalStateException(e);
469 } catch (IOException e) {
470 throw new IllegalStateException(e);
471 }
472 }
473
474
475
476
477
478
479 @JsonProperty("crv")
480 public JsonWebKeyCurveName crv() {
481 return this.crv;
482 }
483
484
485
486
487
488
489
490
491 public JsonWebKey withCrv(JsonWebKeyCurveName crv) {
492 this.crv = crv;
493 return this;
494 }
495
496
497
498
499
500
501 @JsonProperty("x")
502 @JsonSerialize(using = Base64UrlJsonSerializer.class)
503 @JsonDeserialize(using = Base64UrlJsonDeserializer.class)
504 public byte[] x() {
505 return ByteExtensions.clone(this.x);
506 }
507
508
509
510
511
512
513
514
515 public JsonWebKey withX(byte[] x) {
516 this.x = ByteExtensions.clone(x);
517 return this;
518 }
519
520
521
522
523
524
525 @JsonProperty("y")
526 @JsonSerialize(using = Base64UrlJsonSerializer.class)
527 @JsonDeserialize(using = Base64UrlJsonDeserializer.class)
528 public byte[] y() {
529 return ByteExtensions.clone(this.y);
530 }
531
532
533
534
535
536
537
538
539 public JsonWebKey withY(byte[] y) {
540 this.y = ByteExtensions.clone(y);
541 return this;
542 }
543
544
545
546
547
548
549 private RSAPublicKeySpec getRSAPublicKeySpec() {
550
551 return new RSAPublicKeySpec(toBigInteger(n), toBigInteger(e));
552 }
553
554
555
556
557
558
559 private RSAPrivateKeySpec getRSAPrivateKeySpec() {
560
561 return new RSAPrivateCrtKeySpec(toBigInteger(n), toBigInteger(e), toBigInteger(d), toBigInteger(p),
562 toBigInteger(q), toBigInteger(dp), toBigInteger(dq), toBigInteger(qi));
563 }
564
565
566
567
568
569
570
571
572 private PublicKey getRSAPublicKey(Provider provider) {
573
574 try {
575 RSAPublicKeySpec publicKeySpec = getRSAPublicKeySpec();
576 KeyFactory factory = provider != null ? KeyFactory.getInstance("RSA", provider)
577 : KeyFactory.getInstance("RSA");
578
579 return factory.generatePublic(publicKeySpec);
580 } catch (GeneralSecurityException e) {
581 throw new IllegalStateException(e);
582 }
583 }
584
585
586
587
588
589
590
591
592 private PrivateKey getRSAPrivateKey(Provider provider) {
593
594 try {
595 RSAPrivateKeySpec privateKeySpec = getRSAPrivateKeySpec();
596 KeyFactory factory = provider != null ? KeyFactory.getInstance("RSA", provider)
597 : KeyFactory.getInstance("RSA");
598
599 return factory.generatePrivate(privateKeySpec);
600 } catch (GeneralSecurityException e) {
601 throw new IllegalStateException(e);
602 }
603 }
604
605 private static PublicKey getECPublicKey(ECPoint ecPoint, ECParameterSpec curveSpec, Provider provider) {
606
607 try {
608 ECPublicKeySpec pubSpec = new ECPublicKeySpec(ecPoint, curveSpec);
609 KeyFactory kf = provider != null ? KeyFactory.getInstance("EC", provider)
610 : KeyFactory.getInstance("EC", "SunEC");
611 return (ECPublicKey) kf.generatePublic(pubSpec);
612 } catch (GeneralSecurityException e) {
613 throw new IllegalStateException(e);
614 }
615 }
616
617 private static PrivateKey getECPrivateKey(byte[] d, ECParameterSpec curveSpec, Provider provider) {
618 try {
619 ECPrivateKeySpec priSpec = new ECPrivateKeySpec(new BigInteger(1, d), curveSpec);
620 KeyFactory kf = provider != null ? KeyFactory.getInstance("EC", provider)
621 : KeyFactory.getInstance("EC", "SunEC");
622 return (ECPrivateKey) kf.generatePrivate(priSpec);
623 } catch (GeneralSecurityException e) {
624 throw new IllegalStateException(e);
625 }
626 }
627
628
629
630
631 private void checkRSACompatible() {
632 if (!JsonWebKeyType.RSA.equals(kty) && !JsonWebKeyType.RSA_HSM.equals(kty)) {
633 throw new UnsupportedOperationException("Not an RSA key");
634 }
635 }
636
637 private static byte[] toByteArray(BigInteger n) {
638 byte[] result = n.toByteArray();
639 if (result[0] == 0) {
640
641
642 return Arrays.copyOfRange(result, 1, result.length);
643 }
644 return result;
645 }
646
647 private static BigInteger toBigInteger(byte[] b) {
648 if (b[0] < 0) {
649
650
651
652 byte[] temp = new byte[1 + b.length];
653 System.arraycopy(b, 0, temp, 1, b.length);
654 b = temp;
655 }
656 return new BigInteger(b);
657 }
658
659
660
661
662
663
664
665
666 public static JsonWebKey fromRSA(KeyPair keyPair) {
667
668 RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey) keyPair.getPrivate();
669 JsonWebKey key = null;
670
671 if (privateKey != null) {
672
673 key = new JsonWebKey().withKty(JsonWebKeyType.RSA).withN(toByteArray(privateKey.getModulus()))
674 .withE(toByteArray(privateKey.getPublicExponent()))
675 .withD(toByteArray(privateKey.getPrivateExponent())).withP(toByteArray(privateKey.getPrimeP()))
676 .withQ(toByteArray(privateKey.getPrimeQ())).withDp(toByteArray(privateKey.getPrimeExponentP()))
677 .withDq(toByteArray(privateKey.getPrimeExponentQ()))
678 .withQi(toByteArray(privateKey.getCrtCoefficient()));
679 } else {
680
681 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
682
683 key = new JsonWebKey().withKty(JsonWebKeyType.RSA).withN(toByteArray(publicKey.getModulus()))
684 .withE(toByteArray(publicKey.getPublicExponent())).withD(null).withP(null).withQ(null).withDp(null)
685 .withDq(null).withQi(null);
686 }
687
688 return key;
689 }
690
691
692
693
694
695
696 public KeyPair toRSA() {
697 return this.toRSA(false);
698 }
699
700
701
702
703
704
705
706
707
708
709 public KeyPair toRSA(boolean includePrivateParameters) {
710 return toRSA(includePrivateParameters, null);
711 }
712
713
714
715
716
717
718
719
720
721
722
723
724 public KeyPair toRSA(boolean includePrivateParameters, Provider provider) {
725
726
727 checkRSACompatible();
728
729 if (includePrivateParameters) {
730 return new KeyPair(getRSAPublicKey(provider), getRSAPrivateKey(provider));
731 } else {
732 return new KeyPair(getRSAPublicKey(provider), null);
733 }
734 }
735
736
737
738
739
740
741
742 public KeyPair toEC() {
743 return toEC(false, null);
744 }
745
746
747
748
749
750
751
752
753
754
755 public KeyPair toEC(boolean includePrivateParameters) {
756 return toEC(includePrivateParameters, null);
757 }
758
759
760
761
762
763
764
765
766
767
768
769
770 public KeyPair toEC(boolean includePrivateParameters, Provider provider) {
771
772 if (provider == null) {
773
774 provider = Security.getProvider("SunEC");
775 }
776
777 if (!JsonWebKeyType.EC.equals(kty) && !JsonWebKeyType.EC_HSM.equals(kty)) {
778 throw new IllegalArgumentException("Not an EC key.");
779 }
780
781 try {
782 KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", provider);
783
784 ECGenParameterSpec gps = new ECGenParameterSpec(CURVE_TO_SPEC_NAME.get(crv));
785 kpg.initialize(gps);
786
787
788 KeyPair apair = kpg.generateKeyPair();
789 ECPublicKey apub = (ECPublicKey) apair.getPublic();
790 ECParameterSpec aspec = apub.getParams();
791
792 ECPoint ecPoint = new ECPoint(new BigInteger(1, x), new BigInteger(1, y));
793
794 KeyPair realKeyPair;
795
796 if (includePrivateParameters) {
797 realKeyPair = new KeyPair(getECPublicKey(ecPoint, aspec, provider),
798 getECPrivateKey(d, aspec, provider));
799 } else {
800 realKeyPair = new KeyPair(getECPublicKey(ecPoint, aspec, provider), null);
801 }
802
803 return realKeyPair;
804 } catch (GeneralSecurityException e) {
805 throw new IllegalStateException(e);
806 }
807 }
808
809
810
811
812
813
814
815
816
817
818 public static JsonWebKey fromEC(KeyPair keyPair, Provider provider) {
819
820 ECPublicKey apub = (ECPublicKey) keyPair.getPublic();
821 ECPoint point = apub.getW();
822 ECPrivateKey apriv = (ECPrivateKey) keyPair.getPrivate();
823
824 if (apriv != null) {
825 return new JsonWebKey().withKty(JsonWebKeyType.EC).withCrv(getCurveFromKeyPair(keyPair, provider))
826 .withX(point.getAffineX().toByteArray()).withY(point.getAffineY().toByteArray())
827 .withD(apriv.getS().toByteArray()).withKty(JsonWebKeyType.EC);
828 } else {
829 return new JsonWebKey().withKty(JsonWebKeyType.EC).withCrv(getCurveFromKeyPair(keyPair, provider))
830 .withX(point.getAffineX().toByteArray()).withY(point.getAffineY().toByteArray())
831 .withKty(JsonWebKeyType.EC);
832 }
833 }
834
835
836 private static JsonWebKeyCurveName getCurveFromKeyPair(KeyPair keyPair, Provider provider) {
837
838 try {
839 ECPublicKey key = (ECPublicKey) keyPair.getPublic();
840 ECParameterSpec spec = key.getParams();
841 EllipticCurve crv = spec.getCurve();
842
843 List<JsonWebKeyCurveName> curveList = Arrays.asList(JsonWebKeyCurveName.P_256, JsonWebKeyCurveName.P_384,
844 JsonWebKeyCurveName.P_521, JsonWebKeyCurveName.P_256K);
845
846 for (JsonWebKeyCurveName curve : curveList) {
847 ECGenParameterSpec gps = new ECGenParameterSpec(CURVE_TO_SPEC_NAME.get(curve));
848 KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", provider);
849 kpg.initialize(gps);
850
851
852 KeyPair apair = kpg.generateKeyPair();
853 ECPublicKey apub = (ECPublicKey) apair.getPublic();
854 ECParameterSpec aspec = apub.getParams();
855 EllipticCurve acurve = aspec.getCurve();
856
857
858 if (acurve.equals(crv)) {
859 return curve;
860 }
861 }
862
863
864 throw new NoSuchAlgorithmException("Curve not supported.");
865 } catch (GeneralSecurityException e) {
866 throw new IllegalStateException(e);
867 }
868 }
869
870
871
872
873
874
875
876
877 public static JsonWebKey fromAes(SecretKey secretKey) {
878 if (secretKey == null) {
879 return null;
880 }
881
882 return new JsonWebKey().withK(secretKey.getEncoded()).withKty(JsonWebKeyType.OCT);
883 }
884
885
886
887
888
889
890 public SecretKey toAes() {
891 if (k == null) {
892 return null;
893 }
894
895 SecretKey secretKey = new SecretKeySpec(k, "AES");
896 return secretKey;
897 }
898
899 @Override
900 public boolean equals(Object obj) {
901 if (obj == this) {
902 return true;
903 }
904 if (obj instanceof JsonWebKey) {
905 return this.equals((JsonWebKey) obj);
906 }
907 return super.equals(obj);
908 }
909
910
911
912
913
914
915
916
917
918 public boolean equals(JsonWebKey jwk) {
919 if (jwk == null) {
920 return false;
921 }
922
923 if (!Objects.equal(kid, jwk.kid)) {
924 return false;
925 }
926
927 if (!Objects.equal(kty, jwk.kty)) {
928 return false;
929 }
930
931 if (!Objects.equal(keyOps, jwk.keyOps)) {
932 return false;
933 }
934
935 if (!Objects.equal(crv, jwk.crv)) {
936 return false;
937 }
938
939 if (!Arrays.equals(k, jwk.k)) {
940 return false;
941 }
942
943
944 if (!Arrays.equals(n, jwk.n)) {
945 return false;
946 }
947 if (!Arrays.equals(e, jwk.e)) {
948 return false;
949 }
950
951
952 if (!Arrays.equals(d, jwk.d)) {
953 return false;
954 }
955 if (!Arrays.equals(dp, jwk.dp)) {
956 return false;
957 }
958 if (!Arrays.equals(dq, jwk.dq)) {
959 return false;
960 }
961 if (!Arrays.equals(qi, jwk.qi)) {
962 return false;
963 }
964 if (!Arrays.equals(p, jwk.p)) {
965 return false;
966 }
967 if (!Arrays.equals(q, jwk.q)) {
968 return false;
969 }
970 if (!Arrays.equals(x, jwk.x)) {
971 return false;
972 }
973 if (!Arrays.equals(y, jwk.y)) {
974 return false;
975 }
976
977
978 if (!Arrays.equals(t, jwk.t)) {
979 return false;
980 }
981
982 return true;
983 }
984
985
986
987
988
989
990 public boolean hasPrivateKey() {
991
992 if (JsonWebKeyType.OCT.equals(kty)) {
993 return k != null;
994 } else if (JsonWebKeyType.RSA.equals(kty) || JsonWebKeyType.RSA_HSM.equals(kty)) {
995 return (d != null && dp != null && dq != null && qi != null && p != null && q != null);
996 } else if (JsonWebKeyType.EC.equals(kty) || JsonWebKeyType.EC_HSM.equals(kty)) {
997 return (d != null);
998 }
999
1000 return false;
1001 }
1002
1003
1004
1005
1006
1007
1008 @JsonIgnore
1009 public boolean isValid() {
1010 if (kty == null) {
1011 return false;
1012 }
1013
1014 if (keyOps != null) {
1015 final Set<JsonWebKeyOperation> set = new HashSet<JsonWebKeyOperation>(JsonWebKeyOperation.ALL_OPERATIONS);
1016 for (int i = 0; i < keyOps.size(); i++) {
1017 if (!set.contains(keyOps.get(i))) {
1018 return false;
1019 }
1020 }
1021 }
1022
1023 if (JsonWebKeyType.OCT.equals(kty)) {
1024 return isValidOctet();
1025 } else if (JsonWebKeyType.RSA.equals(kty)) {
1026 return isValidRsa();
1027 } else if (JsonWebKeyType.RSA_HSM.equals(kty)) {
1028 return isValidRsaHsm();
1029 } else if (JsonWebKeyType.EC.equals(kty)) {
1030 return isValidEc();
1031 } else if (JsonWebKeyType.EC_HSM.equals(kty)) {
1032 return isValidEcHsm();
1033 }
1034
1035 return false;
1036 }
1037
1038 private boolean isValidOctet() {
1039 if (k != null) {
1040 return true;
1041 }
1042 return false;
1043 }
1044
1045 private boolean isValidRsa() {
1046 if (n == null || e == null) {
1047 return false;
1048 }
1049
1050 return hasPrivateKey() || (d == null && dp == null && dq == null && qi == null && p == null && q == null);
1051 }
1052
1053 private boolean isValidRsaHsm() {
1054
1055 if ((n == null && e != null) || (n != null && e == null)) {
1056 return false;
1057 }
1058
1059
1060 if (hasPrivateKey()) {
1061 return false;
1062 }
1063
1064
1065 boolean tokenParameters = t != null;
1066 boolean publicParameters = (n != null && e != null);
1067
1068 if (tokenParameters && publicParameters) {
1069 return false;
1070 }
1071
1072 return (tokenParameters || publicParameters);
1073 }
1074
1075 private boolean isValidEc() {
1076 boolean ecPointParameters = (x != null && y != null);
1077 if (!ecPointParameters || crv == null) {
1078 return false;
1079 }
1080
1081 return hasPrivateKey() || (d == null);
1082 }
1083
1084 private boolean isValidEcHsm() {
1085
1086 boolean ecPointParameters = (x != null && y != null);
1087 if ((ecPointParameters && crv == null) || (!ecPointParameters && crv != null)) {
1088 return false;
1089 }
1090
1091
1092 if (hasPrivateKey()) {
1093 return false;
1094 }
1095
1096
1097 boolean publicParameters = (ecPointParameters && crv != null);
1098 boolean tokenParameters = t != null;
1099
1100 if (tokenParameters && publicParameters) {
1101 return false;
1102 }
1103
1104 return (tokenParameters || publicParameters);
1105 }
1106
1107
1108
1109
1110 public void clearMemory() {
1111 zeroArray(k);
1112 k = null;
1113 zeroArray(n);
1114 n = null;
1115 zeroArray(e);
1116 e = null;
1117 zeroArray(d);
1118 d = null;
1119 zeroArray(dp);
1120 dp = null;
1121 zeroArray(dq);
1122 dq = null;
1123 zeroArray(qi);
1124 qi = null;
1125 zeroArray(p);
1126 p = null;
1127 zeroArray(q);
1128 q = null;
1129 zeroArray(t);
1130 t = null;
1131 zeroArray(x);
1132 x = null;
1133 zeroArray(y);
1134 y = null;
1135 }
1136
1137 private static void zeroArray(byte[] bytes) {
1138 if (bytes != null) {
1139 Arrays.fill(bytes, (byte) 0);
1140 }
1141 }
1142
1143 @Override
1144 public int hashCode() {
1145 int hashCode = 48313;
1146 if (kid != null) {
1147 hashCode += kid.hashCode();
1148 }
1149
1150 if (JsonWebKeyType.OCT.equals(kty)) {
1151 hashCode += hashCode(k);
1152 } else if (JsonWebKeyType.RSA.equals(kty)) {
1153 hashCode += hashCode(n);
1154 } else if (JsonWebKeyType.EC.equals(kty)) {
1155 hashCode += hashCode(x);
1156 hashCode += hashCode(y);
1157 hashCode += crv.hashCode();
1158 } else if (JsonWebKeyType.RSA_HSM.equals(kty) || JsonWebKeyType.EC_HSM.equals(kty)) {
1159 hashCode += hashCode(t);
1160 }
1161
1162 return hashCode;
1163 }
1164
1165 private static int hashCode(byte[] obj) {
1166 int hashCode = 0;
1167
1168 if (obj == null || obj.length == 0) {
1169 return 0;
1170 }
1171
1172 for (int i = 0; i < obj.length; i++) {
1173 hashCode = (hashCode << 3) | (hashCode >> 29) ^ obj[i];
1174 }
1175 return hashCode;
1176 }
1177
1178 private static final Map<JsonWebKeyCurveName, String> CURVE_TO_SPEC_NAME = ImmutableMap
1179 .<JsonWebKeyCurveName, String>builder().put(JsonWebKeyCurveName.P_256, "secp256r1")
1180 .put(JsonWebKeyCurveName.P_384, "secp384r1").put(JsonWebKeyCurveName.P_521, "secp521r1")
1181 .put(JsonWebKeyCurveName.P_256K, "secp256k1").build();
1182 }
1183