Path: blob/jdk8u272-b10-aarch32-20201026/jdk/src/share/classes/sun/security/pkcs11/P11Cipher.java
83409 views
/*1* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/24package sun.security.pkcs11;2526import java.nio.ByteBuffer;27import java.util.Arrays;28import java.util.Locale;2930import java.security.*;31import java.security.spec.*;3233import javax.crypto.*;34import javax.crypto.spec.*;3536import sun.nio.ch.DirectBuffer;37import sun.security.jca.JCAUtil;38import sun.security.pkcs11.wrapper.*;39import static sun.security.pkcs11.wrapper.PKCS11Constants.*;4041/**42* Cipher implementation class. This class currently supports43* DES, DESede, AES, ARCFOUR, and Blowfish.44*45* This class is designed to support ECB, CBC, CTR with NoPadding46* and ECB, CBC with PKCS5Padding. It will use its own padding impl47* if the native mechanism does not support padding.48*49* Note that PKCS#11 currently only supports ECB, CBC, and CTR.50* There are no provisions for other modes such as CFB, OFB, and PCBC.51*52* @author Andreas Sterbenz53* @since 1.554*/55final class P11Cipher extends CipherSpi {5657// mode constant for ECB mode58private final static int MODE_ECB = 3;59// mode constant for CBC mode60private final static int MODE_CBC = 4;61// mode constant for CTR mode62private final static int MODE_CTR = 5;6364// padding constant for NoPadding65private final static int PAD_NONE = 5;66// padding constant for PKCS5Padding67private final static int PAD_PKCS5 = 6;6869private static interface Padding {70// ENC: format the specified buffer with padding bytes and return the71// actual padding length72int setPaddingBytes(byte[] paddingBuffer, int padLen);7374// DEC: return the length of trailing padding bytes given the specified75// padded data76int unpad(byte[] paddedData, int len)77throws BadPaddingException, IllegalBlockSizeException;78}7980private static class PKCS5Padding implements Padding {8182private final int blockSize;8384PKCS5Padding(int blockSize)85throws NoSuchPaddingException {86if (blockSize == 0) {87throw new NoSuchPaddingException88("PKCS#5 padding not supported with stream ciphers");89}90this.blockSize = blockSize;91}9293public int setPaddingBytes(byte[] paddingBuffer, int padLen) {94Arrays.fill(paddingBuffer, 0, padLen, (byte) (padLen & 0x007f));95return padLen;96}9798public int unpad(byte[] paddedData, int len)99throws BadPaddingException, IllegalBlockSizeException {100if ((len < 1) || (len % blockSize != 0)) {101throw new IllegalBlockSizeException102("Input length must be multiples of " + blockSize);103}104byte padValue = paddedData[len - 1];105if (padValue < 1 || padValue > blockSize) {106throw new BadPaddingException("Invalid pad value!");107}108// sanity check padding bytes109int padStartIndex = len - padValue;110for (int i = padStartIndex; i < len; i++) {111if (paddedData[i] != padValue) {112throw new BadPaddingException("Invalid pad bytes!");113}114}115return padValue;116}117}118119// token instance120private final Token token;121122// algorithm name123private final String algorithm;124125// name of the key algorithm, e.g. DES instead of algorithm DES/CBC/...126private final String keyAlgorithm;127128// mechanism id129private final long mechanism;130131// associated session, if any132private Session session;133134// key, if init() was called135private P11Key p11Key;136137// flag indicating whether an operation is initialized138private boolean initialized;139140// falg indicating encrypt or decrypt mode141private boolean encrypt;142143// mode, one of MODE_* above (MODE_ECB for stream ciphers)144private int blockMode;145146// block size, 0 for stream ciphers147private final int blockSize;148149// padding type, on of PAD_* above (PAD_NONE for stream ciphers)150private int paddingType;151152// when the padding is requested but unsupported by the native mechanism,153// we use the following to do padding and necessary data buffering.154// padding object which generate padding and unpad the decrypted data155private Padding paddingObj;156// buffer for holding back the block which contains padding bytes157private byte[] padBuffer;158private int padBufferLen;159160// original IV, if in MODE_CBC or MODE_CTR161private byte[] iv;162163// number of bytes buffered internally by the native mechanism and padBuffer164// if we do the padding165private int bytesBuffered;166167// length of key size in bytes; currently only used by AES given its oid168// specification mandates a fixed size of the key169private int fixedKeySize = -1;170171P11Cipher(Token token, String algorithm, long mechanism)172throws PKCS11Exception, NoSuchAlgorithmException {173super();174this.token = token;175this.algorithm = algorithm;176this.mechanism = mechanism;177178String algoParts[] = algorithm.split("/");179180if (algoParts[0].startsWith("AES")) {181blockSize = 16;182int index = algoParts[0].indexOf('_');183if (index != -1) {184// should be well-formed since we specify what we support185fixedKeySize = Integer.parseInt(algoParts[0].substring(index+1))/8;186}187keyAlgorithm = "AES";188} else {189keyAlgorithm = algoParts[0];190if (keyAlgorithm.equals("RC4") ||191keyAlgorithm.equals("ARCFOUR")) {192blockSize = 0;193} else { // DES, DESede, Blowfish194blockSize = 8;195}196}197this.blockMode =198(algoParts.length > 1 ? parseMode(algoParts[1]) : MODE_ECB);199String defPadding = (blockSize == 0 ? "NoPadding" : "PKCS5Padding");200String paddingStr =201(algoParts.length > 2 ? algoParts[2] : defPadding);202try {203engineSetPadding(paddingStr);204} catch (NoSuchPaddingException nspe) {205// should not happen206throw new ProviderException(nspe);207}208}209210protected void engineSetMode(String mode) throws NoSuchAlgorithmException {211// Disallow change of mode for now since currently it's explicitly212// defined in transformation strings213throw new NoSuchAlgorithmException("Unsupported mode " + mode);214}215216private int parseMode(String mode) throws NoSuchAlgorithmException {217mode = mode.toUpperCase(Locale.ENGLISH);218int result;219if (mode.equals("ECB")) {220result = MODE_ECB;221} else if (mode.equals("CBC")) {222if (blockSize == 0) {223throw new NoSuchAlgorithmException224("CBC mode not supported with stream ciphers");225}226result = MODE_CBC;227} else if (mode.equals("CTR")) {228result = MODE_CTR;229} else {230throw new NoSuchAlgorithmException("Unsupported mode " + mode);231}232return result;233}234235// see JCE spec236protected void engineSetPadding(String padding)237throws NoSuchPaddingException {238paddingObj = null;239padBuffer = null;240padding = padding.toUpperCase(Locale.ENGLISH);241if (padding.equals("NOPADDING")) {242paddingType = PAD_NONE;243} else if (padding.equals("PKCS5PADDING")) {244if (this.blockMode == MODE_CTR) {245throw new NoSuchPaddingException246("PKCS#5 padding not supported with CTR mode");247}248paddingType = PAD_PKCS5;249if (mechanism != CKM_DES_CBC_PAD && mechanism != CKM_DES3_CBC_PAD &&250mechanism != CKM_AES_CBC_PAD) {251// no native padding support; use our own padding impl252paddingObj = new PKCS5Padding(blockSize);253padBuffer = new byte[blockSize];254}255} else {256throw new NoSuchPaddingException("Unsupported padding " + padding);257}258}259260// see JCE spec261protected int engineGetBlockSize() {262return blockSize;263}264265// see JCE spec266protected int engineGetOutputSize(int inputLen) {267return doFinalLength(inputLen);268}269270// see JCE spec271protected byte[] engineGetIV() {272return (iv == null) ? null : iv.clone();273}274275// see JCE spec276protected AlgorithmParameters engineGetParameters() {277if (iv == null) {278return null;279}280IvParameterSpec ivSpec = new IvParameterSpec(iv);281try {282AlgorithmParameters params =283AlgorithmParameters.getInstance(keyAlgorithm,284P11Util.getSunJceProvider());285params.init(ivSpec);286return params;287} catch (GeneralSecurityException e) {288// NoSuchAlgorithmException, NoSuchProviderException289// InvalidParameterSpecException290throw new ProviderException("Could not encode parameters", e);291}292}293294// see JCE spec295protected void engineInit(int opmode, Key key, SecureRandom random)296throws InvalidKeyException {297try {298implInit(opmode, key, null, random);299} catch (InvalidAlgorithmParameterException e) {300throw new InvalidKeyException("init() failed", e);301}302}303304// see JCE spec305protected void engineInit(int opmode, Key key,306AlgorithmParameterSpec params, SecureRandom random)307throws InvalidKeyException, InvalidAlgorithmParameterException {308byte[] ivValue;309if (params != null) {310if (params instanceof IvParameterSpec == false) {311throw new InvalidAlgorithmParameterException312("Only IvParameterSpec supported");313}314IvParameterSpec ivSpec = (IvParameterSpec) params;315ivValue = ivSpec.getIV();316} else {317ivValue = null;318}319implInit(opmode, key, ivValue, random);320}321322// see JCE spec323protected void engineInit(int opmode, Key key, AlgorithmParameters params,324SecureRandom random)325throws InvalidKeyException, InvalidAlgorithmParameterException {326byte[] ivValue;327if (params != null) {328try {329IvParameterSpec ivSpec =330params.getParameterSpec(IvParameterSpec.class);331ivValue = ivSpec.getIV();332} catch (InvalidParameterSpecException e) {333throw new InvalidAlgorithmParameterException334("Could not decode IV", e);335}336} else {337ivValue = null;338}339implInit(opmode, key, ivValue, random);340}341342// actual init() implementation343private void implInit(int opmode, Key key, byte[] iv,344SecureRandom random)345throws InvalidKeyException, InvalidAlgorithmParameterException {346reset(true);347if (fixedKeySize != -1 &&348((key instanceof P11Key) ? ((P11Key) key).length() >> 3 :349key.getEncoded().length) != fixedKeySize) {350throw new InvalidKeyException("Key size is invalid");351}352switch (opmode) {353case Cipher.ENCRYPT_MODE:354encrypt = true;355break;356case Cipher.DECRYPT_MODE:357encrypt = false;358break;359default:360throw new InvalidAlgorithmParameterException361("Unsupported mode: " + opmode);362}363if (blockMode == MODE_ECB) { // ECB or stream cipher364if (iv != null) {365if (blockSize == 0) {366throw new InvalidAlgorithmParameterException367("IV not used with stream ciphers");368} else {369throw new InvalidAlgorithmParameterException370("IV not used in ECB mode");371}372}373} else { // MODE_CBC or MODE_CTR374if (iv == null) {375if (encrypt == false) {376String exMsg =377(blockMode == MODE_CBC ?378"IV must be specified for decryption in CBC mode" :379"IV must be specified for decryption in CTR mode");380throw new InvalidAlgorithmParameterException(exMsg);381}382// generate random IV383if (random == null) {384random = JCAUtil.getSecureRandom();385}386iv = new byte[blockSize];387random.nextBytes(iv);388} else {389if (iv.length != blockSize) {390throw new InvalidAlgorithmParameterException391("IV length must match block size");392}393}394}395this.iv = iv;396p11Key = P11SecretKeyFactory.convertKey(token, key, keyAlgorithm);397try {398initialize();399} catch (PKCS11Exception e) {400throw new InvalidKeyException("Could not initialize cipher", e);401}402}403404// reset the states to the pre-initialized values405// need to be called after doFinal or prior to re-init406private void reset(boolean doCancel) {407if (!initialized) {408return;409}410initialized = false;411412try {413if (session == null) {414return;415}416417if (doCancel && token.explicitCancel) {418cancelOperation();419}420} finally {421p11Key.releaseKeyID();422session = token.releaseSession(session);423bytesBuffered = 0;424padBufferLen = 0;425}426}427428private void cancelOperation() {429token.ensureValid();430// cancel operation by finishing it; avoid killSession as some431// hardware vendors may require re-login432try {433int bufLen = doFinalLength(0);434byte[] buffer = new byte[bufLen];435if (encrypt) {436token.p11.C_EncryptFinal(session.id(), 0, buffer, 0, bufLen);437} else {438token.p11.C_DecryptFinal(session.id(), 0, buffer, 0, bufLen);439}440} catch (PKCS11Exception e) {441if (e.getErrorCode() == CKR_OPERATION_NOT_INITIALIZED) {442// Cancel Operation may be invoked after an error on a PKCS#11443// call. If the operation inside the token was already cancelled,444// do not fail here. This is part of a defensive mechanism for445// PKCS#11 libraries that do not strictly follow the standard.446return;447}448if (encrypt) {449throw new ProviderException("Cancel failed", e);450}451// ignore failure for decryption452}453}454455private void ensureInitialized() throws PKCS11Exception {456if (!initialized) {457initialize();458}459}460461private void initialize() throws PKCS11Exception {462if (p11Key == null) {463throw new ProviderException(464"Operation cannot be performed without"465+ " calling engineInit first");466}467token.ensureValid();468long p11KeyID = p11Key.getKeyID();469try {470if (session == null) {471session = token.getOpSession();472}473CK_MECHANISM mechParams = (blockMode == MODE_CTR?474new CK_MECHANISM(mechanism, new CK_AES_CTR_PARAMS(iv)) :475new CK_MECHANISM(mechanism, iv));476if (encrypt) {477token.p11.C_EncryptInit(session.id(), mechParams, p11KeyID);478} else {479token.p11.C_DecryptInit(session.id(), mechParams, p11KeyID);480}481} catch (PKCS11Exception e) {482p11Key.releaseKeyID();483session = token.releaseSession(session);484throw e;485}486initialized = true;487bytesBuffered = 0;488padBufferLen = 0;489}490491// if update(inLen) is called, how big does the output buffer have to be?492private int updateLength(int inLen) {493if (inLen <= 0) {494return 0;495}496497int result = inLen + bytesBuffered;498if (blockSize != 0 && blockMode != MODE_CTR) {499// minus the number of bytes in the last incomplete block.500result -= (result & (blockSize - 1));501}502return result;503}504505// if doFinal(inLen) is called, how big does the output buffer have to be?506private int doFinalLength(int inLen) {507if (inLen < 0) {508return 0;509}510511int result = inLen + bytesBuffered;512if (blockSize != 0 && encrypt && paddingType != PAD_NONE) {513// add the number of bytes to make the last block complete.514result += (blockSize - (result & (blockSize - 1)));515}516return result;517}518519// see JCE spec520protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) {521try {522byte[] out = new byte[updateLength(inLen)];523int n = engineUpdate(in, inOfs, inLen, out, 0);524return P11Util.convert(out, 0, n);525} catch (ShortBufferException e) {526// convert since the output length is calculated by updateLength()527throw new ProviderException(e);528}529}530531// see JCE spec532protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out,533int outOfs) throws ShortBufferException {534int outLen = out.length - outOfs;535return implUpdate(in, inOfs, inLen, out, outOfs, outLen);536}537538// see JCE spec539@Override540protected int engineUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer)541throws ShortBufferException {542return implUpdate(inBuffer, outBuffer);543}544545// see JCE spec546protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen)547throws IllegalBlockSizeException, BadPaddingException {548try {549byte[] out = new byte[doFinalLength(inLen)];550int n = engineDoFinal(in, inOfs, inLen, out, 0);551return P11Util.convert(out, 0, n);552} catch (ShortBufferException e) {553// convert since the output length is calculated by doFinalLength()554throw new ProviderException(e);555}556}557558// see JCE spec559protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out,560int outOfs) throws ShortBufferException, IllegalBlockSizeException,561BadPaddingException {562int n = 0;563if ((inLen != 0) && (in != null)) {564n = engineUpdate(in, inOfs, inLen, out, outOfs);565outOfs += n;566}567n += implDoFinal(out, outOfs, out.length - outOfs);568return n;569}570571// see JCE spec572@Override573protected int engineDoFinal(ByteBuffer inBuffer, ByteBuffer outBuffer)574throws ShortBufferException, IllegalBlockSizeException,575BadPaddingException {576int n = engineUpdate(inBuffer, outBuffer);577n += implDoFinal(outBuffer);578return n;579}580581private int implUpdate(byte[] in, int inOfs, int inLen,582byte[] out, int outOfs, int outLen) throws ShortBufferException {583if (outLen < updateLength(inLen)) {584throw new ShortBufferException();585}586try {587ensureInitialized();588int k = 0;589if (encrypt) {590k = token.p11.C_EncryptUpdate(session.id(), 0, in, inOfs, inLen,5910, out, outOfs, outLen);592} else {593int newPadBufferLen = 0;594if (paddingObj != null) {595if (padBufferLen != 0) {596// NSS throws up when called with data not in multiple597// of blocks. Try to work around this by holding the598// extra data in padBuffer.599if (padBufferLen != padBuffer.length) {600int bufCapacity = padBuffer.length - padBufferLen;601if (inLen > bufCapacity) {602bufferInputBytes(in, inOfs, bufCapacity);603inOfs += bufCapacity;604inLen -= bufCapacity;605} else {606bufferInputBytes(in, inOfs, inLen);607return 0;608}609}610k = token.p11.C_DecryptUpdate(session.id(),6110, padBuffer, 0, padBufferLen,6120, out, outOfs, outLen);613padBufferLen = 0;614}615newPadBufferLen = inLen & (blockSize - 1);616if (newPadBufferLen == 0) {617newPadBufferLen = padBuffer.length;618}619inLen -= newPadBufferLen;620}621if (inLen > 0) {622k += token.p11.C_DecryptUpdate(session.id(), 0, in, inOfs,623inLen, 0, out, (outOfs + k), (outLen - k));624}625// update 'padBuffer' if using our own padding impl.626if (paddingObj != null) {627bufferInputBytes(in, inOfs + inLen, newPadBufferLen);628}629}630bytesBuffered += (inLen - k);631return k;632} catch (PKCS11Exception e) {633if (e.getErrorCode() == CKR_BUFFER_TOO_SMALL) {634throw (ShortBufferException)635(new ShortBufferException().initCause(e));636}637// Some implementations such as the NSS Software Token do not638// cancel the operation upon a C_EncryptUpdate/C_DecryptUpdate639// failure (as required by the PKCS#11 standard). See JDK-8258833640// for further information.641reset(true);642throw new ProviderException("update() failed", e);643}644}645646private int implUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer)647throws ShortBufferException {648int inLen = inBuffer.remaining();649if (inLen <= 0) {650return 0;651}652653int outLen = outBuffer.remaining();654if (outLen < updateLength(inLen)) {655throw new ShortBufferException();656}657int origPos = inBuffer.position();658try {659ensureInitialized();660661long inAddr = 0;662int inOfs = 0;663byte[] inArray = null;664665if (inBuffer instanceof DirectBuffer) {666inAddr = ((DirectBuffer) inBuffer).address();667inOfs = origPos;668} else if (inBuffer.hasArray()) {669inArray = inBuffer.array();670inOfs = (origPos + inBuffer.arrayOffset());671}672673long outAddr = 0;674int outOfs = 0;675byte[] outArray = null;676if (outBuffer instanceof DirectBuffer) {677outAddr = ((DirectBuffer) outBuffer).address();678outOfs = outBuffer.position();679} else {680if (outBuffer.hasArray()) {681outArray = outBuffer.array();682outOfs = (outBuffer.position() + outBuffer.arrayOffset());683} else {684outArray = new byte[outLen];685}686}687688int k = 0;689if (encrypt) {690if (inAddr == 0 && inArray == null) {691inArray = new byte[inLen];692inBuffer.get(inArray);693} else {694inBuffer.position(origPos + inLen);695}696k = token.p11.C_EncryptUpdate(session.id(),697inAddr, inArray, inOfs, inLen,698outAddr, outArray, outOfs, outLen);699} else {700int newPadBufferLen = 0;701if (paddingObj != null) {702if (padBufferLen != 0) {703// NSS throws up when called with data not in multiple704// of blocks. Try to work around this by holding the705// extra data in padBuffer.706if (padBufferLen != padBuffer.length) {707int bufCapacity = padBuffer.length - padBufferLen;708if (inLen > bufCapacity) {709bufferInputBytes(inBuffer, bufCapacity);710inOfs += bufCapacity;711inLen -= bufCapacity;712} else {713bufferInputBytes(inBuffer, inLen);714return 0;715}716}717k = token.p11.C_DecryptUpdate(session.id(), 0,718padBuffer, 0, padBufferLen, outAddr, outArray,719outOfs, outLen);720padBufferLen = 0;721}722newPadBufferLen = inLen & (blockSize - 1);723if (newPadBufferLen == 0) {724newPadBufferLen = padBuffer.length;725}726inLen -= newPadBufferLen;727}728if (inLen > 0) {729if (inAddr == 0 && inArray == null) {730inArray = new byte[inLen];731inBuffer.get(inArray);732} else {733inBuffer.position(inBuffer.position() + inLen);734}735k += token.p11.C_DecryptUpdate(session.id(), inAddr,736inArray, inOfs, inLen, outAddr, outArray,737(outOfs + k), (outLen - k));738}739// update 'padBuffer' if using our own padding impl.740if (paddingObj != null && newPadBufferLen != 0) {741bufferInputBytes(inBuffer, newPadBufferLen);742}743}744bytesBuffered += (inLen - k);745if (!(outBuffer instanceof DirectBuffer) &&746!outBuffer.hasArray()) {747outBuffer.put(outArray, outOfs, k);748} else {749outBuffer.position(outBuffer.position() + k);750}751return k;752} catch (PKCS11Exception e) {753// Reset input buffer to its original position for754inBuffer.position(origPos);755if (e.getErrorCode() == CKR_BUFFER_TOO_SMALL) {756throw (ShortBufferException)757(new ShortBufferException().initCause(e));758}759// Some implementations such as the NSS Software Token do not760// cancel the operation upon a C_EncryptUpdate/C_DecryptUpdate761// failure (as required by the PKCS#11 standard). See JDK-8258833762// for further information.763reset(true);764throw new ProviderException("update() failed", e);765}766}767768private int implDoFinal(byte[] out, int outOfs, int outLen)769throws ShortBufferException, IllegalBlockSizeException,770BadPaddingException {771int requiredOutLen = doFinalLength(0);772if (outLen < requiredOutLen) {773throw new ShortBufferException();774}775boolean doCancel = true;776try {777ensureInitialized();778int k = 0;779if (encrypt) {780if (paddingObj != null) {781int actualPadLen = paddingObj.setPaddingBytes(padBuffer,782requiredOutLen - bytesBuffered);783k = token.p11.C_EncryptUpdate(session.id(),7840, padBuffer, 0, actualPadLen,7850, out, outOfs, outLen);786}787// Some implementations such as the NSS Software Token do not788// cancel the operation upon a C_EncryptUpdate failure (as789// required by the PKCS#11 standard). Cancel is not needed790// only after this point. See JDK-8258833 for further791// information.792doCancel = false;793k += token.p11.C_EncryptFinal(session.id(),7940, out, (outOfs + k), (outLen - k));795} else {796// Special handling to match SunJCE provider behavior797if (bytesBuffered == 0 && padBufferLen == 0) {798return 0;799}800if (paddingObj != null) {801if (padBufferLen != 0) {802k = token.p11.C_DecryptUpdate(session.id(), 0,803padBuffer, 0, padBufferLen, 0, padBuffer, 0,804padBuffer.length);805}806// Some implementations such as the NSS Software Token do not807// cancel the operation upon a C_DecryptUpdate failure (as808// required by the PKCS#11 standard). Cancel is not needed809// only after this point. See JDK-8258833 for further810// information.811doCancel = false;812k += token.p11.C_DecryptFinal(session.id(), 0, padBuffer, k,813padBuffer.length - k);814815int actualPadLen = paddingObj.unpad(padBuffer, k);816k -= actualPadLen;817System.arraycopy(padBuffer, 0, out, outOfs, k);818} else {819doCancel = false;820k = token.p11.C_DecryptFinal(session.id(), 0, out, outOfs,821outLen);822}823}824return k;825} catch (PKCS11Exception e) {826handleException(e);827throw new ProviderException("doFinal() failed", e);828} finally {829reset(doCancel);830}831}832833private int implDoFinal(ByteBuffer outBuffer)834throws ShortBufferException, IllegalBlockSizeException,835BadPaddingException {836int outLen = outBuffer.remaining();837int requiredOutLen = doFinalLength(0);838if (outLen < requiredOutLen) {839throw new ShortBufferException();840}841842boolean doCancel = true;843try {844ensureInitialized();845846long outAddr = 0;847byte[] outArray = null;848int outOfs = 0;849if (outBuffer instanceof DirectBuffer) {850outAddr = ((DirectBuffer) outBuffer).address();851outOfs = outBuffer.position();852} else {853if (outBuffer.hasArray()) {854outArray = outBuffer.array();855outOfs = outBuffer.position() + outBuffer.arrayOffset();856} else {857outArray = new byte[outLen];858}859}860861int k = 0;862863if (encrypt) {864if (paddingObj != null) {865int actualPadLen = paddingObj.setPaddingBytes(padBuffer,866requiredOutLen - bytesBuffered);867k = token.p11.C_EncryptUpdate(session.id(),8680, padBuffer, 0, actualPadLen,869outAddr, outArray, outOfs, outLen);870}871// Some implementations such as the NSS Software Token do not872// cancel the operation upon a C_EncryptUpdate failure (as873// required by the PKCS#11 standard). Cancel is not needed874// only after this point. See JDK-8258833 for further875// information.876doCancel = false;877k += token.p11.C_EncryptFinal(session.id(),878outAddr, outArray, (outOfs + k), (outLen - k));879} else {880// Special handling to match SunJCE provider behavior881if (bytesBuffered == 0 && padBufferLen == 0) {882return 0;883}884885if (paddingObj != null) {886if (padBufferLen != 0) {887k = token.p11.C_DecryptUpdate(session.id(),8880, padBuffer, 0, padBufferLen,8890, padBuffer, 0, padBuffer.length);890padBufferLen = 0;891}892// Some implementations such as the NSS Software Token do not893// cancel the operation upon a C_DecryptUpdate failure (as894// required by the PKCS#11 standard). Cancel is not needed895// only after this point. See JDK-8258833 for further896// information.897doCancel = false;898k += token.p11.C_DecryptFinal(session.id(),8990, padBuffer, k, padBuffer.length - k);900901int actualPadLen = paddingObj.unpad(padBuffer, k);902k -= actualPadLen;903outArray = padBuffer;904outOfs = 0;905} else {906doCancel = false;907k = token.p11.C_DecryptFinal(session.id(),908outAddr, outArray, outOfs, outLen);909}910}911if ((!encrypt && paddingObj != null) ||912(!(outBuffer instanceof DirectBuffer) &&913!outBuffer.hasArray())) {914outBuffer.put(outArray, outOfs, k);915} else {916outBuffer.position(outBuffer.position() + k);917}918return k;919} catch (PKCS11Exception e) {920handleException(e);921throw new ProviderException("doFinal() failed", e);922} finally {923reset(doCancel);924}925}926927private void handleException(PKCS11Exception e)928throws ShortBufferException, IllegalBlockSizeException {929long errorCode = e.getErrorCode();930if (errorCode == CKR_BUFFER_TOO_SMALL) {931throw (ShortBufferException)932(new ShortBufferException().initCause(e));933} else if (errorCode == CKR_DATA_LEN_RANGE ||934errorCode == CKR_ENCRYPTED_DATA_LEN_RANGE) {935throw (IllegalBlockSizeException)936(new IllegalBlockSizeException(e.toString()).initCause(e));937}938}939940// see JCE spec941protected byte[] engineWrap(Key key) throws IllegalBlockSizeException,942InvalidKeyException {943// XXX key wrapping944throw new UnsupportedOperationException("engineWrap()");945}946947// see JCE spec948protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,949int wrappedKeyType)950throws InvalidKeyException, NoSuchAlgorithmException {951// XXX key unwrapping952throw new UnsupportedOperationException("engineUnwrap()");953}954955// see JCE spec956@Override957protected int engineGetKeySize(Key key) throws InvalidKeyException {958int n = P11SecretKeyFactory.convertKey959(token, key, keyAlgorithm).length();960return n;961}962963private final void bufferInputBytes(byte[] in, int inOfs, int len) {964System.arraycopy(in, inOfs, padBuffer, padBufferLen, len);965padBufferLen += len;966bytesBuffered += len;967}968969private final void bufferInputBytes(ByteBuffer inBuffer, int len) {970inBuffer.get(padBuffer, padBufferLen, len);971padBufferLen += len;972bytesBuffered += len;973}974}975976977