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