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