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 initialize(); 398 } catch (PKCS11Exception e) { 399 throw new InvalidKeyException("Could not initialize cipher", e); 400 } 401 } 402 403 private void cancelOperation() { 404 if (initialized == false) { 405 return; 406 } 407 408 if ((session == null) || (token.explicitCancel == false)) { 409 return; 410 } 411 try { 412 if (session.hasObjects() == false) { 413 session = token.killSession(session); 414 return; 415 } else { 416 // cancel operation by finishing it 417 int bufLen = doFinalLength(0); 418 byte[] buffer = new byte[bufLen]; 419 if (encrypt) { 420 token.p11.C_EncryptFinal(session.id(), 0, buffer, 0, bufLen); 421 } else { 422 token.p11.C_DecryptFinal(session.id(), 0, buffer, 0, bufLen); 423 } 424 } 425 } catch (PKCS11Exception e) { 426 throw new ProviderException("Cancel failed", e); 427 } 428 } 429 430 private void ensureInitialized() throws PKCS11Exception { 431 if (initialized == false) { 432 initialize(); 433 } 434 } 435 436 private void initialize() throws PKCS11Exception { 437 if (session == null) { 438 session = token.getOpSession(); 439 } 440 CK_MECHANISM mechParams = (blockMode == MODE_CTR? 441 new CK_MECHANISM(mechanism, new CK_AES_CTR_PARAMS(iv)) : 442 new CK_MECHANISM(mechanism, iv)); 443 444 try { 445 if (encrypt) { 446 token.p11.C_EncryptInit(session.id(), mechParams, p11Key.keyID); 447 } else { 448 token.p11.C_DecryptInit(session.id(), mechParams, p11Key.keyID); 449 } 450 } catch (PKCS11Exception ex) { 451 // release session when initialization failed 452 session = token.releaseSession(session); 453 throw ex; 454 } 455 bytesBuffered = 0; 456 padBufferLen = 0; 457 initialized = true; 458 } 459 460 // if update(inLen) is called, how big does the output buffer have to be? 461 private int updateLength(int inLen) { 462 if (inLen <= 0) { 463 return 0; 464 } 465 466 int result = inLen + bytesBuffered; 467 if (blockSize != 0 && blockMode != MODE_CTR) { 468 // minus the number of bytes in the last incomplete block. 469 result -= (result & (blockSize - 1)); 470 } 471 return result; 472 } 473 474 // if doFinal(inLen) is called, how big does the output buffer have to be? 475 private int doFinalLength(int inLen) { 476 if (inLen < 0) { 477 return 0; 478 } 479 480 int result = inLen + bytesBuffered; 481 if (blockSize != 0 && encrypt && paddingType != PAD_NONE) { 482 // add the number of bytes to make the last block complete. 483 result += (blockSize - (result & (blockSize - 1))); 484 } 485 return result; 486 } 487 488 // reset the states to the pre-initialized values 489 private void reset(boolean doCancel) { 490 if (doCancel) cancelOperation(); 491 492 initialized = false; 493 bytesBuffered = 0; 494 padBufferLen = 0; 495 if (session != null) { 496 session = token.releaseSession(session); 497 } 498 } 499 500 // see JCE spec 501 protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) { 502 try { 503 byte[] out = new byte[updateLength(inLen)]; 504 int n = engineUpdate(in, inOfs, inLen, out, 0); 505 return P11Util.convert(out, 0, n); 506 } catch (ShortBufferException e) { 507 // convert since the output length is calculated by updateLength() 508 throw new ProviderException(e); 509 } 510 } 511 512 // see JCE spec 513 protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out, 514 int outOfs) throws ShortBufferException { 515 int outLen = out.length - outOfs; 516 return implUpdate(in, inOfs, inLen, out, outOfs, outLen); 517 } 518 519 // see JCE spec 520 @Override 521 protected int engineUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer) 522 throws ShortBufferException { 523 return implUpdate(inBuffer, outBuffer); 524 } 525 526 // see JCE spec 527 protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen) 528 throws IllegalBlockSizeException, BadPaddingException { 529 try { 530 byte[] out = new byte[doFinalLength(inLen)]; 531 int n = engineDoFinal(in, inOfs, inLen, out, 0); 532 return P11Util.convert(out, 0, n); 533 } catch (ShortBufferException e) { 534 // convert since the output length is calculated by doFinalLength() 535 throw new ProviderException(e); 536 } 537 } 538 539 // see JCE spec 540 protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out, 541 int outOfs) throws ShortBufferException, IllegalBlockSizeException, 542 BadPaddingException { 543 int n = 0; 544 if ((inLen != 0) && (in != null)) { 545 n = engineUpdate(in, inOfs, inLen, out, outOfs); 546 outOfs += n; 547 } 548 n += implDoFinal(out, outOfs, out.length - outOfs); 549 return n; 550 } 551 552 // see JCE spec 553 @Override 554 protected int engineDoFinal(ByteBuffer inBuffer, ByteBuffer outBuffer) 555 throws ShortBufferException, IllegalBlockSizeException, 556 BadPaddingException { 557 int n = engineUpdate(inBuffer, outBuffer); 558 n += implDoFinal(outBuffer); 559 return n; 560 } 561 562 private int implUpdate(byte[] in, int inOfs, int inLen, 563 byte[] out, int outOfs, int outLen) throws ShortBufferException { 564 if (outLen < updateLength(inLen)) { 565 throw new ShortBufferException(); 566 } 567 try { 568 ensureInitialized(); 569 int k = 0; 570 if (encrypt) { 571 k = token.p11.C_EncryptUpdate(session.id(), 0, in, inOfs, inLen, 572 0, out, outOfs, outLen); 573 } else { 574 int newPadBufferLen = 0; 575 if (paddingObj != null) { 576 if (padBufferLen != 0) { 577 // NSS throws up when called with data not in multiple 578 // of blocks. Try to work around this by holding the 579 // extra data in padBuffer. 580 if (padBufferLen != padBuffer.length) { 581 int bufCapacity = padBuffer.length - padBufferLen; 582 if (inLen > bufCapacity) { 583 bufferInputBytes(in, inOfs, bufCapacity); 584 inOfs += bufCapacity; 585 inLen -= bufCapacity; 586 } else { 587 bufferInputBytes(in, inOfs, inLen); 588 return 0; 589 } 590 } 591 k = token.p11.C_DecryptUpdate(session.id(), 592 0, padBuffer, 0, padBufferLen, 593 0, out, outOfs, outLen); 594 padBufferLen = 0; 595 } 596 newPadBufferLen = inLen & (blockSize - 1); 597 if (newPadBufferLen == 0) { 598 newPadBufferLen = padBuffer.length; 599 } 600 inLen -= newPadBufferLen; 601 } 602 if (inLen > 0) { 603 k += token.p11.C_DecryptUpdate(session.id(), 0, in, inOfs, 604 inLen, 0, out, (outOfs + k), (outLen - k)); 605 } 606 // update 'padBuffer' if using our own padding impl. 607 if (paddingObj != null) { 608 bufferInputBytes(in, inOfs + inLen, newPadBufferLen); 609 } 610 } 611 bytesBuffered += (inLen - k); 612 return k; 613 } catch (PKCS11Exception e) { 614 if (e.getErrorCode() == CKR_BUFFER_TOO_SMALL) { 615 throw (ShortBufferException) 616 (new ShortBufferException().initCause(e)); 617 } 618 reset(false); 619 throw new ProviderException("update() failed", e); 620 } 621 } 622 623 private int implUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer) 624 throws ShortBufferException { 625 int inLen = inBuffer.remaining(); 626 if (inLen <= 0) { 627 return 0; 628 } 629 630 int outLen = outBuffer.remaining(); 631 if (outLen < updateLength(inLen)) { 632 throw new ShortBufferException(); 633 } 634 int origPos = inBuffer.position(); 635 try { 636 ensureInitialized(); 637 638 long inAddr = 0; 639 int inOfs = 0; 640 byte[] inArray = null; 641 642 if (inBuffer instanceof DirectBuffer) { 643 inAddr = ((DirectBuffer) inBuffer).address(); 644 inOfs = origPos; 645 } else if (inBuffer.hasArray()) { 646 inArray = inBuffer.array(); 647 inOfs = (origPos + inBuffer.arrayOffset()); 648 } 649 650 long outAddr = 0; 651 int outOfs = 0; 652 byte[] outArray = null; 653 if (outBuffer instanceof DirectBuffer) { 654 outAddr = ((DirectBuffer) outBuffer).address(); 655 outOfs = outBuffer.position(); 656 } else { 657 if (outBuffer.hasArray()) { 658 outArray = outBuffer.array(); 659 outOfs = (outBuffer.position() + outBuffer.arrayOffset()); 660 } else { 661 outArray = new byte[outLen]; 662 } 663 } 664 665 int k = 0; 666 if (encrypt) { 667 if (inAddr == 0 && inArray == null) { 668 inArray = new byte[inLen]; 669 inBuffer.get(inArray); 670 } else { 671 inBuffer.position(origPos + inLen); 672 } 673 k = token.p11.C_EncryptUpdate(session.id(), 674 inAddr, inArray, inOfs, inLen, 675 outAddr, outArray, outOfs, outLen); 676 } else { 677 int newPadBufferLen = 0; 678 if (paddingObj != null) { 679 if (padBufferLen != 0) { 680 // NSS throws up when called with data not in multiple 681 // of blocks. Try to work around this by holding the 682 // extra data in padBuffer. 683 if (padBufferLen != padBuffer.length) { 684 int bufCapacity = padBuffer.length - padBufferLen; 685 if (inLen > bufCapacity) { 686 bufferInputBytes(inBuffer, bufCapacity); 687 inOfs += bufCapacity; 688 inLen -= bufCapacity; 689 } else { 690 bufferInputBytes(inBuffer, inLen); 691 return 0; 692 } 693 } 694 k = token.p11.C_DecryptUpdate(session.id(), 0, 695 padBuffer, 0, padBufferLen, outAddr, outArray, 696 outOfs, outLen); 697 padBufferLen = 0; 698 } 699 newPadBufferLen = inLen & (blockSize - 1); 700 if (newPadBufferLen == 0) { 701 newPadBufferLen = padBuffer.length; 702 } 703 inLen -= newPadBufferLen; 704 } 705 if (inLen > 0) { 706 if (inAddr == 0 && inArray == null) { 707 inArray = new byte[inLen]; 708 inBuffer.get(inArray); 709 } else { 710 inBuffer.position(inBuffer.position() + inLen); 711 } 712 k += token.p11.C_DecryptUpdate(session.id(), inAddr, 713 inArray, inOfs, inLen, outAddr, outArray, 714 (outOfs + k), (outLen - k)); 715 } 716 // update 'padBuffer' if using our own padding impl. 717 if (paddingObj != null && newPadBufferLen != 0) { 718 bufferInputBytes(inBuffer, newPadBufferLen); 719 } 720 } 721 bytesBuffered += (inLen - k); 722 if (!(outBuffer instanceof DirectBuffer) && 723 !outBuffer.hasArray()) { 724 outBuffer.put(outArray, outOfs, k); 725 } else { 726 outBuffer.position(outBuffer.position() + k); 727 } 728 return k; 729 } catch (PKCS11Exception e) { 730 // Reset input buffer to its original position for 731 inBuffer.position(origPos); 732 if (e.getErrorCode() == CKR_BUFFER_TOO_SMALL) { 733 throw (ShortBufferException) 734 (new ShortBufferException().initCause(e)); 735 } 736 reset(false); 737 throw new ProviderException("update() failed", e); 738 } 739 } 740 741 private int implDoFinal(byte[] out, int outOfs, int outLen) 742 throws ShortBufferException, IllegalBlockSizeException, 743 BadPaddingException { 744 int requiredOutLen = doFinalLength(0); 745 if (outLen < requiredOutLen) { 746 throw new ShortBufferException(); 747 } 748 boolean doCancel = true; 749 try { 750 ensureInitialized(); 751 int k = 0; 752 if (encrypt) { 753 if (paddingObj != null) { 754 int actualPadLen = paddingObj.setPaddingBytes(padBuffer, 755 requiredOutLen - bytesBuffered); 756 k = token.p11.C_EncryptUpdate(session.id(), 757 0, padBuffer, 0, actualPadLen, 758 0, out, outOfs, outLen); 759 } 760 k += token.p11.C_EncryptFinal(session.id(), 761 0, out, (outOfs + k), (outLen - k)); 762 doCancel = false; 763 } else { 764 // Special handling to match SunJCE provider behavior 765 if (bytesBuffered == 0 && padBufferLen == 0) { 766 return 0; 767 } 768 if (paddingObj != null) { 769 if (padBufferLen != 0) { 770 k = token.p11.C_DecryptUpdate(session.id(), 0, 771 padBuffer, 0, padBufferLen, 0, padBuffer, 0, 772 padBuffer.length); 773 } 774 k += token.p11.C_DecryptFinal(session.id(), 0, padBuffer, k, 775 padBuffer.length - k); 776 doCancel = false; 777 778 int actualPadLen = paddingObj.unpad(padBuffer, k); 779 k -= actualPadLen; 780 System.arraycopy(padBuffer, 0, out, outOfs, k); 781 } else { 782 k = token.p11.C_DecryptFinal(session.id(), 0, out, outOfs, 783 outLen); 784 doCancel = false; 785 } 786 } 787 return k; 788 } catch (PKCS11Exception e) { 789 doCancel = false; 790 handleException(e); 791 throw new ProviderException("doFinal() failed", e); 792 } finally { 793 reset(doCancel); 794 } 795 } 796 797 private int implDoFinal(ByteBuffer outBuffer) 798 throws ShortBufferException, IllegalBlockSizeException, 799 BadPaddingException { 800 int outLen = outBuffer.remaining(); 801 int requiredOutLen = doFinalLength(0); 802 if (outLen < requiredOutLen) { 803 throw new ShortBufferException(); 804 } 805 806 boolean doCancel = true; 807 try { 808 ensureInitialized(); 809 810 long outAddr = 0; 811 byte[] outArray = null; 812 int outOfs = 0; 813 if (outBuffer instanceof DirectBuffer) { 814 outAddr = ((DirectBuffer) outBuffer).address(); 815 outOfs = outBuffer.position(); 816 } else { 817 if (outBuffer.hasArray()) { 818 outArray = outBuffer.array(); 819 outOfs = outBuffer.position() + outBuffer.arrayOffset(); 820 } else { 821 outArray = new byte[outLen]; 822 } 823 } 824 825 int k = 0; 826 827 if (encrypt) { 828 if (paddingObj != null) { 829 int actualPadLen = paddingObj.setPaddingBytes(padBuffer, 830 requiredOutLen - bytesBuffered); 831 k = token.p11.C_EncryptUpdate(session.id(), 832 0, padBuffer, 0, actualPadLen, 833 outAddr, outArray, outOfs, outLen); 834 } 835 k += token.p11.C_EncryptFinal(session.id(), 836 outAddr, outArray, (outOfs + k), (outLen - k)); 837 doCancel = false; 838 } else { 839 // Special handling to match SunJCE provider behavior 840 if (bytesBuffered == 0 && padBufferLen == 0) { 841 return 0; 842 } 843 844 if (paddingObj != null) { 845 if (padBufferLen != 0) { 846 k = token.p11.C_DecryptUpdate(session.id(), 847 0, padBuffer, 0, padBufferLen, 848 0, padBuffer, 0, padBuffer.length); 849 padBufferLen = 0; 850 } 851 k += token.p11.C_DecryptFinal(session.id(), 852 0, padBuffer, k, padBuffer.length - k); 853 doCancel = false; 854 855 int actualPadLen = paddingObj.unpad(padBuffer, k); 856 k -= actualPadLen; 857 outArray = padBuffer; 858 outOfs = 0; 859 } else { 860 k = token.p11.C_DecryptFinal(session.id(), 861 outAddr, outArray, outOfs, outLen); 862 doCancel = false; 863 } 864 } 865 if ((!encrypt && paddingObj != null) || 866 (!(outBuffer instanceof DirectBuffer) && 867 !outBuffer.hasArray())) { 868 outBuffer.put(outArray, outOfs, k); 869 } else { 870 outBuffer.position(outBuffer.position() + k); 871 } 872 return k; 873 } catch (PKCS11Exception e) { 874 doCancel = false; 875 handleException(e); 876 throw new ProviderException("doFinal() failed", e); 877 } finally { 878 reset(doCancel); 879 } 880 } 881 882 private void handleException(PKCS11Exception e) 883 throws ShortBufferException, IllegalBlockSizeException { 884 long errorCode = e.getErrorCode(); 885 if (errorCode == CKR_BUFFER_TOO_SMALL) { 886 throw (ShortBufferException) 887 (new ShortBufferException().initCause(e)); 888 } else if (errorCode == CKR_DATA_LEN_RANGE || 889 errorCode == CKR_ENCRYPTED_DATA_LEN_RANGE) { 890 throw (IllegalBlockSizeException) 891 (new IllegalBlockSizeException(e.toString()).initCause(e)); 892 } 893 } 894 895 // see JCE spec 896 protected byte[] engineWrap(Key key) throws IllegalBlockSizeException, 897 InvalidKeyException { 898 // XXX key wrapping 899 throw new UnsupportedOperationException("engineWrap()"); 900 } 901 902 // see JCE spec 903 protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, 904 int wrappedKeyType) 905 throws InvalidKeyException, NoSuchAlgorithmException { 906 // XXX key unwrapping 907 throw new UnsupportedOperationException("engineUnwrap()"); 908 } 909 910 // see JCE spec 911 @Override 912 protected int engineGetKeySize(Key key) throws InvalidKeyException { 913 int n = P11SecretKeyFactory.convertKey 914 (token, key, keyAlgorithm).length(); 915 return n; 916 } 917 918 private final void bufferInputBytes(byte[] in, int inOfs, int len) { 919 System.arraycopy(in, inOfs, padBuffer, padBufferLen, len); 920 padBufferLen += len; 921 bytesBuffered += len; 922 } 923 924 private final void bufferInputBytes(ByteBuffer inBuffer, int len) { 925 inBuffer.get(padBuffer, padBufferLen, len); 926 padBufferLen += len; 927 bytesBuffered += len; 928 } 929 }