1 /* 2 * Copyright (c) 2003, 2016, 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 package sun.security.pkcs11; 26 27 import java.nio.ByteBuffer; 28 import java.util.Arrays; 29 import java.util.Locale; 30 31 import java.security.*; 32 import java.security.spec.*; 33 34 import javax.crypto.*; 35 import javax.crypto.spec.*; 36 37 import sun.nio.ch.DirectBuffer; 38 import sun.security.jca.JCAUtil; 39 import sun.security.pkcs11.wrapper.*; 40 import static sun.security.pkcs11.wrapper.PKCS11Constants.*; 41 42 /** 43 * Cipher implementation class. This class currently supports 44 * DES, DESede, AES, ARCFOUR, and Blowfish. 45 * 46 * This class is designed to support ECB, CBC, CTR with NoPadding 47 * and ECB, CBC with PKCS5Padding. It will use its own padding impl 48 * if the native mechanism does not support padding. 49 * 50 * Note that PKCS#11 currently only supports ECB, CBC, and CTR. 51 * There are no provisions for other modes such as CFB, OFB, and PCBC. 52 * 53 * @author Andreas Sterbenz 54 * @since 1.5 55 */ 56 final class P11Cipher extends CipherSpi { 57 58 // mode constant for ECB mode 59 private final static int MODE_ECB = 3; 60 // mode constant for CBC mode 61 private final static int MODE_CBC = 4; 62 // mode constant for CTR mode 63 private final static int MODE_CTR = 5; 64 65 // padding constant for NoPadding 66 private final static int PAD_NONE = 5; 67 // padding constant for PKCS5Padding 68 private final static int PAD_PKCS5 = 6; 69 70 private static interface Padding { 71 // ENC: format the specified buffer with padding bytes and return the 72 // actual padding length 73 int setPaddingBytes(byte[] paddingBuffer, int padLen); 74 75 // DEC: return the length of trailing padding bytes given the specified 76 // padded data 77 int unpad(byte[] paddedData, int len) 78 throws BadPaddingException, IllegalBlockSizeException; 79 } 80 81 private static class PKCS5Padding implements Padding { 82 83 private final int blockSize; 84 85 PKCS5Padding(int blockSize) 86 throws NoSuchPaddingException { 87 if (blockSize == 0) { 88 throw new NoSuchPaddingException 89 ("PKCS#5 padding not supported with stream ciphers"); 90 } 91 this.blockSize = blockSize; 92 } 93 94 public int setPaddingBytes(byte[] paddingBuffer, int padLen) { 95 Arrays.fill(paddingBuffer, 0, padLen, (byte) (padLen & 0x007f)); 96 return padLen; 97 } 98 99 public int unpad(byte[] paddedData, int len) 100 throws BadPaddingException, IllegalBlockSizeException { 101 if ((len < 1) || (len % blockSize != 0)) { 102 throw new IllegalBlockSizeException 103 ("Input length must be multiples of " + blockSize); 104 } 105 byte padValue = paddedData[len - 1]; 106 if (padValue < 1 || padValue > blockSize) { 107 throw new BadPaddingException("Invalid pad value!"); 108 } 109 // sanity check padding bytes 110 int padStartIndex = len - padValue; 111 for (int i = padStartIndex; i < len; i++) { 112 if (paddedData[i] != padValue) { 113 throw new BadPaddingException("Invalid pad bytes!"); 114 } 115 } 116 return padValue; 117 } 118 } 119 120 // token instance 121 private final Token token; 122 123 // algorithm name 124 private final String algorithm; 125 126 // name of the key algorithm, e.g. DES instead of algorithm DES/CBC/... 127 private final String keyAlgorithm; 128 129 // mechanism id 130 private final long mechanism; 131 132 // associated session, if any 133 private Session session; 134 135 // key, if init() was called 136 private P11Key p11Key; 137 138 // flag indicating whether an operation is initialized 139 private boolean initialized; 140 141 // falg indicating encrypt or decrypt mode 142 private boolean encrypt; 143 144 // mode, one of MODE_* above (MODE_ECB for stream ciphers) 145 private int blockMode; 146 147 // block size, 0 for stream ciphers 148 private final int blockSize; 149 150 // padding type, on of PAD_* above (PAD_NONE for stream ciphers) 151 private int paddingType; 152 153 // when the padding is requested but unsupported by the native mechanism, 154 // we use the following to do padding and necessary data buffering. 155 // padding object which generate padding and unpad the decrypted data 156 private Padding paddingObj; 157 // buffer for holding back the block which contains padding bytes 158 private byte[] padBuffer; 159 private int padBufferLen; 160 161 // original IV, if in MODE_CBC or MODE_CTR 162 private byte[] iv; 163 164 // number of bytes buffered internally by the native mechanism and padBuffer 165 // if we do the padding 166 private int bytesBuffered; 167 168 // length of key size in bytes; currently only used by AES given its oid 169 // specification mandates a fixed size of the key 170 private int fixedKeySize = -1; 171 172 P11Cipher(Token token, String algorithm, long mechanism) 173 throws PKCS11Exception, NoSuchAlgorithmException { 174 super(); 175 this.token = token; 176 this.algorithm = algorithm; 177 this.mechanism = mechanism; 178 179 String[] algoParts = algorithm.split("/"); 180 181 if (algoParts[0].startsWith("AES")) { 182 blockSize = 16; 183 int index = algoParts[0].indexOf('_'); 184 if (index != -1) { 185 // should be well-formed since we specify what we support 186 fixedKeySize = Integer.parseInt(algoParts[0].substring(index+1))/8; 187 } 188 keyAlgorithm = "AES"; 189 } else { 190 keyAlgorithm = algoParts[0]; 191 if (keyAlgorithm.equals("RC4") || 192 keyAlgorithm.equals("ARCFOUR")) { 193 blockSize = 0; 194 } else { // DES, DESede, Blowfish 195 blockSize = 8; 196 } 197 } 198 this.blockMode = 199 (algoParts.length > 1 ? parseMode(algoParts[1]) : MODE_ECB); 200 String defPadding = (blockSize == 0 ? "NoPadding" : "PKCS5Padding"); 201 String paddingStr = 202 (algoParts.length > 2 ? algoParts[2] : defPadding); 203 try { 204 engineSetPadding(paddingStr); 205 } catch (NoSuchPaddingException nspe) { 206 // should not happen 207 throw new ProviderException(nspe); 208 } 209 } 210 211 protected void engineSetMode(String mode) throws NoSuchAlgorithmException { 212 // Disallow change of mode for now since currently it's explicitly 213 // defined in transformation strings 214 throw new NoSuchAlgorithmException("Unsupported mode " + mode); 215 } 216 217 private int parseMode(String mode) throws NoSuchAlgorithmException { 218 mode = mode.toUpperCase(Locale.ENGLISH); 219 int result; 220 if (mode.equals("ECB")) { 221 result = MODE_ECB; 222 } else if (mode.equals("CBC")) { 223 if (blockSize == 0) { 224 throw new NoSuchAlgorithmException 225 ("CBC mode not supported with stream ciphers"); 226 } 227 result = MODE_CBC; 228 } else if (mode.equals("CTR")) { 229 result = MODE_CTR; 230 } else { 231 throw new NoSuchAlgorithmException("Unsupported mode " + mode); 232 } 233 return result; 234 } 235 236 // see JCE spec 237 protected void engineSetPadding(String padding) 238 throws NoSuchPaddingException { 239 paddingObj = null; 240 padBuffer = null; 241 padding = padding.toUpperCase(Locale.ENGLISH); 242 if (padding.equals("NOPADDING")) { 243 paddingType = PAD_NONE; 244 } else if (padding.equals("PKCS5PADDING")) { 245 if (this.blockMode == MODE_CTR) { 246 throw new NoSuchPaddingException 247 ("PKCS#5 padding not supported with CTR mode"); 248 } 249 paddingType = PAD_PKCS5; 250 if (mechanism != CKM_DES_CBC_PAD && mechanism != CKM_DES3_CBC_PAD && 251 mechanism != CKM_AES_CBC_PAD) { 252 // no native padding support; use our own padding impl 253 paddingObj = new PKCS5Padding(blockSize); 254 padBuffer = new byte[blockSize]; 255 } 256 } else { 257 throw new NoSuchPaddingException("Unsupported padding " + padding); 258 } 259 } 260 261 // see JCE spec 262 protected int engineGetBlockSize() { 263 return blockSize; 264 } 265 266 // see JCE spec 267 protected int engineGetOutputSize(int inputLen) { 268 return doFinalLength(inputLen); 269 } 270 271 // see JCE spec 272 protected byte[] engineGetIV() { 273 return (iv == null) ? null : iv.clone(); 274 } 275 276 // see JCE spec 277 protected AlgorithmParameters engineGetParameters() { 278 if (iv == null) { 279 return null; 280 } 281 IvParameterSpec ivSpec = new IvParameterSpec(iv); 282 try { 283 AlgorithmParameters params = 284 AlgorithmParameters.getInstance(keyAlgorithm, 285 P11Util.getSunJceProvider()); 286 params.init(ivSpec); 287 return params; 288 } catch (GeneralSecurityException e) { 289 // NoSuchAlgorithmException, NoSuchProviderException 290 // InvalidParameterSpecException 291 throw new ProviderException("Could not encode parameters", e); 292 } 293 } 294 295 // see JCE spec 296 protected void engineInit(int opmode, Key key, SecureRandom random) 297 throws InvalidKeyException { 298 try { 299 implInit(opmode, key, null, random); 300 } catch (InvalidAlgorithmParameterException e) { 301 throw new InvalidKeyException("init() failed", e); 302 } 303 } 304 305 // see JCE spec 306 protected void engineInit(int opmode, Key key, 307 AlgorithmParameterSpec params, SecureRandom random) 308 throws InvalidKeyException, InvalidAlgorithmParameterException { 309 byte[] ivValue; 310 if (params != null) { 311 if (params instanceof IvParameterSpec == false) { 312 throw new InvalidAlgorithmParameterException 313 ("Only IvParameterSpec supported"); 314 } 315 IvParameterSpec ivSpec = (IvParameterSpec) params; 316 ivValue = ivSpec.getIV(); 317 } else { 318 ivValue = null; 319 } 320 implInit(opmode, key, ivValue, random); 321 } 322 323 // see JCE spec 324 protected void engineInit(int opmode, Key key, AlgorithmParameters params, 325 SecureRandom random) 326 throws InvalidKeyException, InvalidAlgorithmParameterException { 327 byte[] ivValue; 328 if (params != null) { 329 try { 330 IvParameterSpec ivSpec = 331 params.getParameterSpec(IvParameterSpec.class); 332 ivValue = ivSpec.getIV(); 333 } catch (InvalidParameterSpecException e) { 334 throw new InvalidAlgorithmParameterException 335 ("Could not decode IV", e); 336 } 337 } else { 338 ivValue = null; 339 } 340 implInit(opmode, key, ivValue, random); 341 } 342 343 // actual init() implementation 344 private void implInit(int opmode, Key key, byte[] iv, 345 SecureRandom random) 346 throws InvalidKeyException, InvalidAlgorithmParameterException { 347 reset(true); 348 if (fixedKeySize != -1 && key.getEncoded().length != fixedKeySize) { 349 throw new InvalidKeyException("Key size is invalid"); 350 } 351 switch (opmode) { 352 case Cipher.ENCRYPT_MODE: 353 encrypt = true; 354 break; 355 case Cipher.DECRYPT_MODE: 356 encrypt = false; 357 break; 358 default: 359 throw new InvalidAlgorithmParameterException 360 ("Unsupported mode: " + opmode); 361 } 362 if (blockMode == MODE_ECB) { // ECB or stream cipher 363 if (iv != null) { 364 if (blockSize == 0) { 365 throw new InvalidAlgorithmParameterException 366 ("IV not used with stream ciphers"); 367 } else { 368 throw new InvalidAlgorithmParameterException 369 ("IV not used in ECB mode"); 370 } 371 } 372 } else { // MODE_CBC or MODE_CTR 373 if (iv == null) { 374 if (encrypt == false) { 375 String exMsg = 376 (blockMode == MODE_CBC ? 377 "IV must be specified for decryption in CBC mode" : 378 "IV must be specified for decryption in CTR mode"); 379 throw new InvalidAlgorithmParameterException(exMsg); 380 } 381 // generate random IV 382 if (random == null) { 383 random = JCAUtil.getSecureRandom(); 384 } 385 iv = new byte[blockSize]; 386 random.nextBytes(iv); 387 } else { 388 if (iv.length != blockSize) { 389 throw new InvalidAlgorithmParameterException 390 ("IV length must match block size"); 391 } 392 } 393 } 394 this.iv = iv; 395 p11Key = P11SecretKeyFactory.convertKey(token, key, keyAlgorithm); 396 try { 397 ensureInitialized(); 398 } catch (PKCS11Exception e) { 399 throw new InvalidKeyException("Could not initialize cipher", e); 400 } 401 } 402 403 // reset the states to the pre-initialized values 404 private void reset(boolean doCancel) { 405 if (!initialized) { 406 return; 407 } 408 initialized = false; 409 try { 410 if (session == null) { 411 return; 412 } 413 if (doCancel && token.explicitCancel) { 414 cancelOperation(); 415 } 416 } finally { 417 p11Key.decNativeKeyRef(); 418 session = token.releaseSession(session); 419 bytesBuffered = 0; 420 padBufferLen = 0; 421 } 422 } 423 424 private void cancelOperation() { 425 token.ensureValid(); 426 if (session.hasObjects() == false) { 427 session = token.killSession(session); 428 return; 429 } else { 430 try { 431 // cancel operation by finishing it 432 int bufLen = doFinalLength(0); 433 byte[] buffer = new byte[bufLen]; 434 if (encrypt) { 435 token.p11.C_EncryptFinal(session.id(), 0, buffer, 0, bufLen); 436 } else { 437 token.p11.C_DecryptFinal(session.id(), 0, buffer, 0, bufLen); 438 } 439 } catch (PKCS11Exception e) { 440 throw new ProviderException("Cancel failed", e); 441 } 442 } 443 } 444 445 private void ensureInitialized() throws PKCS11Exception { 446 if (initialized) { 447 return; 448 } 449 if (p11Key == null) { 450 throw new ProviderException( 451 "Operation cannot be performed without calling engineInit first"); 452 } 453 token.ensureValid(); 454 p11Key.incNativeKeyRef(); 455 try { 456 if (session == null) { 457 session = token.getOpSession(); 458 } 459 CK_MECHANISM mechParams = (blockMode == MODE_CTR? 460 new CK_MECHANISM(mechanism, new CK_AES_CTR_PARAMS(iv)) : 461 new CK_MECHANISM(mechanism, iv)); 462 if (encrypt) { 463 token.p11.C_EncryptInit(session.id(), mechParams, p11Key.keyID); 464 } else { 465 token.p11.C_DecryptInit(session.id(), mechParams, p11Key.keyID); 466 } 467 } catch (Throwable t) { 468 p11Key.decNativeKeyRef(); 469 session = token.releaseSession(session); 470 throw t; 471 } 472 initialized = true; 473 bytesBuffered = 0; 474 padBufferLen = 0; 475 } 476 477 // if update(inLen) is called, how big does the output buffer have to be? 478 private int updateLength(int inLen) { 479 if (inLen <= 0) { 480 return 0; 481 } 482 483 int result = inLen + bytesBuffered; 484 if (blockSize != 0 && blockMode != MODE_CTR) { 485 // minus the number of bytes in the last incomplete block. 486 result -= (result & (blockSize - 1)); 487 } 488 return result; 489 } 490 491 // if doFinal(inLen) is called, how big does the output buffer have to be? 492 private int doFinalLength(int inLen) { 493 if (inLen < 0) { 494 return 0; 495 } 496 497 int result = inLen + bytesBuffered; 498 if (blockSize != 0 && encrypt && paddingType != PAD_NONE) { 499 // add the number of bytes to make the last block complete. 500 result += (blockSize - (result & (blockSize - 1))); 501 } 502 return result; 503 } 504 505 // see JCE spec 506 protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) { 507 try { 508 byte[] out = new byte[updateLength(inLen)]; 509 int n = engineUpdate(in, inOfs, inLen, out, 0); 510 return P11Util.convert(out, 0, n); 511 } catch (ShortBufferException e) { 512 // convert since the output length is calculated by updateLength() 513 throw new ProviderException(e); 514 } 515 } 516 517 // see JCE spec 518 protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out, 519 int outOfs) throws ShortBufferException { 520 int outLen = out.length - outOfs; 521 return implUpdate(in, inOfs, inLen, out, outOfs, outLen); 522 } 523 524 // see JCE spec 525 @Override 526 protected int engineUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer) 527 throws ShortBufferException { 528 return implUpdate(inBuffer, outBuffer); 529 } 530 531 // see JCE spec 532 protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen) 533 throws IllegalBlockSizeException, BadPaddingException { 534 try { 535 byte[] out = new byte[doFinalLength(inLen)]; 536 int n = engineDoFinal(in, inOfs, inLen, out, 0); 537 return P11Util.convert(out, 0, n); 538 } catch (ShortBufferException e) { 539 // convert since the output length is calculated by doFinalLength() 540 throw new ProviderException(e); 541 } 542 } 543 544 // see JCE spec 545 protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out, 546 int outOfs) throws ShortBufferException, IllegalBlockSizeException, 547 BadPaddingException { 548 int n = 0; 549 if ((inLen != 0) && (in != null)) { 550 n = engineUpdate(in, inOfs, inLen, out, outOfs); 551 outOfs += n; 552 } 553 n += implDoFinal(out, outOfs, out.length - outOfs); 554 return n; 555 } 556 557 // see JCE spec 558 @Override 559 protected int engineDoFinal(ByteBuffer inBuffer, ByteBuffer outBuffer) 560 throws ShortBufferException, IllegalBlockSizeException, 561 BadPaddingException { 562 int n = engineUpdate(inBuffer, outBuffer); 563 n += implDoFinal(outBuffer); 564 return n; 565 } 566 567 private int implUpdate(byte[] in, int inOfs, int inLen, 568 byte[] out, int outOfs, int outLen) throws ShortBufferException { 569 if (outLen < updateLength(inLen)) { 570 throw new ShortBufferException(); 571 } 572 try { 573 ensureInitialized(); 574 int k = 0; 575 if (encrypt) { 576 k = token.p11.C_EncryptUpdate(session.id(), 0, in, inOfs, inLen, 577 0, out, outOfs, outLen); 578 } else { 579 int newPadBufferLen = 0; 580 if (paddingObj != null) { 581 if (padBufferLen != 0) { 582 // NSS throws up when called with data not in multiple 583 // of blocks. Try to work around this by holding the 584 // extra data in padBuffer. 585 if (padBufferLen != padBuffer.length) { 586 int bufCapacity = padBuffer.length - padBufferLen; 587 if (inLen > bufCapacity) { 588 bufferInputBytes(in, inOfs, bufCapacity); 589 inOfs += bufCapacity; 590 inLen -= bufCapacity; 591 } else { 592 bufferInputBytes(in, inOfs, inLen); 593 return 0; 594 } 595 } 596 k = token.p11.C_DecryptUpdate(session.id(), 597 0, padBuffer, 0, padBufferLen, 598 0, out, outOfs, outLen); 599 padBufferLen = 0; 600 } 601 newPadBufferLen = inLen & (blockSize - 1); 602 if (newPadBufferLen == 0) { 603 newPadBufferLen = padBuffer.length; 604 } 605 inLen -= newPadBufferLen; 606 } 607 if (inLen > 0) { 608 k += token.p11.C_DecryptUpdate(session.id(), 0, in, inOfs, 609 inLen, 0, out, (outOfs + k), (outLen - k)); 610 } 611 // update 'padBuffer' if using our own padding impl. 612 if (paddingObj != null) { 613 bufferInputBytes(in, inOfs + inLen, newPadBufferLen); 614 } 615 } 616 bytesBuffered += (inLen - k); 617 return k; 618 } catch (PKCS11Exception e) { 619 if (e.getErrorCode() == CKR_BUFFER_TOO_SMALL) { 620 throw (ShortBufferException) 621 (new ShortBufferException().initCause(e)); 622 } 623 reset(false); 624 throw new ProviderException("update() failed", e); 625 } 626 } 627 628 private int implUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer) 629 throws ShortBufferException { 630 int inLen = inBuffer.remaining(); 631 if (inLen <= 0) { 632 return 0; 633 } 634 635 int outLen = outBuffer.remaining(); 636 if (outLen < updateLength(inLen)) { 637 throw new ShortBufferException(); 638 } 639 int origPos = inBuffer.position(); 640 try { 641 ensureInitialized(); 642 643 long inAddr = 0; 644 int inOfs = 0; 645 byte[] inArray = null; 646 647 if (inBuffer instanceof DirectBuffer) { 648 inAddr = ((DirectBuffer) inBuffer).address(); 649 inOfs = origPos; 650 } else if (inBuffer.hasArray()) { 651 inArray = inBuffer.array(); 652 inOfs = (origPos + inBuffer.arrayOffset()); 653 } 654 655 long outAddr = 0; 656 int outOfs = 0; 657 byte[] outArray = null; 658 if (outBuffer instanceof DirectBuffer) { 659 outAddr = ((DirectBuffer) outBuffer).address(); 660 outOfs = outBuffer.position(); 661 } else { 662 if (outBuffer.hasArray()) { 663 outArray = outBuffer.array(); 664 outOfs = (outBuffer.position() + outBuffer.arrayOffset()); 665 } else { 666 outArray = new byte[outLen]; 667 } 668 } 669 670 int k = 0; 671 if (encrypt) { 672 if (inAddr == 0 && inArray == null) { 673 inArray = new byte[inLen]; 674 inBuffer.get(inArray); 675 } else { 676 inBuffer.position(origPos + inLen); 677 } 678 k = token.p11.C_EncryptUpdate(session.id(), 679 inAddr, inArray, inOfs, inLen, 680 outAddr, outArray, outOfs, outLen); 681 } else { 682 int newPadBufferLen = 0; 683 if (paddingObj != null) { 684 if (padBufferLen != 0) { 685 // NSS throws up when called with data not in multiple 686 // of blocks. Try to work around this by holding the 687 // extra data in padBuffer. 688 if (padBufferLen != padBuffer.length) { 689 int bufCapacity = padBuffer.length - padBufferLen; 690 if (inLen > bufCapacity) { 691 bufferInputBytes(inBuffer, bufCapacity); 692 inOfs += bufCapacity; 693 inLen -= bufCapacity; 694 } else { 695 bufferInputBytes(inBuffer, inLen); 696 return 0; 697 } 698 } 699 k = token.p11.C_DecryptUpdate(session.id(), 0, 700 padBuffer, 0, padBufferLen, outAddr, outArray, 701 outOfs, outLen); 702 padBufferLen = 0; 703 } 704 newPadBufferLen = inLen & (blockSize - 1); 705 if (newPadBufferLen == 0) { 706 newPadBufferLen = padBuffer.length; 707 } 708 inLen -= newPadBufferLen; 709 } 710 if (inLen > 0) { 711 if (inAddr == 0 && inArray == null) { 712 inArray = new byte[inLen]; 713 inBuffer.get(inArray); 714 } else { 715 inBuffer.position(inBuffer.position() + inLen); 716 } 717 k += token.p11.C_DecryptUpdate(session.id(), inAddr, 718 inArray, inOfs, inLen, outAddr, outArray, 719 (outOfs + k), (outLen - k)); 720 } 721 // update 'padBuffer' if using our own padding impl. 722 if (paddingObj != null && newPadBufferLen != 0) { 723 bufferInputBytes(inBuffer, newPadBufferLen); 724 } 725 } 726 bytesBuffered += (inLen - k); 727 if (!(outBuffer instanceof DirectBuffer) && 728 !outBuffer.hasArray()) { 729 outBuffer.put(outArray, outOfs, k); 730 } else { 731 outBuffer.position(outBuffer.position() + k); 732 } 733 return k; 734 } catch (PKCS11Exception e) { 735 // Reset input buffer to its original position for 736 inBuffer.position(origPos); 737 if (e.getErrorCode() == CKR_BUFFER_TOO_SMALL) { 738 throw (ShortBufferException) 739 (new ShortBufferException().initCause(e)); 740 } 741 reset(false); 742 throw new ProviderException("update() failed", e); 743 } 744 } 745 746 private int implDoFinal(byte[] out, int outOfs, int outLen) 747 throws ShortBufferException, IllegalBlockSizeException, 748 BadPaddingException { 749 int requiredOutLen = doFinalLength(0); 750 if (outLen < requiredOutLen) { 751 throw new ShortBufferException(); 752 } 753 boolean doCancel = true; 754 try { 755 ensureInitialized(); 756 int k = 0; 757 if (encrypt) { 758 if (paddingObj != null) { 759 int actualPadLen = paddingObj.setPaddingBytes(padBuffer, 760 requiredOutLen - bytesBuffered); 761 k = token.p11.C_EncryptUpdate(session.id(), 762 0, padBuffer, 0, actualPadLen, 763 0, out, outOfs, outLen); 764 } 765 k += token.p11.C_EncryptFinal(session.id(), 766 0, out, (outOfs + k), (outLen - k)); 767 doCancel = false; 768 } else { 769 // Special handling to match SunJCE provider behavior 770 if (bytesBuffered == 0 && padBufferLen == 0) { 771 return 0; 772 } 773 if (paddingObj != null) { 774 if (padBufferLen != 0) { 775 k = token.p11.C_DecryptUpdate(session.id(), 0, 776 padBuffer, 0, padBufferLen, 0, padBuffer, 0, 777 padBuffer.length); 778 } 779 k += token.p11.C_DecryptFinal(session.id(), 0, padBuffer, k, 780 padBuffer.length - k); 781 doCancel = false; 782 783 int actualPadLen = paddingObj.unpad(padBuffer, k); 784 k -= actualPadLen; 785 System.arraycopy(padBuffer, 0, out, outOfs, k); 786 } else { 787 k = token.p11.C_DecryptFinal(session.id(), 0, out, outOfs, 788 outLen); 789 doCancel = false; 790 } 791 } 792 return k; 793 } catch (PKCS11Exception e) { 794 doCancel = false; 795 handleException(e); 796 throw new ProviderException("doFinal() failed", e); 797 } finally { 798 reset(doCancel); 799 } 800 } 801 802 private int implDoFinal(ByteBuffer outBuffer) 803 throws ShortBufferException, IllegalBlockSizeException, 804 BadPaddingException { 805 int outLen = outBuffer.remaining(); 806 int requiredOutLen = doFinalLength(0); 807 if (outLen < requiredOutLen) { 808 throw new ShortBufferException(); 809 } 810 811 boolean doCancel = true; 812 try { 813 ensureInitialized(); 814 815 long outAddr = 0; 816 byte[] outArray = null; 817 int outOfs = 0; 818 if (outBuffer instanceof DirectBuffer) { 819 outAddr = ((DirectBuffer) outBuffer).address(); 820 outOfs = outBuffer.position(); 821 } else { 822 if (outBuffer.hasArray()) { 823 outArray = outBuffer.array(); 824 outOfs = outBuffer.position() + outBuffer.arrayOffset(); 825 } else { 826 outArray = new byte[outLen]; 827 } 828 } 829 830 int k = 0; 831 832 if (encrypt) { 833 if (paddingObj != null) { 834 int actualPadLen = paddingObj.setPaddingBytes(padBuffer, 835 requiredOutLen - bytesBuffered); 836 k = token.p11.C_EncryptUpdate(session.id(), 837 0, padBuffer, 0, actualPadLen, 838 outAddr, outArray, outOfs, outLen); 839 } 840 k += token.p11.C_EncryptFinal(session.id(), 841 outAddr, outArray, (outOfs + k), (outLen - k)); 842 doCancel = false; 843 } else { 844 // Special handling to match SunJCE provider behavior 845 if (bytesBuffered == 0 && padBufferLen == 0) { 846 return 0; 847 } 848 849 if (paddingObj != null) { 850 if (padBufferLen != 0) { 851 k = token.p11.C_DecryptUpdate(session.id(), 852 0, padBuffer, 0, padBufferLen, 853 0, padBuffer, 0, padBuffer.length); 854 padBufferLen = 0; 855 } 856 k += token.p11.C_DecryptFinal(session.id(), 857 0, padBuffer, k, padBuffer.length - k); 858 doCancel = false; 859 860 int actualPadLen = paddingObj.unpad(padBuffer, k); 861 k -= actualPadLen; 862 outArray = padBuffer; 863 outOfs = 0; 864 } else { 865 k = token.p11.C_DecryptFinal(session.id(), 866 outAddr, outArray, outOfs, outLen); 867 doCancel = false; 868 } 869 } 870 if ((!encrypt && paddingObj != null) || 871 (!(outBuffer instanceof DirectBuffer) && 872 !outBuffer.hasArray())) { 873 outBuffer.put(outArray, outOfs, k); 874 } else { 875 outBuffer.position(outBuffer.position() + k); 876 } 877 return k; 878 } catch (PKCS11Exception e) { 879 doCancel = false; 880 handleException(e); 881 throw new ProviderException("doFinal() failed", e); 882 } finally { 883 reset(doCancel); 884 } 885 } 886 887 private void handleException(PKCS11Exception e) 888 throws ShortBufferException, IllegalBlockSizeException { 889 long errorCode = e.getErrorCode(); 890 if (errorCode == CKR_BUFFER_TOO_SMALL) { 891 throw (ShortBufferException) 892 (new ShortBufferException().initCause(e)); 893 } else if (errorCode == CKR_DATA_LEN_RANGE || 894 errorCode == CKR_ENCRYPTED_DATA_LEN_RANGE) { 895 throw (IllegalBlockSizeException) 896 (new IllegalBlockSizeException(e.toString()).initCause(e)); 897 } 898 } 899 900 // see JCE spec 901 protected byte[] engineWrap(Key key) throws IllegalBlockSizeException, 902 InvalidKeyException { 903 // XXX key wrapping 904 throw new UnsupportedOperationException("engineWrap()"); 905 } 906 907 // see JCE spec 908 protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, 909 int wrappedKeyType) 910 throws InvalidKeyException, NoSuchAlgorithmException { 911 // XXX key unwrapping 912 throw new UnsupportedOperationException("engineUnwrap()"); 913 } 914 915 // see JCE spec 916 @Override 917 protected int engineGetKeySize(Key key) throws InvalidKeyException { 918 int n = P11SecretKeyFactory.convertKey 919 (token, key, keyAlgorithm).length(); 920 return n; 921 } 922 923 private final void bufferInputBytes(byte[] in, int inOfs, int len) { 924 System.arraycopy(in, inOfs, padBuffer, padBufferLen, len); 925 padBufferLen += len; 926 bytesBuffered += len; 927 } 928 929 private final void bufferInputBytes(ByteBuffer inBuffer, int len) { 930 inBuffer.get(padBuffer, padBufferLen, len); 931 padBufferLen += len; 932 bytesBuffered += len; 933 } 934 }