001 package com.nimbusds.jose.jwk; 002 003 004 import java.math.BigInteger; 005 import java.security.KeyFactory; 006 import java.security.KeyPair; 007 import java.security.NoSuchAlgorithmException; 008 import java.security.interfaces.RSAMultiPrimePrivateCrtKey; 009 import java.security.interfaces.RSAPrivateCrtKey; 010 import java.security.interfaces.RSAPrivateKey; 011 import java.security.interfaces.RSAPublicKey; 012 import java.security.spec.InvalidKeySpecException; 013 import java.security.spec.RSAMultiPrimePrivateCrtKeySpec; 014 import java.security.spec.RSAOtherPrimeInfo; 015 import java.security.spec.RSAPrivateCrtKeySpec; 016 import java.security.spec.RSAPrivateKeySpec; 017 import java.security.spec.RSAPublicKeySpec; 018 import java.text.ParseException; 019 import java.util.ArrayList; 020 import java.util.Collections; 021 import java.util.List; 022 023 import net.jcip.annotations.Immutable; 024 025 import net.minidev.json.JSONArray; 026 import net.minidev.json.JSONObject; 027 028 import com.nimbusds.jose.Algorithm; 029 import com.nimbusds.jose.util.Base64URL; 030 import com.nimbusds.jose.util.JSONObjectUtils; 031 032 033 /** 034 * Public and private {@link KeyType#RSA RSA} JSON Web Key (JWK). This class is 035 * immutable. 036 * 037 * <p>Provides RSA JWK import from / export to the following standard Java 038 * interfaces and classes: 039 * 040 * <ul> 041 * <li>{@code java.security.interfaces.RSAPublicKey} 042 * <li>{@code java.security.interfaces.RSAPrivateKey} 043 * <ul> 044 * <li>{@code java.security.interfaces.RSAPrivateCrtKey} 045 * <li>{@code java.security.interfaces.RSAMultiPrimePrivateCrtKey} 046 * </ul> 047 * <li>{@code java.security.KeyPair} 048 * </ul> 049 * 050 * <p>Example JSON object representation of a public RSA JWK: 051 * 052 * <pre> 053 * { 054 * "kty" : "RSA", 055 * "n" : "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx 056 * 4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMs 057 * tn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2 058 * QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbI 059 * SD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqb 060 * w0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw", 061 * "e" : "AQAB", 062 * "alg" : "RS256", 063 * "kid" : "2011-04-29" 064 * } 065 * </pre> 066 * 067 * <p>Example JSON object representation of a public and private RSA JWK (with 068 * both the first and the second private key representations): 069 * 070 * <pre> 071 * { 072 * "kty" : "RSA", 073 * "n" : "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx 074 * 4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMs 075 * tn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2 076 * QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbI 077 * SD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqb 078 * w0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw", 079 * "e" : "AQAB", 080 * "d" : "X4cTteJY_gn4FYPsXB8rdXix5vwsg1FLN5E3EaG6RJoVH-HLLKD9 081 * M7dx5oo7GURknchnrRweUkC7hT5fJLM0WbFAKNLWY2vv7B6NqXSzUvxT0_YSfqij 082 * wp3RTzlBaCxWp4doFk5N2o8Gy_nHNKroADIkJ46pRUohsXywbReAdYaMwFs9tv8d 083 * _cPVY3i07a3t8MN6TNwm0dSawm9v47UiCl3Sk5ZiG7xojPLu4sbg1U2jx4IBTNBz 084 * nbJSzFHK66jT8bgkuqsk0GjskDJk19Z4qwjwbsnn4j2WBii3RL-Us2lGVkY8fkFz 085 * me1z0HbIkfz0Y6mqnOYtqc0X4jfcKoAC8Q", 086 * "p" : "83i-7IvMGXoMXCskv73TKr8637FiO7Z27zv8oj6pbWUQyLPQBQxtPV 087 * nwD20R-60eTDmD2ujnMt5PoqMrm8RfmNhVWDtjjMmCMjOpSXicFHj7XOuVIYQyqV 088 * WlWEh6dN36GVZYk93N8Bc9vY41xy8B9RzzOGVQzXvNEvn7O0nVbfs", 089 * "q" : "3dfOR9cuYq-0S-mkFLzgItgMEfFzB2q3hWehMuG0oCuqnb3vobLyum 090 * qjVZQO1dIrdwgTnCdpYzBcOfW5r370AFXjiWft_NGEiovonizhKpo9VVS78TzFgx 091 * kIdrecRezsZ-1kYd_s1qDbxtkDEgfAITAG9LUnADun4vIcb6yelxk", 092 * "dp" : "G4sPXkc6Ya9y8oJW9_ILj4xuppu0lzi_H7VTkS8xj5SdX3coE0oim 093 * YwxIi2emTAue0UOa5dpgFGyBJ4c8tQ2VF402XRugKDTP8akYhFo5tAA77Qe_Nmtu 094 * YZc3C3m3I24G2GvR5sSDxUyAN2zq8Lfn9EUms6rY3Ob8YeiKkTiBj0", 095 * "dq" : "s9lAH9fggBsoFR8Oac2R_E2gw282rT2kGOAhvIllETE1efrA6huUU 096 * vMfBcMpn8lqeW6vzznYY5SSQF7pMdC_agI3nG8Ibp1BUb0JUiraRNqUfLhcQb_d9 097 * GF4Dh7e74WbRsobRonujTYN1xCaP6TO61jvWrX-L18txXw494Q_cgk", 098 * "qi" : "GyM_p6JrXySiz1toFgKbWV-JdI3jQ4ypu9rbMWx3rQJBfmt0FoYzg 099 * UIZEVFEcOqwemRN81zoDAaa-Bk0KWNGDjJHZDdDmFhW3AN7lI-puxk_mHZGJ11rx 100 * yR8O55XLSe3SPmRfKwZI6yU24ZxvQKFYItdldUKGzO6Ia6zTKhAVRU", 101 * "alg" : "RS256", 102 * "kid" : "2011-04-29" 103 * } 104 * </pre> 105 * 106 * <p>See RFC 3447. 107 * 108 * <p>See http://en.wikipedia.org/wiki/RSA_%28algorithm%29 109 * 110 * @author Vladimir Dzhuvinov 111 * @author Justin Richer 112 * @version $version$ (2013-03-27) 113 */ 114 @Immutable 115 public final class RSAKey extends JWK { 116 117 118 /** 119 * Other Primes Info, represents the private {@code oth} parameter of a 120 * RSA JWK. This class is immutable. 121 * 122 * @author Justin Richer 123 */ 124 @Immutable 125 public static class OtherPrimesInfo { 126 127 128 /** 129 * The prime factor. 130 */ 131 private final Base64URL r; 132 133 134 /** 135 * The factor Chinese Remainder Theorem (CRT) exponent. 136 */ 137 private final Base64URL d; 138 139 140 /** 141 * The factor Chinese Remainder Theorem (CRT) coefficient. 142 */ 143 private final Base64URL t; 144 145 146 /** 147 * Creates a new JWK Other Primes Info with the specified 148 * parameters. 149 * 150 * @param r The prime factor. Must not be {@code null}. 151 * @param d The factor Chinese Remainder Theorem (CRT) 152 * exponent. Must not be {@code null}. 153 * @param t The factor Chinese Remainder Theorem (CRT) 154 * coefficient. Must not be {@code null}. 155 */ 156 public OtherPrimesInfo(final Base64URL r, final Base64URL d, final Base64URL t) { 157 158 if (r == null) { 159 160 throw new IllegalArgumentException("The prime factor must not be null"); 161 } 162 163 this.r = r; 164 165 if (d == null) { 166 167 throw new IllegalArgumentException("The factor CRT exponent must not be null"); 168 } 169 170 this.d = d; 171 172 if (t == null) { 173 174 throw new IllegalArgumentException("The factor CRT coefficient must not be null"); 175 } 176 177 this.t = t; 178 } 179 180 181 /** 182 * Creates a new JWK Other Primes Info from the specified 183 * {@code java.security.spec.RSAOtherPrimeInfo} instance. 184 * 185 * @param oth The RSA Other Primes Info instance. Must not be 186 * {@code null}. 187 */ 188 public OtherPrimesInfo(final RSAOtherPrimeInfo oth) { 189 190 r = Base64URL.encode(oth.getPrime()); 191 d = Base64URL.encode(oth.getExponent()); 192 t = Base64URL.encode(oth.getCrtCoefficient()); 193 } 194 195 196 /** 197 * Gets the prime factor ({@code r}). 198 * 199 * @return The prime factor. 200 */ 201 public Base64URL getPrimeFactor() { 202 203 return r; 204 } 205 206 207 /** 208 * Gets factor Chinese Remainder Theorem (CRT) exponent 209 * ({@code d}). 210 * 211 * @return The factor Chinese Remainder Theorem (CRT) exponent. 212 */ 213 public Base64URL getFactorCRTExponent() { 214 215 return d; 216 } 217 218 219 /** 220 * The factor Chinese Remainder Theorem (CRT) coefficient 221 * ({@code t}). 222 * 223 * @return The factor Chinese Remainder Theorem (CRT) 224 * coefficient. 225 */ 226 public Base64URL getFactorCRTCoefficient() { 227 228 return t; 229 } 230 231 232 /** 233 * Converts the specified array of 234 * {@code java.security.spec.RSAOtherPrimeInfo} instances to a 235 * list of JWK Other Prime Infos. 236 * 237 * @param othArray Array of RSA Other Primes Info instances. 238 * May be be {@code null}. 239 * 240 * @return The corresponding list of JWK Other Prime Infos, or 241 * empty list of the array was {@code null}. 242 */ 243 public static List<OtherPrimesInfo> toList(final RSAOtherPrimeInfo[] othArray) { 244 245 List<OtherPrimesInfo> list = new ArrayList<OtherPrimesInfo>(); 246 247 if (othArray == null) { 248 249 // Return empty list 250 return list; 251 } 252 253 for (RSAOtherPrimeInfo oth: othArray) { 254 255 list.add(new OtherPrimesInfo(oth)); 256 } 257 258 return list; 259 } 260 } 261 262 263 // Public RSA params 264 265 /** 266 * The modulus value for the RSA key. 267 */ 268 private final Base64URL n; 269 270 271 /** 272 * The public exponent of the RSA key. 273 */ 274 private final Base64URL e; 275 276 277 // Private RSA params, 1st representation 278 279 /** 280 * The private exponent of the RSA key. 281 */ 282 private final Base64URL d; 283 284 285 // Private RSA params, 2nd representation 286 287 /** 288 * The first prime factor of the private RSA key. 289 */ 290 private final Base64URL p; 291 292 293 /** 294 * The second prime factor of the private RSA key. 295 */ 296 private final Base64URL q; 297 298 299 /** 300 * The first factor Chinese Remainder Theorem exponent of the private 301 * RSA key. 302 */ 303 private final Base64URL dp; 304 305 306 /** 307 * The second factor Chinese Remainder Theorem exponent of the private 308 * RSA key. 309 */ 310 private final Base64URL dq; 311 312 313 /** 314 * The first Chinese Remainder Theorem coefficient of the private RSA 315 * key. 316 */ 317 private final Base64URL qi; 318 319 320 /** 321 * The other primes information of the private RSA key, should the 322 * exist. When only two primes have been used (the normal case), this 323 * parameter MUST be omitted. When three or more primes have been used, 324 * the number of array elements MUST be the number of primes used minus 325 * two. Each array element MUST be an object with the following 326 * members: 327 */ 328 private final List<OtherPrimesInfo> oth; 329 330 331 /** 332 * Creates a new public RSA JSON Web Key (JWK) with the specified 333 * parameters. 334 * 335 * @param n The the modulus value for the public RSA key. It is 336 * represented as the Base64URL encoding of value's big 337 * endian representation. Must not be {@code null}. 338 * @param e The exponent value for the public RSA key. It is 339 * represented as the Base64URL encoding of value's big 340 * endian representation. Must not be {@code null}. 341 * @param use The key use, {@code null} if not specified. 342 * @param alg The intended JOSE algorithm for the key, {@code null} if 343 * not specified. 344 * @param kid The key ID. {@code null} if not specified. 345 */ 346 public RSAKey(final Base64URL n, final Base64URL e, final Use use, 347 final Algorithm alg, final String kid) { 348 349 // Call the full constructor, all private key parameters are null 350 this(n, e, null, null, null, null, null, null, null, use, alg, kid); 351 } 352 353 354 /** 355 * Creates a new public / private RSA JSON Web Key (JWK) with the 356 * specified parameters. The private RSA key is specified by its first 357 * representation (see RFC 3447, section 3.2). 358 * 359 * @param n The the modulus value for the public RSA key. It is 360 * represented as the Base64URL encoding of value's big 361 * endian representation. Must not be {@code null}. 362 * @param e The exponent value for the public RSA key. It is 363 * represented as the Base64URL encoding of value's big 364 * endian representation. Must not be {@code null}. 365 * @param d The private exponent. It is represented as the Base64URL 366 * encoding of the value's big endian representation. Must 367 * not be {@code null}. 368 * @param use The key use, {@code null} if not specified. 369 * @param alg The intended JOSE algorithm for the key, {@code null} if 370 * not specified. 371 * @param kid The key ID. {@code null} if not specified. 372 */ 373 public RSAKey(final Base64URL n, final Base64URL e, final Base64URL d, 374 final Use use, final Algorithm alg, final String kid) { 375 376 // Call the full constructor, the second private representation 377 // parameters are all null 378 this(n, e, d, null, null, null, null, null, null, use, alg, kid); 379 380 if (d == null) { 381 throw new IllegalArgumentException("The private exponent must not be null"); 382 } 383 } 384 385 386 /** 387 * Creates a new public / private RSA JSON Web Key (JWK) with the 388 * specified parameters. The private RSA key is specified by its 389 * second representation (see RFC 3447, section 3.2). 390 * 391 * @param n The the modulus value for the public RSA key. It is 392 * represented as the Base64URL encoding of value's big 393 * endian representation. Must not be {@code null}. 394 * @param e The exponent value for the public RSA key. It is 395 * represented as the Base64URL encoding of value's big 396 * endian representation. Must not be {@code null}. 397 * @param p The first prime factor. It is represented as the 398 * Base64URL encoding of the value's big endian 399 * representation. Must not be {@code null}. 400 * @param q The second prime factor. It is represented as the 401 * Base64URL encoding of the value's big endian 402 * representation. Must not be {@code null}. 403 * @param dp The first factor Chinese Remainder Theorem exponent. It 404 * is represented as the Base64URL encoding of the value's 405 * big endian representation. Must not be {@code null}. 406 * @param dq The second factor Chinese Remainder Theorem exponent. It 407 * is represented as the Base64URL encoding of the value's 408 * big endian representation. Must not be {@code null}. 409 * @param qi The first Chinese Remainder Theorem coefficient. It is 410 * represented as the Base64URL encoding of the value's big 411 * endian representation. Must not be {@code null}. 412 * @param oth The other primes information, should they exist, 413 * {@code null} or an empty list if not specified. 414 * @param use The key use, {@code null} if not specified. 415 * @param alg The intended JOSE algorithm for the key, {@code null} if 416 * not specified. 417 * @param kid The key ID. {@code null} if not specified. 418 */ 419 public RSAKey(final Base64URL n, final Base64URL e, 420 final Base64URL p, final Base64URL q, 421 final Base64URL dp, final Base64URL dq, final Base64URL qi, 422 final List<OtherPrimesInfo> oth, 423 final Use use, final Algorithm alg, final String kid) { 424 425 // Call the full constructor, the first private representation 426 // d param is null 427 this(n, e, null, p, q, dp, dq, qi, oth, use, alg, kid); 428 429 if (p == null) { 430 throw new IllegalArgumentException("The first prime factor must not be null"); 431 } 432 433 if (q == null) { 434 throw new IllegalArgumentException("The second prime factor must not be null"); 435 } 436 437 if (dp == null) { 438 throw new IllegalArgumentException("The first factor CRT exponent must not be null"); 439 } 440 441 if (dq == null) { 442 throw new IllegalArgumentException("The second factor CRT exponent must not be null"); 443 } 444 445 if (qi == null) { 446 throw new IllegalArgumentException("The first CRT coefficient must not be null"); 447 } 448 } 449 450 451 /** 452 * Creates a new public / private RSA JSON Web Key (JWK) with the 453 * specified parameters. The private RSA key is specified by both its 454 * first and second representations (see RFC 3447, section 3.2). 455 * 456 * <p>A valid first private RSA key representation must specify the 457 * {@code d}. 458 * 459 * <p>A valid second private RSA key representation must specify all 460 * required Chinese Remained Theorem (CRT) parameters - {@code p}, 461 * {@code q}, {@code dp}, {@code dq} and {@code qi}, else an 462 * {@link java.lang.IllegalArgumentException} will be thrown. 463 * 464 * @param n The the modulus value for the public RSA key. It is 465 * represented as the Base64URL encoding of value's big 466 * endian representation. Must not be {@code null}. 467 * @param e The exponent value for the public RSA key. It is 468 * represented as the Base64URL encoding of value's big 469 * endian representation. Must not be {@code null}. 470 * @param d The private exponent. It is represented as the Base64URL 471 * encoding of the value's big endian representation. May 472 * be {@code null}. 473 * @param p The first prime factor. It is represented as the 474 * Base64URL encoding of the value's big endian 475 * representation. May be {@code null}. 476 * @param q The second prime factor. It is represented as the 477 * Base64URL encoding of the value's big endian 478 * representation. May be {@code null}. 479 * @param dp The first factor Chinese Remainder Theorem exponent. It 480 * is represented as the Base64URL encoding of the value's 481 * big endian representation. May be {@code null}. 482 * @param dq The second factor Chinese Remainder Theorem exponent. It 483 * is represented as the Base64URL encoding of the value's 484 * big endian representation. May be {@code null}. 485 * @param qi The first Chinese Remainder Theorem coefficient. It is 486 * represented as the Base64URL encoding of the value's big 487 * endian representation. May be {@code null}. 488 * @param oth The other primes information, should they exist, 489 * {@code null} or an empty list if not specified. 490 * @param use The key use, {@code null} if not specified. 491 * @param alg The intended JOSE algorithm for the key, {@code null} if 492 * not specified. 493 * @param kid The key ID. {@code null} if not specified. 494 */ 495 public RSAKey(final Base64URL n, final Base64URL e, 496 final Base64URL d, 497 final Base64URL p, final Base64URL q, 498 final Base64URL dp, final Base64URL dq, final Base64URL qi, 499 final List<OtherPrimesInfo> oth, 500 final Use use, final Algorithm alg, final String kid) { 501 502 super(KeyType.RSA, use, alg, kid); 503 504 505 // Ensure the public params are defined 506 507 if (n == null) { 508 throw new IllegalArgumentException("The modulus value must not be null"); 509 } 510 511 this.n = n; 512 513 514 if (e == null) { 515 throw new IllegalArgumentException("The public exponent value must not be null"); 516 } 517 518 this.e = e; 519 520 521 // Private params, 1st representation 522 523 this.d = d; 524 525 526 // Private params, 2nd representation, check for consistency 527 528 if (p != null && q != null && dp != null && dq != null && qi != null) { 529 530 // CRT params fully specified 531 532 this.p = p; 533 this.q = q; 534 this.dp = dp; 535 this.dq = dq; 536 this.qi = qi; 537 538 // Other RSA primes info optional, default to empty list 539 if (oth != null) { 540 541 this.oth = Collections.unmodifiableList(oth); 542 543 } else { 544 545 this.oth = Collections.emptyList(); 546 } 547 548 } else if (p == null && q == null && dp == null && dq == null && qi == null && oth == null) { 549 550 // No CRT params 551 this.p = null; 552 this.q = null; 553 this.dp = null; 554 this.dq = null; 555 this.qi = null; 556 557 this.oth = Collections.emptyList(); 558 559 } else { 560 561 if (p == null) { 562 throw new IllegalArgumentException("Incomplete second private (CRT) representation: The first prime factor must not be null"); 563 } 564 565 if (q == null) { 566 throw new IllegalArgumentException("Incomplete second private (CRT) representation: The second prime factor must not be null"); 567 } 568 569 if (dp == null) { 570 throw new IllegalArgumentException("Incomplete second private (CRT) representation: The first factor CRT exponent must not be null"); 571 } 572 573 if (dq == null) { 574 throw new IllegalArgumentException("Incomplete second private (CRT) representation: The second factor CRT exponent must not be null"); 575 } 576 577 if (qi == null) { 578 throw new IllegalArgumentException("Incomplete second private (CRT) representation: The first CRT coefficient must not be null"); 579 } 580 581 // We shouldn't really fall through 582 throw new IllegalArgumentException("Incomplete second private (CRT) representation"); 583 } 584 } 585 586 587 /** 588 * Creates a new public RSA JSON Web Key (JWK) with the specified 589 * parameters. 590 * 591 * @param pub The public RSA key to represent. Must not be 592 * {@code null}. 593 * @param use The key use, {@code null} if not specified. 594 * @param alg The intended JOSE algorithm for the key, {@code null} if 595 * not specified. 596 * @param kid The key ID. {@code null} if not specified. 597 */ 598 public RSAKey(final RSAPublicKey pub, final Use use, final Algorithm alg, final String kid) { 599 600 this(Base64URL.encode(pub.getModulus()), 601 Base64URL.encode(pub.getPublicExponent()), 602 use, alg, kid); 603 } 604 605 606 /** 607 * Creates a new public / private RSA JSON Web Key (JWK) with the 608 * specified parameters. The private RSA key is specified by its first 609 * representation (see RFC 3447, section 3.2). 610 * 611 * @param pub The public RSA key to represent. Must not be 612 * {@code null}. 613 * @param priv The private RSA key to represent. Must not be 614 * {@code null}. 615 * @param use The key use, {@code null} if not specified. 616 * @param alg The intended JOSE algorithm for the key, {@code null} if 617 * not specified. 618 * @param kid The key ID. {@code null} if not specified. 619 */ 620 public RSAKey(final RSAPublicKey pub, final RSAPrivateKey priv, 621 final Use use, final Algorithm alg, final String kid) { 622 623 this(Base64URL.encode(pub.getModulus()), 624 Base64URL.encode(pub.getPublicExponent()), 625 Base64URL.encode(priv.getPrivateExponent()), 626 use, alg, kid); 627 } 628 629 630 /** 631 * Creates a new public / private RSA JSON Web Key (JWK) with the 632 * specified parameters. The private RSA key is specified by its second 633 * representation (see RFC 3447, section 3.2). 634 * 635 * @param pub The public RSA key to represent. Must not be 636 * {@code null}. 637 * @param priv The private RSA key to represent. Must not be 638 * {@code null}. 639 * @param use The key use, {@code null} if not specified. 640 * @param alg The intended JOSE algorithm for the key, {@code null} if 641 * not specified. 642 * @param kid The key ID. {@code null} if not specified. 643 */ 644 public RSAKey(final RSAPublicKey pub, final RSAPrivateCrtKey priv, 645 final Use use, final Algorithm alg, final String kid) { 646 647 this(Base64URL.encode(pub.getModulus()), 648 Base64URL.encode(pub.getPublicExponent()), 649 Base64URL.encode(priv.getPrivateExponent()), 650 Base64URL.encode(priv.getPrimeP()), 651 Base64URL.encode(priv.getPrimeQ()), 652 Base64URL.encode(priv.getPrimeExponentP()), 653 Base64URL.encode(priv.getPrimeExponentQ()), 654 Base64URL.encode(priv.getCrtCoefficient()), 655 null, 656 use, alg, kid); 657 } 658 659 660 /** 661 * Creates a new public / private RSA JSON Web Key (JWK) with the 662 * specified parameters. The private RSA key is specified by its second 663 * representation, with optional other primes info (see RFC 3447, 664 * section 3.2). 665 * 666 * @param pub The public RSA key to represent. Must not be 667 * {@code null}. 668 * @param priv The private RSA key to represent. Must not be 669 * {@code null}. 670 * @param use The key use, {@code null} if not specified. 671 * @param alg The intended JOSE algorithm for the key, {@code null} if 672 * not specified. 673 * @param kid The key ID. {@code null} if not specified. 674 */ 675 public RSAKey(final RSAPublicKey pub, final RSAMultiPrimePrivateCrtKey priv, 676 final Use use, final Algorithm alg, final String kid) { 677 678 this(Base64URL.encode(pub.getModulus()), 679 Base64URL.encode(pub.getPublicExponent()), 680 Base64URL.encode(priv.getPrivateExponent()), 681 Base64URL.encode(priv.getPrimeP()), 682 Base64URL.encode(priv.getPrimeQ()), 683 Base64URL.encode(priv.getPrimeExponentP()), 684 Base64URL.encode(priv.getPrimeExponentQ()), 685 Base64URL.encode(priv.getCrtCoefficient()), 686 OtherPrimesInfo.toList(priv.getOtherPrimeInfo()), 687 use, alg, kid); 688 } 689 690 691 /** 692 * Returns the modulus value ({@code n}) of the RSA key. It is 693 * represented as the Base64URL encoding of the value's big endian 694 * representation. 695 * 696 * @return The RSA key modulus. 697 */ 698 public Base64URL getModulus() { 699 700 return n; 701 } 702 703 704 /** 705 * Returns the public exponent ({@code e}) of the RSA key. It is 706 * represented as the Base64URL encoding of the value's big endian 707 * representation. 708 * 709 * @return The public RSA key exponent. 710 */ 711 public Base64URL getPublicExponent() { 712 713 return e; 714 } 715 716 717 /** 718 * Returns the private exponent ({@code d}) of the RSA key. It is 719 * represented as the Base64URL encoding of the value's big endian 720 * representation. 721 * 722 * @return The private RSA key exponent, {@code null} if not specified. 723 */ 724 public Base64URL getPrivateExponent() { 725 726 return d; 727 } 728 729 730 /** 731 * Returns the first prime factor ({@code p}) of the private RSA key. 732 * It is represented as the Base64URL encoding of the value's big 733 * endian representation. 734 * 735 * @return The RSA first prime factor, {@code null} if not specified. 736 */ 737 public Base64URL getFirstPrimeFactor() { 738 739 return p; 740 } 741 742 743 /** 744 * Returns the second prime factor ({@code q}) of the private RSA key. 745 * It is represented as the Base64URL encoding of the value's big 746 * endian representation. 747 * 748 * @return The RSA second prime factor, {@code null} if not specified. 749 */ 750 public Base64URL getSecondPrimeFactor() { 751 752 return q; 753 } 754 755 756 /** 757 * Returns the first factor Chinese Remainder Theorem (CRT) exponent 758 * ({@code dp}) of the private RSA key. It is represented as the 759 * Base64URL encoding of the value's big endian representation. 760 * 761 * @return The RSA first factor CRT exponent, {@code null} if not 762 * specified. 763 */ 764 public Base64URL getFirstFactorCRTExponent() { 765 766 return dp; 767 } 768 769 770 /** 771 * Returns the second factor Chinese Remainder Theorem (CRT) exponent 772 * ({@code dq}) of the private RSA key. It is represented as the 773 * Base64URL encoding of the value's big endian representation. 774 * 775 * @return The RSA second factor CRT exponent, {@code null} if not 776 * specified. 777 */ 778 public Base64URL getSecondFactorCRTExponent() { 779 780 return dq; 781 } 782 783 784 /** 785 * Returns the first Chinese Remainder Theorem (CRT) coefficient 786 * ({@code qi})} of the private RSA key. It is represented as the 787 * Base64URL encoding of the value's big endian representation. 788 * 789 * @return The RSA first CRT coefficient, {@code null} if not 790 * specified. 791 */ 792 public Base64URL getFirstCRTCoefficient() { 793 794 return qi; 795 } 796 797 798 /** 799 * Returns the other primes information ({@code oth}) for the private 800 * RSA key, should they exist. 801 * 802 * @return The RSA other primes information, {@code null} or empty list 803 * if not specified. 804 */ 805 public List<OtherPrimesInfo> getOtherPrimes() { 806 807 return oth; 808 } 809 810 811 /** 812 * Returns a standard {@code java.security.interfaces.RSAPublicKey} 813 * representation of this RSA JWK. 814 * 815 * @return The public RSA key. 816 * 817 * @throws NoSuchAlgorithmException If RSA is not supported by the 818 * underlying Java Cryptography (JCA) 819 * provider. 820 * @throws InvalidKeySpecException If the JWK key parameters are 821 * invalid for a public RSA key. 822 */ 823 public RSAPublicKey toRSAPublicKey() 824 throws NoSuchAlgorithmException, InvalidKeySpecException { 825 826 BigInteger modulus = n.decodeToBigInteger(); 827 BigInteger exponent = e.decodeToBigInteger(); 828 829 RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, exponent); 830 KeyFactory factory = KeyFactory.getInstance("RSA"); 831 832 RSAPublicKey pub = (RSAPublicKey) factory.generatePublic(spec); 833 834 return pub; 835 } 836 837 838 /** 839 * Returns a standard {@code java.security.interfaces.RSAPrivateKey} 840 * representation of this RSA JWK. 841 * 842 * @return The private RSA key, {@code null} if not specified by this 843 * JWK. 844 * 845 * @throws NoSuchAlgorithmException If RSA is not supported by the 846 * underlying Java Cryptography (JCA) 847 * provider. 848 * @throws InvalidKeySpecException If the JWK key parameters are 849 * invalid for a private RSA key. 850 */ 851 public RSAPrivateKey toRSAPrivateKey() 852 throws NoSuchAlgorithmException, InvalidKeySpecException { 853 854 if (d == null) { 855 // no private key 856 return null; 857 } 858 859 BigInteger modulus = n.decodeToBigInteger(); 860 BigInteger privateExponent = d.decodeToBigInteger(); 861 862 RSAPrivateKeySpec spec; 863 864 if (p == null) { 865 // Use 1st representation 866 spec = new RSAPrivateKeySpec(modulus, privateExponent); 867 868 } else { 869 // Use 2nd (CRT) representation 870 BigInteger publicExponent = e.decodeToBigInteger(); 871 BigInteger primeP = p.decodeToBigInteger(); 872 BigInteger primeQ = q.decodeToBigInteger(); 873 BigInteger primeExponentP = dp.decodeToBigInteger(); 874 BigInteger primeExponentQ = dq.decodeToBigInteger(); 875 BigInteger crtCoefficient = qi.decodeToBigInteger(); 876 877 if (oth != null && ! oth.isEmpty()) { 878 // Construct other info spec 879 RSAOtherPrimeInfo[] otherInfo = new RSAOtherPrimeInfo[oth.size()]; 880 881 for (int i=0; i < oth.size(); i++) { 882 883 OtherPrimesInfo opi = oth.get(i); 884 885 BigInteger otherPrime = opi.getPrimeFactor().decodeToBigInteger(); 886 BigInteger otherPrimeExponent = opi.getFactorCRTExponent().decodeToBigInteger(); 887 BigInteger otherCrtCoefficient = opi.getFactorCRTCoefficient().decodeToBigInteger(); 888 889 otherInfo[i] = new RSAOtherPrimeInfo(otherPrime, 890 otherPrimeExponent, 891 otherCrtCoefficient); 892 } 893 894 spec = new RSAMultiPrimePrivateCrtKeySpec(modulus, 895 publicExponent, 896 privateExponent, 897 primeP, 898 primeQ, 899 primeExponentP, 900 primeExponentQ, 901 crtCoefficient, 902 otherInfo); 903 } else { 904 // Construct spec with no other info 905 spec = new RSAPrivateCrtKeySpec(modulus, 906 publicExponent, 907 privateExponent, 908 primeP, 909 primeQ, 910 primeExponentP, 911 primeExponentQ, 912 crtCoefficient); 913 } 914 } 915 916 KeyFactory factory = KeyFactory.getInstance("RSA"); 917 918 RSAPrivateKey priv = (RSAPrivateKey) factory.generatePrivate(spec); 919 920 return priv; 921 } 922 923 924 /** 925 * Returns a standard {@code java.security.KeyPair} representation of 926 * this RSA JWK. 927 * 928 * @return The RSA key pair. The private RSA key will be {@code null} 929 * if not specified. 930 * 931 * @throws NoSuchAlgorithmException If RSA is not supported by the 932 * underlying Java Cryptography (JCA) 933 * provider. 934 * @throws InvalidKeySpecException If the JWK key parameters are 935 * invalid for a public and / or 936 * private RSA key. 937 */ 938 public KeyPair toKeyPair() 939 throws NoSuchAlgorithmException, InvalidKeySpecException { 940 941 return new KeyPair(toRSAPublicKey(), toRSAPrivateKey()); 942 } 943 944 945 @Override 946 public boolean isPrivate() { 947 948 // Check if 1st or 2nd form params are specified 949 if (d != null || p != null) { 950 951 return true; 952 953 } else { 954 955 return false; 956 } 957 } 958 959 960 /** 961 * Returns a copy of this RSA JWK with any private values removed. 962 * 963 * @return The copied public RSA JWK. 964 */ 965 @Override 966 public RSAKey toPublicJWK() { 967 968 return new RSAKey(getModulus(), getPublicExponent(), getKeyUse(), getAlgorithm(), getKeyID()); 969 } 970 971 972 @Override 973 public JSONObject toJSONObject() { 974 975 JSONObject o = super.toJSONObject(); 976 977 // Append public RSA key specific attributes 978 o.put("n", n.toString()); 979 o.put("e", e.toString()); 980 if (d != null) { 981 o.put("d", d.toString()); 982 } 983 if (p != null) { 984 o.put("p", p.toString()); 985 } 986 if (q != null) { 987 o.put("q", q.toString()); 988 } 989 if (dp != null) { 990 o.put("dp", dp.toString()); 991 } 992 if (dq != null) { 993 o.put("dq", dq.toString()); 994 } 995 if (qi != null) { 996 o.put("qi", qi.toString()); 997 } 998 if (oth != null && !oth.isEmpty()) { 999 1000 JSONArray a = new JSONArray(); 1001 1002 for (OtherPrimesInfo other : oth) { 1003 1004 JSONObject oo = new JSONObject(); 1005 oo.put("r", other.r.toString()); 1006 oo.put("d", other.d.toString()); 1007 oo.put("t", other.t.toString()); 1008 1009 a.add(oo); 1010 } 1011 1012 o.put("oth", a); 1013 } 1014 1015 return o; 1016 } 1017 1018 1019 /** 1020 * Parses a public / private RSA Curve JWK from the specified JSON 1021 * object string representation. 1022 * 1023 * @param s The JSON object string to parse. Must not be {@code null}. 1024 * 1025 * @return The public / private RSA JWK. 1026 * 1027 * @throws ParseException If the string couldn't be parsed to an RSA 1028 * JWK. 1029 */ 1030 public static RSAKey parse(final String s) 1031 throws ParseException { 1032 1033 return parse(JSONObjectUtils.parseJSONObject(s)); 1034 } 1035 1036 1037 /** 1038 * Parses a public / private RSA JWK from the specified JSON object 1039 * representation. 1040 * 1041 * @param jsonObject The JSON object to parse. Must not be 1042 * @code null}. 1043 * 1044 * @return The public / private RSA Key. 1045 * 1046 * @throws ParseException If the JSON object couldn't be parsed to an 1047 * RSA JWK. 1048 */ 1049 public static RSAKey parse(final JSONObject jsonObject) 1050 throws ParseException { 1051 1052 // Parse the mandatory public key parameters first 1053 Base64URL n = new Base64URL(JSONObjectUtils.getString(jsonObject, "n")); 1054 Base64URL e = new Base64URL(JSONObjectUtils.getString(jsonObject, "e")); 1055 1056 // Check key type 1057 KeyType kty = KeyType.parse(JSONObjectUtils.getString(jsonObject, "kty")); 1058 if (kty != KeyType.RSA) { 1059 throw new ParseException("The key type \"kty\" must be RSA", 0); 1060 } 1061 1062 // Parse the optional private key parameters 1063 1064 // 1st private representation 1065 Base64URL d = null; 1066 if (jsonObject.get("d") != null) { 1067 d = new Base64URL(JSONObjectUtils.getString(jsonObject, "d")); 1068 } 1069 1070 // 2nd private (CRT) representation 1071 Base64URL p = null; 1072 if (jsonObject.get("p") != null) { 1073 p = new Base64URL(JSONObjectUtils.getString(jsonObject, "p")); 1074 } 1075 Base64URL q = null; 1076 if (jsonObject.get("q") != null) { 1077 q = new Base64URL(JSONObjectUtils.getString(jsonObject, "q")); 1078 } 1079 Base64URL dp = null; 1080 if (jsonObject.get("dp") != null) { 1081 dp = new Base64URL(JSONObjectUtils.getString(jsonObject, "dp")); 1082 } 1083 Base64URL dq= null; 1084 if (jsonObject.get("dq") != null) { 1085 dq = new Base64URL(JSONObjectUtils.getString(jsonObject, "dq")); 1086 } 1087 Base64URL qi = null; 1088 if (jsonObject.get("qi") != null) { 1089 qi = new Base64URL(JSONObjectUtils.getString(jsonObject, "qi")); 1090 } 1091 1092 List<OtherPrimesInfo> oth = null; 1093 if (jsonObject.get("oth") != null) { 1094 1095 JSONArray arr = JSONObjectUtils.getJSONArray(jsonObject, "oth"); 1096 oth = new ArrayList<RSAKey.OtherPrimesInfo>(arr.size()); 1097 1098 for (Object o : arr) { 1099 1100 if (o instanceof JSONObject) { 1101 JSONObject otherJson = (JSONObject)o; 1102 1103 Base64URL r = new Base64URL(JSONObjectUtils.getString(otherJson, "r")); 1104 Base64URL odq = new Base64URL(JSONObjectUtils.getString(otherJson, "dq")); 1105 Base64URL t = new Base64URL(JSONObjectUtils.getString(otherJson, "t")); 1106 1107 OtherPrimesInfo prime = new OtherPrimesInfo(r, odq, t); 1108 oth.add(prime); 1109 } 1110 } 1111 } 1112 1113 // Get optional key use 1114 Use use = JWK.parseKeyUse(jsonObject); 1115 1116 // Get optional intended algorithm 1117 Algorithm alg = JWK.parseAlgorithm(jsonObject); 1118 1119 // Get optional key ID 1120 String kid = JWK.parseKeyID(jsonObject); 1121 1122 try { 1123 return new RSAKey(n, e, d, p, q, dp, dq, qi, oth, use, alg, kid); 1124 1125 } catch (IllegalArgumentException ex) { 1126 1127 // Inconsistent 2nd spec 1128 throw new ParseException(ex.getMessage(), 0); 1129 } 1130 } 1131 }