J. Duke | 319a3b9 | 2007-12-01 00:00:00 +0000 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright 2003-2007 Sun Microsystems, Inc. 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. Sun designates this |
| 8 | * particular file as subject to the "Classpath" exception as provided |
| 9 | * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| 22 | * CA 95054 USA or visit www.sun.com if you need additional information or |
| 23 | * have any 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 javax.crypto.*; |
| 33 | import javax.crypto.spec.*; |
| 34 | |
| 35 | import static sun.security.pkcs11.TemplateManager.*; |
| 36 | import sun.security.pkcs11.wrapper.*; |
| 37 | import static sun.security.pkcs11.wrapper.PKCS11Constants.*; |
| 38 | |
| 39 | /** |
| 40 | * RSA Cipher implementation class. We currently only support |
| 41 | * PKCS#1 v1.5 padding on top of CKM_RSA_PKCS. |
| 42 | * |
| 43 | * @author Andreas Sterbenz |
| 44 | * @since 1.5 |
| 45 | */ |
| 46 | final class P11RSACipher extends CipherSpi { |
| 47 | |
| 48 | // minimum length of PKCS#1 v1.5 padding |
| 49 | private final static int PKCS1_MIN_PADDING_LENGTH = 11; |
| 50 | |
| 51 | // constant byte[] of length 0 |
| 52 | private final static byte[] B0 = new byte[0]; |
| 53 | |
| 54 | // mode constant for public key encryption |
| 55 | private final static int MODE_ENCRYPT = 1; |
| 56 | // mode constant for private key decryption |
| 57 | private final static int MODE_DECRYPT = 2; |
| 58 | // mode constant for private key encryption (signing) |
| 59 | private final static int MODE_SIGN = 3; |
| 60 | // mode constant for public key decryption (verifying) |
| 61 | private final static int MODE_VERIFY = 4; |
| 62 | |
| 63 | // token instance |
| 64 | private final Token token; |
| 65 | |
| 66 | // algorithm name (always "RSA") |
| 67 | private final String algorithm; |
| 68 | |
| 69 | // mechanism id |
| 70 | private final long mechanism; |
| 71 | |
| 72 | // associated session, if any |
| 73 | private Session session; |
| 74 | |
| 75 | // mode, one of MODE_* above |
| 76 | private int mode; |
| 77 | |
| 78 | private byte[] buffer; |
| 79 | private int bufOfs; |
| 80 | |
| 81 | // key, if init() was called |
| 82 | private P11Key p11Key; |
| 83 | |
| 84 | // flag indicating whether an operation is initialized |
| 85 | private boolean initialized; |
| 86 | |
| 87 | // maximum input data size allowed |
| 88 | // for decryption, this is the length of the key |
| 89 | // for encryption, length of the key minus minimum padding length |
| 90 | private int maxInputSize; |
| 91 | |
| 92 | // maximum output size. this is the length of the key |
| 93 | private int outputSize; |
| 94 | |
| 95 | P11RSACipher(Token token, String algorithm, long mechanism) |
| 96 | throws PKCS11Exception { |
| 97 | super(); |
| 98 | this.token = token; |
| 99 | this.algorithm = "RSA"; |
| 100 | this.mechanism = mechanism; |
| 101 | session = token.getOpSession(); |
| 102 | } |
| 103 | |
| 104 | // modes do not make sense for RSA, but allow ECB |
| 105 | // see JCE spec |
| 106 | protected void engineSetMode(String mode) throws NoSuchAlgorithmException { |
| 107 | if (mode.equalsIgnoreCase("ECB") == false) { |
| 108 | throw new NoSuchAlgorithmException("Unsupported mode " + mode); |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | protected void engineSetPadding(String padding) |
| 113 | throws NoSuchPaddingException { |
| 114 | String lowerPadding = padding.toLowerCase(); |
| 115 | if (lowerPadding.equals("pkcs1Padding")) { |
| 116 | // empty |
| 117 | } else { |
| 118 | throw new NoSuchPaddingException("Unsupported padding " + padding); |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | // return 0 as block size, we are not a block cipher |
| 123 | // see JCE spec |
| 124 | protected int engineGetBlockSize() { |
| 125 | return 0; |
| 126 | } |
| 127 | |
| 128 | // return the output size |
| 129 | // see JCE spec |
| 130 | protected int engineGetOutputSize(int inputLen) { |
| 131 | return outputSize; |
| 132 | } |
| 133 | |
| 134 | // no IV, return null |
| 135 | // see JCE spec |
| 136 | protected byte[] engineGetIV() { |
| 137 | return null; |
| 138 | } |
| 139 | |
| 140 | // no parameters, return null |
| 141 | // see JCE spec |
| 142 | protected AlgorithmParameters engineGetParameters() { |
| 143 | return null; |
| 144 | } |
| 145 | |
| 146 | // see JCE spec |
| 147 | protected void engineInit(int opmode, Key key, SecureRandom random) |
| 148 | throws InvalidKeyException { |
| 149 | implInit(opmode, key); |
| 150 | } |
| 151 | |
| 152 | // see JCE spec |
| 153 | protected void engineInit(int opmode, Key key, |
| 154 | AlgorithmParameterSpec params, SecureRandom random) |
| 155 | throws InvalidKeyException, InvalidAlgorithmParameterException { |
| 156 | if (params != null) { |
| 157 | throw new InvalidAlgorithmParameterException |
| 158 | ("Parameters not supported"); |
| 159 | } |
| 160 | implInit(opmode, key); |
| 161 | } |
| 162 | |
| 163 | // see JCE spec |
| 164 | protected void engineInit(int opmode, Key key, AlgorithmParameters params, |
| 165 | SecureRandom random) |
| 166 | throws InvalidKeyException, InvalidAlgorithmParameterException { |
| 167 | if (params != null) { |
| 168 | throw new InvalidAlgorithmParameterException |
| 169 | ("Parameters not supported"); |
| 170 | } |
| 171 | implInit(opmode, key); |
| 172 | } |
| 173 | |
| 174 | private void implInit(int opmode, Key key) throws InvalidKeyException { |
| 175 | cancelOperation(); |
| 176 | p11Key = P11KeyFactory.convertKey(token, key, algorithm); |
| 177 | boolean encrypt; |
| 178 | if (opmode == Cipher.ENCRYPT_MODE) { |
| 179 | encrypt = true; |
| 180 | } else if (opmode == Cipher.DECRYPT_MODE) { |
| 181 | encrypt = false; |
| 182 | } else if (opmode == Cipher.WRAP_MODE) { |
| 183 | if (p11Key.isPublic() == false) { |
| 184 | throw new InvalidKeyException |
| 185 | ("Wrap has to be used with public keys"); |
| 186 | } |
| 187 | // No further setup needed for C_Wrap(). We remain uninitialized. |
| 188 | return; |
| 189 | } else if (opmode == Cipher.UNWRAP_MODE) { |
| 190 | if (p11Key.isPrivate() == false) { |
| 191 | throw new InvalidKeyException |
| 192 | ("Unwrap has to be used with private keys"); |
| 193 | } |
| 194 | encrypt = false; |
| 195 | } else { |
| 196 | throw new InvalidKeyException("Unsupported mode: " + opmode); |
| 197 | } |
| 198 | if (p11Key.isPublic()) { |
| 199 | mode = encrypt ? MODE_ENCRYPT : MODE_VERIFY; |
| 200 | } else if (p11Key.isPrivate()) { |
| 201 | mode = encrypt ? MODE_SIGN : MODE_DECRYPT; |
| 202 | } else { |
| 203 | throw new InvalidKeyException("Unknown key type: " + p11Key); |
| 204 | } |
| 205 | int n = (p11Key.keyLength() + 7) >> 3; |
| 206 | outputSize = n; |
| 207 | buffer = new byte[n]; |
| 208 | maxInputSize = encrypt ? (n - PKCS1_MIN_PADDING_LENGTH) : n; |
| 209 | try { |
| 210 | initialize(); |
| 211 | } catch (PKCS11Exception e) { |
| 212 | throw new InvalidKeyException("init() failed", e); |
| 213 | } |
| 214 | } |
| 215 | |
| 216 | private void cancelOperation() { |
| 217 | token.ensureValid(); |
| 218 | if (initialized == false) { |
| 219 | return; |
| 220 | } |
| 221 | initialized = false; |
| 222 | if ((session == null) || (token.explicitCancel == false)) { |
| 223 | return; |
| 224 | } |
| 225 | if (session.hasObjects() == false) { |
| 226 | session = token.killSession(session); |
| 227 | return; |
| 228 | } |
| 229 | try { |
| 230 | PKCS11 p11 = token.p11; |
| 231 | int inLen = maxInputSize; |
| 232 | int outLen = buffer.length; |
| 233 | switch (mode) { |
| 234 | case MODE_ENCRYPT: |
| 235 | p11.C_Encrypt |
| 236 | (session.id(), buffer, 0, inLen, buffer, 0, outLen); |
| 237 | break; |
| 238 | case MODE_DECRYPT: |
| 239 | p11.C_Decrypt |
| 240 | (session.id(), buffer, 0, inLen, buffer, 0, outLen); |
| 241 | break; |
| 242 | case MODE_SIGN: |
| 243 | byte[] tmpBuffer = new byte[maxInputSize]; |
| 244 | p11.C_Sign |
| 245 | (session.id(), tmpBuffer); |
| 246 | break; |
| 247 | case MODE_VERIFY: |
| 248 | p11.C_VerifyRecover |
| 249 | (session.id(), buffer, 0, inLen, buffer, 0, outLen); |
| 250 | break; |
| 251 | default: |
| 252 | throw new ProviderException("internal error"); |
| 253 | } |
| 254 | } catch (PKCS11Exception e) { |
| 255 | // XXX ensure this always works, ignore error |
| 256 | } |
| 257 | } |
| 258 | |
| 259 | private void ensureInitialized() throws PKCS11Exception { |
| 260 | token.ensureValid(); |
| 261 | if (initialized == false) { |
| 262 | initialize(); |
| 263 | } |
| 264 | } |
| 265 | |
| 266 | private void initialize() throws PKCS11Exception { |
| 267 | if (session == null) { |
| 268 | session = token.getOpSession(); |
| 269 | } |
| 270 | PKCS11 p11 = token.p11; |
| 271 | CK_MECHANISM ckMechanism = new CK_MECHANISM(mechanism); |
| 272 | switch (mode) { |
| 273 | case MODE_ENCRYPT: |
| 274 | p11.C_EncryptInit(session.id(), ckMechanism, p11Key.keyID); |
| 275 | break; |
| 276 | case MODE_DECRYPT: |
| 277 | p11.C_DecryptInit(session.id(), ckMechanism, p11Key.keyID); |
| 278 | break; |
| 279 | case MODE_SIGN: |
| 280 | p11.C_SignInit(session.id(), ckMechanism, p11Key.keyID); |
| 281 | break; |
| 282 | case MODE_VERIFY: |
| 283 | p11.C_VerifyRecoverInit(session.id(), ckMechanism, p11Key.keyID); |
| 284 | break; |
| 285 | default: |
| 286 | throw new AssertionError("internal error"); |
| 287 | } |
| 288 | bufOfs = 0; |
| 289 | initialized = true; |
| 290 | } |
| 291 | |
| 292 | private void implUpdate(byte[] in, int inOfs, int inLen) { |
| 293 | try { |
| 294 | ensureInitialized(); |
| 295 | } catch (PKCS11Exception e) { |
| 296 | throw new ProviderException("update() failed", e); |
| 297 | } |
| 298 | if ((inLen == 0) || (in == null)) { |
| 299 | return; |
| 300 | } |
| 301 | if (bufOfs + inLen > maxInputSize) { |
| 302 | bufOfs = maxInputSize + 1; |
| 303 | return; |
| 304 | } |
| 305 | System.arraycopy(in, inOfs, buffer, bufOfs, inLen); |
| 306 | bufOfs += inLen; |
| 307 | } |
| 308 | |
| 309 | private int implDoFinal(byte[] out, int outOfs, int outLen) |
| 310 | throws BadPaddingException, IllegalBlockSizeException { |
| 311 | if (bufOfs > maxInputSize) { |
| 312 | throw new IllegalBlockSizeException("Data must not be longer " |
| 313 | + "than " + maxInputSize + " bytes"); |
| 314 | } |
| 315 | try { |
| 316 | ensureInitialized(); |
| 317 | PKCS11 p11 = token.p11; |
| 318 | int n; |
| 319 | switch (mode) { |
| 320 | case MODE_ENCRYPT: |
| 321 | n = p11.C_Encrypt |
| 322 | (session.id(), buffer, 0, bufOfs, out, outOfs, outLen); |
| 323 | break; |
| 324 | case MODE_DECRYPT: |
| 325 | n = p11.C_Decrypt |
| 326 | (session.id(), buffer, 0, bufOfs, out, outOfs, outLen); |
| 327 | break; |
| 328 | case MODE_SIGN: |
| 329 | byte[] tmpBuffer = new byte[bufOfs]; |
| 330 | System.arraycopy(buffer, 0, tmpBuffer, 0, bufOfs); |
| 331 | tmpBuffer = p11.C_Sign(session.id(), tmpBuffer); |
| 332 | if (tmpBuffer.length > outLen) { |
| 333 | throw new BadPaddingException("Output buffer too small"); |
| 334 | } |
| 335 | System.arraycopy(tmpBuffer, 0, out, outOfs, tmpBuffer.length); |
| 336 | n = tmpBuffer.length; |
| 337 | break; |
| 338 | case MODE_VERIFY: |
| 339 | n = p11.C_VerifyRecover |
| 340 | (session.id(), buffer, 0, bufOfs, out, outOfs, outLen); |
| 341 | break; |
| 342 | default: |
| 343 | throw new ProviderException("internal error"); |
| 344 | } |
| 345 | return n; |
| 346 | } catch (PKCS11Exception e) { |
| 347 | throw (BadPaddingException)new BadPaddingException |
| 348 | ("doFinal() failed").initCause(e); |
| 349 | } finally { |
| 350 | initialized = false; |
| 351 | session = token.releaseSession(session); |
| 352 | } |
| 353 | } |
| 354 | |
| 355 | // see JCE spec |
| 356 | protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) { |
| 357 | implUpdate(in, inOfs, inLen); |
| 358 | return B0; |
| 359 | } |
| 360 | |
| 361 | // see JCE spec |
| 362 | protected int engineUpdate(byte[] in, int inOfs, int inLen, |
| 363 | byte[] out, int outOfs) throws ShortBufferException { |
| 364 | implUpdate(in, inOfs, inLen); |
| 365 | return 0; |
| 366 | } |
| 367 | |
| 368 | // see JCE spec |
| 369 | protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen) |
| 370 | throws IllegalBlockSizeException, BadPaddingException { |
| 371 | implUpdate(in, inOfs, inLen); |
| 372 | int n = implDoFinal(buffer, 0, buffer.length); |
| 373 | byte[] out = new byte[n]; |
| 374 | System.arraycopy(buffer, 0, out, 0, n); |
| 375 | return out; |
| 376 | } |
| 377 | |
| 378 | // see JCE spec |
| 379 | protected int engineDoFinal(byte[] in, int inOfs, int inLen, |
| 380 | byte[] out, int outOfs) throws ShortBufferException, |
| 381 | IllegalBlockSizeException, BadPaddingException { |
| 382 | implUpdate(in, inOfs, inLen); |
| 383 | return implDoFinal(out, outOfs, out.length - outOfs); |
| 384 | } |
| 385 | |
| 386 | private byte[] doFinal() throws BadPaddingException, IllegalBlockSizeException { |
| 387 | byte[] t = new byte[2048]; |
| 388 | int n = implDoFinal(t, 0, t.length); |
| 389 | byte[] out = new byte[n]; |
| 390 | System.arraycopy(t, 0, out, 0, n); |
| 391 | return out; |
| 392 | } |
| 393 | |
| 394 | // see JCE spec |
| 395 | protected byte[] engineWrap(Key key) throws InvalidKeyException, |
| 396 | IllegalBlockSizeException { |
| 397 | // XXX Note that if we cannot convert key to a key on this token, |
| 398 | // we will fail. For example, trying a wrap an AES key on a token that |
| 399 | // does not support AES. |
| 400 | // We could implement a fallback that just encrypts the encoding |
| 401 | // (assuming the key is not sensitive). For now, we are operating under |
| 402 | // the assumption that this is not necessary. |
| 403 | String keyAlg = key.getAlgorithm(); |
| 404 | P11Key secretKey = P11SecretKeyFactory.convertKey(token, key, keyAlg); |
| 405 | Session s = null; |
| 406 | try { |
| 407 | s = token.getOpSession(); |
| 408 | byte[] b = token.p11.C_WrapKey(s.id(), new CK_MECHANISM(mechanism), |
| 409 | p11Key.keyID, secretKey.keyID); |
| 410 | return b; |
| 411 | } catch (PKCS11Exception e) { |
| 412 | throw new InvalidKeyException("wrap() failed", e); |
| 413 | } finally { |
| 414 | token.releaseSession(s); |
| 415 | } |
| 416 | } |
| 417 | |
| 418 | // see JCE spec |
| 419 | protected Key engineUnwrap(byte[] wrappedKey, String algorithm, |
| 420 | int type) throws InvalidKeyException, NoSuchAlgorithmException { |
| 421 | if (algorithm.equals("TlsRsaPremasterSecret")) { |
| 422 | // the instance variable "session" has been initialized for |
| 423 | // decrypt mode, so use a local variable instead. |
| 424 | Session s = null; |
| 425 | try { |
| 426 | s = token.getObjSession(); |
| 427 | long keyType = CKK_GENERIC_SECRET; |
| 428 | CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { |
| 429 | new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), |
| 430 | new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType), |
| 431 | }; |
| 432 | attributes = token.getAttributes |
| 433 | (O_IMPORT, CKO_SECRET_KEY, keyType, attributes); |
| 434 | long keyID = token.p11.C_UnwrapKey(s.id(), new CK_MECHANISM(mechanism), |
| 435 | p11Key.keyID, wrappedKey, attributes); |
| 436 | return P11Key.secretKey(session, keyID, algorithm, 48 << 3, attributes); |
| 437 | } catch (PKCS11Exception e) { |
| 438 | throw new InvalidKeyException("wrap() failed", e); |
| 439 | } finally { |
| 440 | token.releaseSession(s); |
| 441 | } |
| 442 | } |
| 443 | // XXX implement unwrap using C_Unwrap() for all keys |
| 444 | if (wrappedKey.length > maxInputSize) { |
| 445 | throw new InvalidKeyException("Key is too long for unwrapping"); |
| 446 | } |
| 447 | implUpdate(wrappedKey, 0, wrappedKey.length); |
| 448 | try { |
| 449 | byte[] encoded = doFinal(); |
| 450 | return ConstructKeys.constructKey(encoded, algorithm, type); |
| 451 | } catch (BadPaddingException e) { |
| 452 | // should not occur |
| 453 | throw new InvalidKeyException("Unwrapping failed", e); |
| 454 | } catch (IllegalBlockSizeException e) { |
| 455 | // should not occur, handled with length check above |
| 456 | throw new InvalidKeyException("Unwrapping failed", e); |
| 457 | } |
| 458 | } |
| 459 | |
| 460 | // see JCE spec |
| 461 | protected int engineGetKeySize(Key key) throws InvalidKeyException { |
| 462 | int n = P11KeyFactory.convertKey(token, key, algorithm).keyLength(); |
| 463 | return n; |
| 464 | } |
| 465 | |
| 466 | protected void finalize() throws Throwable { |
| 467 | try { |
| 468 | if ((session != null) && token.isValid()) { |
| 469 | cancelOperation(); |
| 470 | session = token.releaseSession(session); |
| 471 | } |
| 472 | } finally { |
| 473 | super.finalize(); |
| 474 | } |
| 475 | } |
| 476 | |
| 477 | } |
| 478 | |
| 479 | final class ConstructKeys { |
| 480 | /** |
| 481 | * Construct a public key from its encoding. |
| 482 | * |
| 483 | * @param encodedKey the encoding of a public key. |
| 484 | * |
| 485 | * @param encodedKeyAlgorithm the algorithm the encodedKey is for. |
| 486 | * |
| 487 | * @return a public key constructed from the encodedKey. |
| 488 | */ |
| 489 | private static final PublicKey constructPublicKey(byte[] encodedKey, |
| 490 | String encodedKeyAlgorithm) |
| 491 | throws InvalidKeyException, NoSuchAlgorithmException { |
| 492 | try { |
| 493 | KeyFactory keyFactory = |
| 494 | KeyFactory.getInstance(encodedKeyAlgorithm); |
| 495 | X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey); |
| 496 | return keyFactory.generatePublic(keySpec); |
| 497 | } catch (NoSuchAlgorithmException nsae) { |
| 498 | throw new NoSuchAlgorithmException("No installed providers " + |
| 499 | "can create keys for the " + |
| 500 | encodedKeyAlgorithm + |
| 501 | "algorithm", nsae); |
| 502 | } catch (InvalidKeySpecException ike) { |
| 503 | throw new InvalidKeyException("Cannot construct public key", ike); |
| 504 | } |
| 505 | } |
| 506 | |
| 507 | /** |
| 508 | * Construct a private key from its encoding. |
| 509 | * |
| 510 | * @param encodedKey the encoding of a private key. |
| 511 | * |
| 512 | * @param encodedKeyAlgorithm the algorithm the wrapped key is for. |
| 513 | * |
| 514 | * @return a private key constructed from the encodedKey. |
| 515 | */ |
| 516 | private static final PrivateKey constructPrivateKey(byte[] encodedKey, |
| 517 | String encodedKeyAlgorithm) throws InvalidKeyException, |
| 518 | NoSuchAlgorithmException { |
| 519 | try { |
| 520 | KeyFactory keyFactory = |
| 521 | KeyFactory.getInstance(encodedKeyAlgorithm); |
| 522 | PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey); |
| 523 | return keyFactory.generatePrivate(keySpec); |
| 524 | } catch (NoSuchAlgorithmException nsae) { |
| 525 | throw new NoSuchAlgorithmException("No installed providers " + |
| 526 | "can create keys for the " + |
| 527 | encodedKeyAlgorithm + |
| 528 | "algorithm", nsae); |
| 529 | } catch (InvalidKeySpecException ike) { |
| 530 | throw new InvalidKeyException("Cannot construct private key", ike); |
| 531 | } |
| 532 | } |
| 533 | |
| 534 | /** |
| 535 | * Construct a secret key from its encoding. |
| 536 | * |
| 537 | * @param encodedKey the encoding of a secret key. |
| 538 | * |
| 539 | * @param encodedKeyAlgorithm the algorithm the secret key is for. |
| 540 | * |
| 541 | * @return a secret key constructed from the encodedKey. |
| 542 | */ |
| 543 | private static final SecretKey constructSecretKey(byte[] encodedKey, |
| 544 | String encodedKeyAlgorithm) { |
| 545 | return new SecretKeySpec(encodedKey, encodedKeyAlgorithm); |
| 546 | } |
| 547 | |
| 548 | static final Key constructKey(byte[] encoding, String keyAlgorithm, |
| 549 | int keyType) throws InvalidKeyException, NoSuchAlgorithmException { |
| 550 | switch (keyType) { |
| 551 | case Cipher.SECRET_KEY: |
| 552 | return constructSecretKey(encoding, keyAlgorithm); |
| 553 | case Cipher.PRIVATE_KEY: |
| 554 | return constructPrivateKey(encoding, keyAlgorithm); |
| 555 | case Cipher.PUBLIC_KEY: |
| 556 | return constructPublicKey(encoding, keyAlgorithm); |
| 557 | default: |
| 558 | throw new InvalidKeyException("Unknown keytype " + keyType); |
| 559 | } |
| 560 | } |
| 561 | } |