1 /* 2 * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.security.pkcs11; 27 28 import java.security.*; 29 import java.security.spec.AlgorithmParameterSpec; 30 import java.security.spec.*; 31 32 import java.util.Locale; 33 34 import javax.crypto.*; 35 import javax.crypto.spec.*; 36 37 import static sun.security.pkcs11.TemplateManager.*; 38 import sun.security.pkcs11.wrapper.*; 39 import static sun.security.pkcs11.wrapper.PKCS11Constants.*; 40 import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; 41 import sun.security.util.KeyUtil; 42 43 /** 44 * RSA Cipher implementation class. We currently only support 45 * PKCS#1 v1.5 padding on top of CKM_RSA_PKCS. 46 * 47 * @author Andreas Sterbenz 48 * @since 1.5 49 */ 50 final class P11RSACipher extends CipherSpi { 51 52 // minimum length of PKCS#1 v1.5 padding 53 private final static int PKCS1_MIN_PADDING_LENGTH = 11; 54 55 // constant byte[] of length 0 56 private final static byte[] B0 = new byte[0]; 57 58 // mode constant for public key encryption 59 private final static int MODE_ENCRYPT = 1; 60 // mode constant for private key decryption 61 private final static int MODE_DECRYPT = 2; 62 // mode constant for private key encryption (signing) 63 private final static int MODE_SIGN = 3; 64 // mode constant for public key decryption (verifying) 65 private final static int MODE_VERIFY = 4; 66 67 // padding type constant for NoPadding 68 private final static int PAD_NONE = 1; 69 // padding type constant for PKCS1Padding 70 private final static int PAD_PKCS1 = 2; 71 72 // token instance 73 private final Token token; 74 75 // algorithm name (always "RSA") 76 private final String algorithm; 77 78 // mechanism id 79 private final long mechanism; 80 81 // associated session, if any 82 private Session session; 83 84 // mode, one of MODE_* above 85 private int mode; 86 87 // padding, one of PAD_* above 88 private int padType; 89 90 private byte[] buffer; 91 private int bufOfs; 92 93 // key, if init() was called 94 private P11Key p11Key; 95 96 // flag indicating whether an operation is initialized 97 private boolean initialized; 98 99 // maximum input data size allowed 100 // for decryption, this is the length of the key 101 // for encryption, length of the key minus minimum padding length 102 private int maxInputSize; 103 104 // maximum output size. this is the length of the key 105 private int outputSize; 106 107 // cipher parameter for TLS RSA premaster secret 108 private AlgorithmParameterSpec spec = null; 109 110 // the source of randomness 111 private SecureRandom random; 112 113 P11RSACipher(Token token, String algorithm, long mechanism) 114 throws PKCS11Exception { 115 super(); 116 this.token = token; 117 this.algorithm = "RSA"; 118 this.mechanism = mechanism; 119 } 120 121 // modes do not make sense for RSA, but allow ECB 122 // see JCE spec 123 protected void engineSetMode(String mode) throws NoSuchAlgorithmException { 124 if (mode.equalsIgnoreCase("ECB") == false) { 125 throw new NoSuchAlgorithmException("Unsupported mode " + mode); 126 } 127 } 128 129 protected void engineSetPadding(String padding) 130 throws NoSuchPaddingException { 131 String lowerPadding = padding.toLowerCase(Locale.ENGLISH); 132 if (lowerPadding.equals("pkcs1padding")) { 133 padType = PAD_PKCS1; 134 } else if (lowerPadding.equals("nopadding")) { 135 padType = PAD_NONE; 136 } else { 137 throw new NoSuchPaddingException("Unsupported padding " + padding); 138 } 139 } 140 141 // return 0 as block size, we are not a block cipher 142 // see JCE spec 143 protected int engineGetBlockSize() { 144 return 0; 145 } 146 147 // return the output size 148 // see JCE spec 149 protected int engineGetOutputSize(int inputLen) { 150 return outputSize; 151 } 152 153 // no IV, return null 154 // see JCE spec 155 protected byte[] engineGetIV() { 156 return null; 157 } 158 159 // no parameters, return null 160 // see JCE spec 161 protected AlgorithmParameters engineGetParameters() { 162 return null; 163 } 164 165 // see JCE spec 166 protected void engineInit(int opmode, Key key, SecureRandom random) 167 throws InvalidKeyException { 168 implInit(opmode, key); 169 } 170 171 // see JCE spec 172 @SuppressWarnings("deprecation") 173 protected void engineInit(int opmode, Key key, 174 AlgorithmParameterSpec params, SecureRandom random) 175 throws InvalidKeyException, InvalidAlgorithmParameterException { 176 if (params != null) { 177 if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) { 178 throw new InvalidAlgorithmParameterException( 179 "Parameters not supported"); 180 } 181 spec = params; 182 this.random = random; // for TLS RSA premaster secret 183 } 184 implInit(opmode, key); 185 } 186 187 // see JCE spec 188 protected void engineInit(int opmode, Key key, AlgorithmParameters params, 189 SecureRandom random) 190 throws InvalidKeyException, InvalidAlgorithmParameterException { 191 if (params != null) { 192 throw new InvalidAlgorithmParameterException( 193 "Parameters not supported"); 194 } 195 implInit(opmode, key); 196 } 197 198 private void implInit(int opmode, Key key) throws InvalidKeyException { 199 reset(true); 200 p11Key = P11KeyFactory.convertKey(token, key, algorithm); 201 boolean encrypt; 202 if (opmode == Cipher.ENCRYPT_MODE) { 203 encrypt = true; 204 } else if (opmode == Cipher.DECRYPT_MODE) { 205 encrypt = false; 206 } else if (opmode == Cipher.WRAP_MODE) { 207 if (p11Key.isPublic() == false) { 208 throw new InvalidKeyException 209 ("Wrap has to be used with public keys"); 210 } 211 // No further setup needed for C_Wrap(). We'll initialize later if 212 // we can't use C_Wrap(). 213 return; 214 } else if (opmode == Cipher.UNWRAP_MODE) { 215 if (p11Key.isPrivate() == false) { 216 throw new InvalidKeyException 217 ("Unwrap has to be used with private keys"); 218 } 219 // No further setup needed for C_Unwrap(). We'll initialize later 220 // if we can't use C_Unwrap(). 221 return; 222 } else { 223 throw new InvalidKeyException("Unsupported mode: " + opmode); 224 } 225 if (p11Key.isPublic()) { 226 mode = encrypt ? MODE_ENCRYPT : MODE_VERIFY; 227 } else if (p11Key.isPrivate()) { 228 mode = encrypt ? MODE_SIGN : MODE_DECRYPT; 229 } else { 230 throw new InvalidKeyException("Unknown key type: " + p11Key); 231 } 232 int n = (p11Key.length() + 7) >> 3; 233 outputSize = n; 234 buffer = new byte[n]; 235 maxInputSize = ((padType == PAD_PKCS1 && encrypt) ? 236 (n - PKCS1_MIN_PADDING_LENGTH) : n); 237 try { 238 ensureInitialized(); 239 } catch (PKCS11Exception e) { 240 throw new InvalidKeyException("init() failed", e); 241 } 242 } 243 244 // reset the states to the pre-initialized values 245 private void reset(boolean doCancel) { 246 if (!initialized) { 247 return; 248 } 249 initialized = false; 250 try { 251 if (session == null) { 252 return; 253 } 254 if (doCancel && token.explicitCancel) { 255 cancelOperation(); 256 } 257 } finally { 258 p11Key.decNativeKeyRef(); 259 session = token.releaseSession(session); 260 } 261 } 262 263 private void cancelOperation() { 264 token.ensureValid(); 265 if (session.hasObjects() == false) { 266 session = token.killSession(session); 267 return; 268 } else { 269 try { 270 PKCS11 p11 = token.p11; 271 int inLen = maxInputSize; 272 int outLen = buffer.length; 273 switch (mode) { 274 case MODE_ENCRYPT: 275 p11.C_Encrypt(session.id(), buffer, 0, inLen, buffer, 0, 276 outLen); 277 break; 278 case MODE_DECRYPT: 279 p11.C_Decrypt(session.id(), buffer, 0, inLen, buffer, 0, 280 outLen); 281 break; 282 case MODE_SIGN: 283 byte[] tmpBuffer = new byte[maxInputSize]; 284 p11.C_Sign 285 (session.id(), tmpBuffer); 286 break; 287 case MODE_VERIFY: 288 p11.C_VerifyRecover(session.id(), buffer, 0, inLen, buffer, 289 0, outLen); 290 break; 291 default: 292 throw new ProviderException("internal error"); 293 } 294 } catch (PKCS11Exception e) { 295 // XXX ensure this always works, ignore error 296 } 297 } 298 } 299 300 private void ensureInitialized() throws PKCS11Exception { 301 if (initialized) { 302 return; 303 } 304 if (p11Key == null) { 305 throw new ProviderException( 306 "Operation cannot be performed without " + 307 "calling engineInit first"); 308 } 309 token.ensureValid(); 310 p11Key.incNativeKeyRef(); 311 try { 312 if (session == null) { 313 session = token.getOpSession(); 314 } 315 PKCS11 p11 = token.p11; 316 CK_MECHANISM ckMechanism = new CK_MECHANISM(mechanism); 317 switch (mode) { 318 case MODE_ENCRYPT: 319 p11.C_EncryptInit(session.id(), ckMechanism, p11Key.keyID); 320 break; 321 case MODE_DECRYPT: 322 p11.C_DecryptInit(session.id(), ckMechanism, p11Key.keyID); 323 break; 324 case MODE_SIGN: 325 p11.C_SignInit(session.id(), ckMechanism, p11Key.keyID); 326 break; 327 case MODE_VERIFY: 328 p11.C_VerifyRecoverInit(session.id(), ckMechanism, 329 p11Key.keyID); 330 break; 331 default: 332 throw new AssertionError("internal error"); 333 } 334 } catch (Throwable t) { 335 p11Key.decNativeKeyRef(); 336 session = token.releaseSession(session); 337 throw t; 338 } 339 initialized = true; 340 bufOfs = 0; 341 } 342 343 private void implUpdate(byte[] in, int inOfs, int inLen) { 344 try { 345 ensureInitialized(); 346 } catch (PKCS11Exception e) { 347 throw new ProviderException("update() failed", e); 348 } 349 if ((inLen == 0) || (in == null)) { 350 return; 351 } 352 if (bufOfs + inLen > maxInputSize) { 353 bufOfs = maxInputSize + 1; 354 return; 355 } 356 System.arraycopy(in, inOfs, buffer, bufOfs, inLen); 357 bufOfs += inLen; 358 } 359 360 private int implDoFinal(byte[] out, int outOfs, int outLen) 361 throws BadPaddingException, IllegalBlockSizeException { 362 if (bufOfs > maxInputSize) { 363 throw new IllegalBlockSizeException("Data must not be longer " 364 + "than " + maxInputSize + " bytes"); 365 } 366 try { 367 ensureInitialized(); 368 PKCS11 p11 = token.p11; 369 int n; 370 switch (mode) { 371 case MODE_ENCRYPT: 372 n = p11.C_Encrypt 373 (session.id(), buffer, 0, bufOfs, out, outOfs, outLen); 374 break; 375 case MODE_DECRYPT: 376 n = p11.C_Decrypt 377 (session.id(), buffer, 0, bufOfs, out, outOfs, outLen); 378 break; 379 case MODE_SIGN: 380 byte[] tmpBuffer = new byte[bufOfs]; 381 System.arraycopy(buffer, 0, tmpBuffer, 0, bufOfs); 382 tmpBuffer = p11.C_Sign(session.id(), tmpBuffer); 383 if (tmpBuffer.length > outLen) { 384 throw new BadPaddingException( 385 "Output buffer (" + outLen + ") is too small to " + 386 "hold the produced data (" + tmpBuffer.length + ")"); 387 } 388 System.arraycopy(tmpBuffer, 0, out, outOfs, tmpBuffer.length); 389 n = tmpBuffer.length; 390 break; 391 case MODE_VERIFY: 392 n = p11.C_VerifyRecover 393 (session.id(), buffer, 0, bufOfs, out, outOfs, outLen); 394 break; 395 default: 396 throw new ProviderException("internal error"); 397 } 398 return n; 399 } catch (PKCS11Exception e) { 400 throw (BadPaddingException)new BadPaddingException 401 ("doFinal() failed").initCause(e); 402 } finally { 403 reset(false); 404 } 405 } 406 407 // see JCE spec 408 protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) { 409 implUpdate(in, inOfs, inLen); 410 return B0; 411 } 412 413 // see JCE spec 414 protected int engineUpdate(byte[] in, int inOfs, int inLen, 415 byte[] out, int outOfs) throws ShortBufferException { 416 implUpdate(in, inOfs, inLen); 417 return 0; 418 } 419 420 // see JCE spec 421 protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen) 422 throws IllegalBlockSizeException, BadPaddingException { 423 implUpdate(in, inOfs, inLen); 424 int n = implDoFinal(buffer, 0, buffer.length); 425 byte[] out = new byte[n]; 426 System.arraycopy(buffer, 0, out, 0, n); 427 return out; 428 } 429 430 // see JCE spec 431 protected int engineDoFinal(byte[] in, int inOfs, int inLen, 432 byte[] out, int outOfs) throws ShortBufferException, 433 IllegalBlockSizeException, BadPaddingException { 434 implUpdate(in, inOfs, inLen); 435 return implDoFinal(out, outOfs, out.length - outOfs); 436 } 437 438 private byte[] doFinal() throws BadPaddingException, 439 IllegalBlockSizeException { 440 byte[] t = new byte[2048]; 441 int n = implDoFinal(t, 0, t.length); 442 byte[] out = new byte[n]; 443 System.arraycopy(t, 0, out, 0, n); 444 return out; 445 } 446 447 // see JCE spec 448 protected byte[] engineWrap(Key key) throws InvalidKeyException, 449 IllegalBlockSizeException { 450 String keyAlg = key.getAlgorithm(); 451 P11Key sKey = null; 452 try { 453 // The conversion may fail, e.g. trying to wrap an AES key on 454 // a token that does not support AES, or when the key size is 455 // not within the range supported by the token. 456 sKey = P11SecretKeyFactory.convertKey(token, key, keyAlg); 457 } catch (InvalidKeyException ike) { 458 byte[] toBeWrappedKey = key.getEncoded(); 459 if (toBeWrappedKey == null) { 460 throw new InvalidKeyException 461 ("wrap() failed, no encoding available", ike); 462 } 463 // Directly encrypt the key encoding when key conversion failed 464 implInit(Cipher.ENCRYPT_MODE, p11Key); 465 implUpdate(toBeWrappedKey, 0, toBeWrappedKey.length); 466 try { 467 return doFinal(); 468 } catch (BadPaddingException bpe) { 469 // should not occur 470 throw new InvalidKeyException("wrap() failed", bpe); 471 } finally { 472 // Restore original mode 473 implInit(Cipher.WRAP_MODE, p11Key); 474 } 475 } 476 Session s = null; 477 try { 478 s = token.getOpSession(); 479 p11Key.incNativeKeyRef(); 480 sKey.incNativeKeyRef(); 481 return token.p11.C_WrapKey(s.id(), new CK_MECHANISM(mechanism), 482 p11Key.keyID, sKey.keyID); 483 } catch (PKCS11Exception e) { 484 throw new InvalidKeyException("wrap() failed", e); 485 } finally { 486 p11Key.decNativeKeyRef(); 487 sKey.decNativeKeyRef(); 488 token.releaseSession(s); 489 } 490 } 491 492 // see JCE spec 493 @SuppressWarnings("deprecation") 494 protected Key engineUnwrap(byte[] wrappedKey, String algorithm, 495 int type) throws InvalidKeyException, NoSuchAlgorithmException { 496 497 boolean isTlsRsaPremasterSecret = 498 algorithm.equals("TlsRsaPremasterSecret"); 499 Exception failover = null; 500 501 // Should C_Unwrap be preferred for non-TLS RSA premaster secret? 502 if (token.supportsRawSecretKeyImport()) { 503 // XXX implement unwrap using C_Unwrap() for all keys 504 implInit(Cipher.DECRYPT_MODE, p11Key); 505 try { 506 if (wrappedKey.length > maxInputSize) { 507 throw new InvalidKeyException("Key is too long for unwrapping"); 508 } 509 510 byte[] encoded = null; 511 implUpdate(wrappedKey, 0, wrappedKey.length); 512 try { 513 encoded = doFinal(); 514 } catch (BadPaddingException e) { 515 if (isTlsRsaPremasterSecret) { 516 failover = e; 517 } else { 518 throw new InvalidKeyException("Unwrapping failed", e); 519 } 520 } catch (IllegalBlockSizeException e) { 521 // should not occur, handled with length check above 522 throw new InvalidKeyException("Unwrapping failed", e); 523 } 524 525 if (isTlsRsaPremasterSecret) { 526 if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) { 527 throw new IllegalStateException( 528 "No TlsRsaPremasterSecretParameterSpec specified"); 529 } 530 531 // polish the TLS premaster secret 532 TlsRsaPremasterSecretParameterSpec psps = 533 (TlsRsaPremasterSecretParameterSpec)spec; 534 encoded = KeyUtil.checkTlsPreMasterSecretKey( 535 psps.getClientVersion(), psps.getServerVersion(), 536 random, encoded, (failover != null)); 537 } 538 539 return ConstructKeys.constructKey(encoded, algorithm, type); 540 } finally { 541 // Restore original mode 542 implInit(Cipher.UNWRAP_MODE, p11Key); 543 } 544 } else { 545 Session s = null; 546 SecretKey secretKey = null; 547 try { 548 try { 549 s = token.getObjSession(); 550 long keyType = CKK_GENERIC_SECRET; 551 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { 552 new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), 553 new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType), 554 }; 555 attributes = token.getAttributes( 556 O_IMPORT, CKO_SECRET_KEY, keyType, attributes); 557 p11Key.incNativeKeyRef(); 558 long keyID; 559 try { 560 keyID = token.p11.C_UnwrapKey(s.id(), 561 new CK_MECHANISM(mechanism), p11Key.keyID, 562 wrappedKey, attributes); 563 } finally { 564 p11Key.decNativeKeyRef(); 565 } 566 secretKey = P11Key.secretKey(s, keyID, 567 algorithm, 48 << 3, attributes, true); 568 } catch (PKCS11Exception e) { 569 if (isTlsRsaPremasterSecret) { 570 failover = e; 571 } else { 572 throw new InvalidKeyException("unwrap() failed", e); 573 } 574 } 575 576 if (isTlsRsaPremasterSecret) { 577 TlsRsaPremasterSecretParameterSpec psps = 578 (TlsRsaPremasterSecretParameterSpec)spec; 579 580 // Please use the tricky failover as the parameter so that 581 // smart compiler won't dispose the unused variable. 582 secretKey = polishPreMasterSecretKey(token, s, 583 failover, secretKey, 584 psps.getClientVersion(), psps.getServerVersion()); 585 } 586 587 return secretKey; 588 } finally { 589 token.releaseSession(s); 590 } 591 } 592 } 593 594 // see JCE spec 595 protected int engineGetKeySize(Key key) throws InvalidKeyException { 596 int n = P11KeyFactory.convertKey(token, key, algorithm).length(); 597 return n; 598 } 599 600 private static SecretKey polishPreMasterSecretKey( 601 Token token, Session session, 602 Exception failover, SecretKey unwrappedKey, 603 int clientVersion, int serverVersion) { 604 605 SecretKey newKey; 606 CK_VERSION version = new CK_VERSION( 607 (clientVersion >>> 8) & 0xFF, clientVersion & 0xFF); 608 try { 609 CK_ATTRIBUTE[] attributes = token.getAttributes( 610 O_GENERATE, CKO_SECRET_KEY, 611 CKK_GENERIC_SECRET, new CK_ATTRIBUTE[0]); 612 long keyID = token.p11.C_GenerateKey(session.id(), 613 new CK_MECHANISM(CKM_SSL3_PRE_MASTER_KEY_GEN, version), 614 attributes); 615 newKey = P11Key.secretKey(session, keyID, 616 "TlsRsaPremasterSecret", 48 << 3, attributes, true); 617 } catch (PKCS11Exception e) { 618 throw new ProviderException( 619 "Could not generate premaster secret", e); 620 } 621 622 return (failover == null) ? unwrappedKey : newKey; 623 } 624 625 } 626 627 final class ConstructKeys { 628 /** 629 * Construct a public key from its encoding. 630 * 631 * @param encodedKey the encoding of a public key. 632 * 633 * @param encodedKeyAlgorithm the algorithm the encodedKey is for. 634 * 635 * @return a public key constructed from the encodedKey. 636 */ 637 private static final PublicKey constructPublicKey(byte[] encodedKey, 638 String encodedKeyAlgorithm) 639 throws InvalidKeyException, NoSuchAlgorithmException { 640 try { 641 KeyFactory keyFactory = 642 KeyFactory.getInstance(encodedKeyAlgorithm); 643 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey); 644 return keyFactory.generatePublic(keySpec); 645 } catch (NoSuchAlgorithmException nsae) { 646 throw new NoSuchAlgorithmException("No installed providers " + 647 "can create keys for the " + 648 encodedKeyAlgorithm + 649 "algorithm", nsae); 650 } catch (InvalidKeySpecException ike) { 651 throw new InvalidKeyException("Cannot construct public key", ike); 652 } 653 } 654 655 /** 656 * Construct a private key from its encoding. 657 * 658 * @param encodedKey the encoding of a private key. 659 * 660 * @param encodedKeyAlgorithm the algorithm the wrapped key is for. 661 * 662 * @return a private key constructed from the encodedKey. 663 */ 664 private static final PrivateKey constructPrivateKey(byte[] encodedKey, 665 String encodedKeyAlgorithm) throws InvalidKeyException, 666 NoSuchAlgorithmException { 667 try { 668 KeyFactory keyFactory = 669 KeyFactory.getInstance(encodedKeyAlgorithm); 670 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey); 671 return keyFactory.generatePrivate(keySpec); 672 } catch (NoSuchAlgorithmException nsae) { 673 throw new NoSuchAlgorithmException("No installed providers " + 674 "can create keys for the " + 675 encodedKeyAlgorithm + 676 "algorithm", nsae); 677 } catch (InvalidKeySpecException ike) { 678 throw new InvalidKeyException("Cannot construct private key", ike); 679 } 680 } 681 682 /** 683 * Construct a secret key from its encoding. 684 * 685 * @param encodedKey the encoding of a secret key. 686 * 687 * @param encodedKeyAlgorithm the algorithm the secret key is for. 688 * 689 * @return a secret key constructed from the encodedKey. 690 */ 691 private static final SecretKey constructSecretKey(byte[] encodedKey, 692 String encodedKeyAlgorithm) { 693 return new SecretKeySpec(encodedKey, encodedKeyAlgorithm); 694 } 695 696 static final Key constructKey(byte[] encoding, String keyAlgorithm, 697 int keyType) throws InvalidKeyException, NoSuchAlgorithmException { 698 switch (keyType) { 699 case Cipher.SECRET_KEY: 700 return constructSecretKey(encoding, keyAlgorithm); 701 case Cipher.PRIVATE_KEY: 702 return constructPrivateKey(encoding, keyAlgorithm); 703 case Cipher.PUBLIC_KEY: 704 return constructPublicKey(encoding, keyAlgorithm); 705 default: 706 throw new InvalidKeyException("Unknown keytype " + keyType); 707 } 708 } 709 }