Path: blob/master/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java
66646 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.*;40import static sun.security.pkcs11.wrapper.PKCS11Exception.*;4142/**43* Cipher implementation class. This class currently supports44* DES, DESede, AES, ARCFOUR, and Blowfish.45*46* This class is designed to support ECB, CBC, CTR with NoPadding47* and ECB, CBC with PKCS5Padding. It will use its own padding impl48* 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 Sterbenz54* @since 1.555*/56final class P11Cipher extends CipherSpi {5758// mode constant for ECB mode59private static final int MODE_ECB = 3;60// mode constant for CBC mode61private static final int MODE_CBC = 4;62// mode constant for CTR mode63private static final int MODE_CTR = 5;6465// padding constant for NoPadding66private static final int PAD_NONE = 5;67// padding constant for PKCS5Padding68private static final int PAD_PKCS5 = 6;6970private static interface Padding {71// ENC: format the specified buffer with padding bytes and return the72// actual padding length73int setPaddingBytes(byte[] paddingBuffer, int startOff, int padLen);7475// DEC: return the length of trailing padding bytes given the specified76// padded data77int unpad(byte[] paddedData, int len)78throws BadPaddingException, IllegalBlockSizeException;79}8081private static class PKCS5Padding implements Padding {8283private final int blockSize;8485PKCS5Padding(int blockSize)86throws NoSuchPaddingException {87if (blockSize == 0) {88throw new NoSuchPaddingException89("PKCS#5 padding not supported with stream ciphers");90}91this.blockSize = blockSize;92}9394public int setPaddingBytes(byte[] paddingBuffer, int startOff, int padLen) {95Arrays.fill(paddingBuffer, startOff, startOff + padLen, (byte) (padLen & 0x007f));96return padLen;97}9899public int unpad(byte[] paddedData, int len)100throws BadPaddingException, IllegalBlockSizeException {101if ((len < 1) || (len % blockSize != 0)) {102throw new IllegalBlockSizeException103("Input length must be multiples of " + blockSize);104}105byte padValue = paddedData[len - 1];106if (padValue < 1 || padValue > blockSize) {107throw new BadPaddingException("Invalid pad value!");108}109// sanity check padding bytes110int padStartIndex = len - padValue;111for (int i = padStartIndex; i < len; i++) {112if (paddedData[i] != padValue) {113throw new BadPaddingException("Invalid pad bytes!");114}115}116return padValue;117}118}119120// token instance121private final Token token;122123// algorithm name124private final String algorithm;125126// name of the key algorithm, e.g. DES instead of algorithm DES/CBC/...127private final String keyAlgorithm;128129// mechanism id130private final long mechanism;131132// associated session, if any133private Session session;134135// key, if init() was called136private P11Key p11Key;137138// flag indicating whether an operation is initialized139private boolean initialized;140141// flag indicating encrypt or decrypt mode142private boolean encrypt;143144// mode, one of MODE_* above (MODE_ECB for stream ciphers)145private int blockMode;146147// block size, 0 for stream ciphers148private final int blockSize;149150// padding type, on of PAD_* above (PAD_NONE for stream ciphers)151private int paddingType;152153// 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 data156private Padding paddingObj;157// buffer for holding back the block which contains padding bytes158private byte[] padBuffer;159private int padBufferLen;160161// original IV, if in MODE_CBC or MODE_CTR162private byte[] iv;163164// number of bytes buffered internally by the native mechanism and padBuffer165// if we do the padding166private int bytesBuffered;167168// length of key size in bytes; currently only used by AES given its oid169// specification mandates a fixed size of the key170private int fixedKeySize = -1;171172// Indicates whether the underlying PKCS#11 library requires block-sized173// updates during multi-part operations. In such case, we buffer data in174// padBuffer up to a block-size. This may be needed only if padding is175// applied on the Java side. An example of the previous is when the176// CKM_AES_ECB mechanism is used and the PKCS#11 library is NSS. See more177// on JDK-8261355.178private boolean reqBlockUpdates = false;179180P11Cipher(Token token, String algorithm, long mechanism)181throws PKCS11Exception, NoSuchAlgorithmException {182super();183this.token = token;184this.algorithm = algorithm;185this.mechanism = mechanism;186187String[] algoParts = algorithm.split("/");188189if (algoParts[0].startsWith("AES")) {190blockSize = 16;191int index = algoParts[0].indexOf('_');192if (index != -1) {193// should be well-formed since we specify what we support194fixedKeySize = Integer.parseInt(algoParts[0].substring(index+1))/8;195}196keyAlgorithm = "AES";197} else {198keyAlgorithm = algoParts[0];199if (keyAlgorithm.equals("RC4") ||200keyAlgorithm.equals("ARCFOUR")) {201blockSize = 0;202} else { // DES, DESede, Blowfish203blockSize = 8;204}205}206this.blockMode =207(algoParts.length > 1 ? parseMode(algoParts[1]) : MODE_ECB);208String defPadding = (blockSize == 0 ? "NoPadding" : "PKCS5Padding");209String paddingStr =210(algoParts.length > 2 ? algoParts[2] : defPadding);211try {212engineSetPadding(paddingStr);213} catch (NoSuchPaddingException nspe) {214// should not happen215throw new ProviderException(nspe);216}217}218219protected void engineSetMode(String mode) throws NoSuchAlgorithmException {220// Disallow change of mode for now since currently it's explicitly221// defined in transformation strings222throw new NoSuchAlgorithmException("Unsupported mode " + mode);223}224225private int parseMode(String mode) throws NoSuchAlgorithmException {226mode = mode.toUpperCase(Locale.ENGLISH);227int result;228if (mode.equals("ECB")) {229result = MODE_ECB;230} else if (mode.equals("CBC")) {231if (blockSize == 0) {232throw new NoSuchAlgorithmException233("CBC mode not supported with stream ciphers");234}235result = MODE_CBC;236} else if (mode.equals("CTR")) {237result = MODE_CTR;238} else {239throw new NoSuchAlgorithmException("Unsupported mode " + mode);240}241return result;242}243244// see JCE spec245protected void engineSetPadding(String padding)246throws NoSuchPaddingException {247paddingObj = null;248padBuffer = null;249padding = padding.toUpperCase(Locale.ENGLISH);250if (padding.equals("NOPADDING")) {251paddingType = PAD_NONE;252} else if (padding.equals("PKCS5PADDING")) {253if (this.blockMode == MODE_CTR) {254throw new NoSuchPaddingException255("PKCS#5 padding not supported with CTR mode");256}257paddingType = PAD_PKCS5;258if (mechanism != CKM_DES_CBC_PAD && mechanism != CKM_DES3_CBC_PAD &&259mechanism != CKM_AES_CBC_PAD) {260// no native padding support; use our own padding impl261paddingObj = new PKCS5Padding(blockSize);262padBuffer = new byte[blockSize];263char[] tokenLabel = token.tokenInfo.label;264// NSS requires block-sized updates in multi-part operations.265reqBlockUpdates = ((tokenLabel[0] == 'N' && tokenLabel[1] == 'S'266&& tokenLabel[2] == 'S') ? true : false);267}268} else {269throw new NoSuchPaddingException("Unsupported padding " + padding);270}271}272273// see JCE spec274protected int engineGetBlockSize() {275return blockSize;276}277278// see JCE spec279protected int engineGetOutputSize(int inputLen) {280return doFinalLength(inputLen);281}282283// see JCE spec284protected byte[] engineGetIV() {285return (iv == null) ? null : iv.clone();286}287288// see JCE spec289protected AlgorithmParameters engineGetParameters() {290if (iv == null) {291return null;292}293IvParameterSpec ivSpec = new IvParameterSpec(iv);294try {295AlgorithmParameters params =296AlgorithmParameters.getInstance(keyAlgorithm,297P11Util.getSunJceProvider());298params.init(ivSpec);299return params;300} catch (GeneralSecurityException e) {301// NoSuchAlgorithmException, NoSuchProviderException302// InvalidParameterSpecException303throw new ProviderException("Could not encode parameters", e);304}305}306307// see JCE spec308protected void engineInit(int opmode, Key key, SecureRandom random)309throws InvalidKeyException {310try {311implInit(opmode, key, null, random);312} catch (InvalidAlgorithmParameterException e) {313throw new InvalidKeyException("init() failed", e);314}315}316317// see JCE spec318protected void engineInit(int opmode, Key key,319AlgorithmParameterSpec params, SecureRandom random)320throws InvalidKeyException, InvalidAlgorithmParameterException {321byte[] ivValue;322if (params != null) {323if (params instanceof IvParameterSpec == false) {324throw new InvalidAlgorithmParameterException325("Only IvParameterSpec supported");326}327IvParameterSpec ivSpec = (IvParameterSpec) params;328ivValue = ivSpec.getIV();329} else {330ivValue = null;331}332implInit(opmode, key, ivValue, random);333}334335// see JCE spec336protected void engineInit(int opmode, Key key, AlgorithmParameters params,337SecureRandom random)338throws InvalidKeyException, InvalidAlgorithmParameterException {339byte[] ivValue;340if (params != null) {341try {342IvParameterSpec ivSpec =343params.getParameterSpec(IvParameterSpec.class);344ivValue = ivSpec.getIV();345} catch (InvalidParameterSpecException e) {346throw new InvalidAlgorithmParameterException347("Could not decode IV", e);348}349} else {350ivValue = null;351}352implInit(opmode, key, ivValue, random);353}354355// actual init() implementation356private void implInit(int opmode, Key key, byte[] iv,357SecureRandom random)358throws InvalidKeyException, InvalidAlgorithmParameterException {359reset(true);360if (fixedKeySize != -1 &&361((key instanceof P11Key) ? ((P11Key) key).length() >> 3 :362key.getEncoded().length) != fixedKeySize) {363throw new InvalidKeyException("Key size is invalid");364}365switch (opmode) {366case Cipher.ENCRYPT_MODE:367encrypt = true;368break;369case Cipher.DECRYPT_MODE:370encrypt = false;371break;372case Cipher.WRAP_MODE:373case Cipher.UNWRAP_MODE:374throw new UnsupportedOperationException375("Unsupported mode: " + opmode);376default:377// should never happen; checked by Cipher.init()378throw new AssertionError("Unknown mode: " + opmode);379}380if (blockMode == MODE_ECB) { // ECB or stream cipher381if (iv != null) {382if (blockSize == 0) {383throw new InvalidAlgorithmParameterException384("IV not used with stream ciphers");385} else {386throw new InvalidAlgorithmParameterException387("IV not used in ECB mode");388}389}390} else { // MODE_CBC or MODE_CTR391if (iv == null) {392if (encrypt == false) {393String exMsg =394(blockMode == MODE_CBC ?395"IV must be specified for decryption in CBC mode" :396"IV must be specified for decryption in CTR mode");397throw new InvalidAlgorithmParameterException(exMsg);398}399// generate random IV400if (random == null) {401random = JCAUtil.getSecureRandom();402}403iv = new byte[blockSize];404random.nextBytes(iv);405} else {406if (iv.length != blockSize) {407throw new InvalidAlgorithmParameterException408("IV length must match block size");409}410}411}412this.iv = iv;413p11Key = P11SecretKeyFactory.convertKey(token, key, keyAlgorithm);414try {415initialize();416} catch (PKCS11Exception e) {417throw new InvalidKeyException("Could not initialize cipher", e);418}419}420421// reset the states to the pre-initialized values422// need to be called after doFinal or prior to re-init423private void reset(boolean doCancel) {424if (!initialized) {425return;426}427initialized = false;428429try {430if (session == null) {431return;432}433434if (doCancel && token.explicitCancel) {435cancelOperation();436}437} finally {438p11Key.releaseKeyID();439session = token.releaseSession(session);440bytesBuffered = 0;441padBufferLen = 0;442}443}444445private void cancelOperation() {446token.ensureValid();447// cancel operation by finishing it; avoid killSession as some448// hardware vendors may require re-login449try {450int bufLen = doFinalLength(0);451byte[] buffer = new byte[bufLen];452if (encrypt) {453token.p11.C_EncryptFinal(session.id(), 0, buffer, 0, bufLen);454} else {455token.p11.C_DecryptFinal(session.id(), 0, buffer, 0, bufLen);456}457} catch (PKCS11Exception e) {458if (e.getErrorCode() == CKR_OPERATION_NOT_INITIALIZED) {459// Cancel Operation may be invoked after an error on a PKCS#11460// call. If the operation inside the token was already cancelled,461// do not fail here. This is part of a defensive mechanism for462// PKCS#11 libraries that do not strictly follow the standard.463return;464}465if (encrypt) {466throw new ProviderException("Cancel failed", e);467}468// ignore failure for decryption469}470}471472private void ensureInitialized() throws PKCS11Exception {473if (!initialized) {474initialize();475}476}477478private void initialize() throws PKCS11Exception {479if (p11Key == null) {480throw new ProviderException(481"Operation cannot be performed without"482+ " calling engineInit first");483}484token.ensureValid();485long p11KeyID = p11Key.getKeyID();486try {487if (session == null) {488session = token.getOpSession();489}490CK_MECHANISM mechParams = (blockMode == MODE_CTR?491new CK_MECHANISM(mechanism, new CK_AES_CTR_PARAMS(iv)) :492new CK_MECHANISM(mechanism, iv));493if (encrypt) {494token.p11.C_EncryptInit(session.id(), mechParams, p11KeyID);495} else {496token.p11.C_DecryptInit(session.id(), mechParams, p11KeyID);497}498} catch (PKCS11Exception e) {499p11Key.releaseKeyID();500session = token.releaseSession(session);501throw e;502}503initialized = true;504bytesBuffered = 0;505padBufferLen = 0;506}507508// if update(inLen) is called, how big does the output buffer have to be?509private int updateLength(int inLen) {510if (inLen <= 0) {511return 0;512}513514int result = inLen + bytesBuffered;515if (blockSize != 0 && blockMode != MODE_CTR) {516// minus the number of bytes in the last incomplete block.517result -= (result & (blockSize - 1));518}519return result;520}521522// if doFinal(inLen) is called, how big does the output buffer have to be?523private int doFinalLength(int inLen) {524if (inLen < 0) {525return 0;526}527528int result = inLen + bytesBuffered;529if (blockSize != 0 && encrypt && paddingType != PAD_NONE) {530// add the number of bytes to make the last block complete.531result += (blockSize - (result & (blockSize - 1)));532}533return result;534}535536// see JCE spec537protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) {538try {539byte[] out = new byte[updateLength(inLen)];540int n = engineUpdate(in, inOfs, inLen, out, 0);541return P11Util.convert(out, 0, n);542} catch (ShortBufferException e) {543// convert since the output length is calculated by updateLength()544throw new ProviderException(e);545}546}547548// see JCE spec549protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out,550int outOfs) throws ShortBufferException {551int outLen = out.length - outOfs;552return implUpdate(in, inOfs, inLen, out, outOfs, outLen);553}554555// see JCE spec556@Override557protected int engineUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer)558throws ShortBufferException {559return implUpdate(inBuffer, outBuffer);560}561562// see JCE spec563protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen)564throws IllegalBlockSizeException, BadPaddingException {565try {566byte[] out = new byte[doFinalLength(inLen)];567int n = engineDoFinal(in, inOfs, inLen, out, 0);568return P11Util.convert(out, 0, n);569} catch (ShortBufferException e) {570// convert since the output length is calculated by doFinalLength()571throw new ProviderException(e);572}573}574575// see JCE spec576protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out,577int outOfs) throws ShortBufferException, IllegalBlockSizeException,578BadPaddingException {579int n = 0;580if ((inLen != 0) && (in != null)) {581n = engineUpdate(in, inOfs, inLen, out, outOfs);582outOfs += n;583}584n += implDoFinal(out, outOfs, out.length - outOfs);585return n;586}587588// see JCE spec589@Override590protected int engineDoFinal(ByteBuffer inBuffer, ByteBuffer outBuffer)591throws ShortBufferException, IllegalBlockSizeException,592BadPaddingException {593int n = engineUpdate(inBuffer, outBuffer);594n += implDoFinal(outBuffer);595return n;596}597598private int implUpdate(byte[] in, int inOfs, int inLen,599byte[] out, int outOfs, int outLen) throws ShortBufferException {600if (outLen < updateLength(inLen)) {601throw new ShortBufferException();602}603try {604ensureInitialized();605int k = 0;606int newPadBufferLen = 0;607if (paddingObj != null && (!encrypt || reqBlockUpdates)) {608if (padBufferLen != 0) {609if (padBufferLen != padBuffer.length) {610int bufCapacity = padBuffer.length - padBufferLen;611if (inLen > bufCapacity) {612bufferInputBytes(in, inOfs, bufCapacity);613inOfs += bufCapacity;614inLen -= bufCapacity;615} else {616bufferInputBytes(in, inOfs, inLen);617return 0;618}619}620if (encrypt) {621k = token.p11.C_EncryptUpdate(session.id(),6220, padBuffer, 0, padBufferLen,6230, out, outOfs, outLen);624} else {625k = token.p11.C_DecryptUpdate(session.id(),6260, padBuffer, 0, padBufferLen,6270, out, outOfs, outLen);628}629padBufferLen = 0;630}631newPadBufferLen = inLen & (blockSize - 1);632if (!encrypt && newPadBufferLen == 0) {633// While decrypting with implUpdate, the last encrypted block634// is always held in a buffer. If it's the final one (unknown635// at this point), it may contain padding bytes and need further636// processing. In implDoFinal (where we know it's the final one)637// the buffer is decrypted, unpadded and returned.638newPadBufferLen = padBuffer.length;639}640inLen -= newPadBufferLen;641}642if (inLen > 0) {643if (encrypt) {644k += token.p11.C_EncryptUpdate(session.id(), 0, in, inOfs,645inLen, 0, out, (outOfs + k), (outLen - k));646} else {647k += token.p11.C_DecryptUpdate(session.id(), 0, in, inOfs,648inLen, 0, out, (outOfs + k), (outLen - k));649}650}651// update 'padBuffer' if using our own padding impl.652if (paddingObj != null && newPadBufferLen > 0) {653bufferInputBytes(in, inOfs + inLen, newPadBufferLen);654}655bytesBuffered += (inLen - k);656return k;657} catch (PKCS11Exception e) {658if (e.getErrorCode() == CKR_BUFFER_TOO_SMALL) {659throw (ShortBufferException)660(new ShortBufferException().initCause(e));661}662// Some implementations such as the NSS Software Token do not663// cancel the operation upon a C_EncryptUpdate/C_DecryptUpdate664// failure (as required by the PKCS#11 standard). See JDK-8258833665// for further information.666reset(true);667throw new ProviderException("update() failed", e);668}669}670671private int implUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer)672throws ShortBufferException {673int inLen = inBuffer.remaining();674if (inLen <= 0) {675return 0;676}677678int outLen = outBuffer.remaining();679if (outLen < updateLength(inLen)) {680throw new ShortBufferException();681}682int origPos = inBuffer.position();683try {684ensureInitialized();685686long inAddr = 0;687int inOfs = 0;688byte[] inArray = null;689690if (inBuffer instanceof DirectBuffer) {691inAddr = ((DirectBuffer) inBuffer).address();692inOfs = origPos;693} else if (inBuffer.hasArray()) {694inArray = inBuffer.array();695inOfs = (origPos + inBuffer.arrayOffset());696}697698long outAddr = 0;699int outOfs = 0;700byte[] outArray = null;701if (outBuffer instanceof DirectBuffer) {702outAddr = ((DirectBuffer) outBuffer).address();703outOfs = outBuffer.position();704} else {705if (outBuffer.hasArray()) {706outArray = outBuffer.array();707outOfs = (outBuffer.position() + outBuffer.arrayOffset());708} else {709outArray = new byte[outLen];710}711}712713int k = 0;714int newPadBufferLen = 0;715if (paddingObj != null && (!encrypt || reqBlockUpdates)) {716if (padBufferLen != 0) {717if (padBufferLen != padBuffer.length) {718int bufCapacity = padBuffer.length - padBufferLen;719if (inLen > bufCapacity) {720bufferInputBytes(inBuffer, bufCapacity);721inOfs += bufCapacity;722inLen -= bufCapacity;723} else {724bufferInputBytes(inBuffer, inLen);725return 0;726}727}728if (encrypt) {729k = token.p11.C_EncryptUpdate(session.id(), 0,730padBuffer, 0, padBufferLen, outAddr, outArray,731outOfs, outLen);732} else {733k = token.p11.C_DecryptUpdate(session.id(), 0,734padBuffer, 0, padBufferLen, outAddr, outArray,735outOfs, outLen);736}737padBufferLen = 0;738}739newPadBufferLen = inLen & (blockSize - 1);740if (!encrypt && newPadBufferLen == 0) {741// While decrypting with implUpdate, the last encrypted block742// is always held in a buffer. If it's the final one (unknown743// at this point), it may contain padding bytes and need further744// processing. In implDoFinal (where we know it's the final one)745// the buffer is decrypted, unpadded and returned.746newPadBufferLen = padBuffer.length;747}748inLen -= newPadBufferLen;749}750if (inLen > 0) {751if (inAddr == 0 && inArray == null) {752inArray = new byte[inLen];753inBuffer.get(inArray);754} else {755inBuffer.position(inBuffer.position() + inLen);756}757if (encrypt) {758k += token.p11.C_EncryptUpdate(session.id(), inAddr,759inArray, inOfs, inLen, outAddr, outArray,760(outOfs + k), (outLen - k));761} else {762k += token.p11.C_DecryptUpdate(session.id(), inAddr,763inArray, inOfs, inLen, outAddr, outArray,764(outOfs + k), (outLen - k));765}766}767// update 'padBuffer' if using our own padding impl.768if (paddingObj != null && newPadBufferLen > 0) {769bufferInputBytes(inBuffer, newPadBufferLen);770}771bytesBuffered += (inLen - k);772if (!(outBuffer instanceof DirectBuffer) &&773!outBuffer.hasArray()) {774outBuffer.put(outArray, outOfs, k);775} else {776outBuffer.position(outBuffer.position() + k);777}778return k;779} catch (PKCS11Exception e) {780// Reset input buffer to its original position for781inBuffer.position(origPos);782if (e.getErrorCode() == CKR_BUFFER_TOO_SMALL) {783throw (ShortBufferException)784(new ShortBufferException().initCause(e));785}786// Some implementations such as the NSS Software Token do not787// cancel the operation upon a C_EncryptUpdate/C_DecryptUpdate788// failure (as required by the PKCS#11 standard). See JDK-8258833789// for further information.790reset(true);791throw new ProviderException("update() failed", e);792}793}794795private int implDoFinal(byte[] out, int outOfs, int outLen)796throws ShortBufferException, IllegalBlockSizeException,797BadPaddingException {798int requiredOutLen = doFinalLength(0);799if (outLen < requiredOutLen) {800throw new ShortBufferException();801}802boolean doCancel = true;803try {804ensureInitialized();805int k = 0;806if (encrypt) {807if (paddingObj != null) {808int startOff = 0;809if (reqBlockUpdates) {810startOff = padBufferLen;811}812int actualPadLen = paddingObj.setPaddingBytes(padBuffer,813startOff, requiredOutLen - bytesBuffered);814k = token.p11.C_EncryptUpdate(session.id(),8150, padBuffer, 0, startOff + actualPadLen,8160, out, outOfs, outLen);817}818// Some implementations such as the NSS Software Token do not819// cancel the operation upon a C_EncryptUpdate failure (as820// required by the PKCS#11 standard). Cancel is not needed821// only after this point. See JDK-8258833 for further822// information.823doCancel = false;824k += token.p11.C_EncryptFinal(session.id(),8250, out, (outOfs + k), (outLen - k));826} else {827// Special handling to match SunJCE provider behavior828if (bytesBuffered == 0 && padBufferLen == 0) {829return 0;830}831if (paddingObj != null) {832if (padBufferLen != 0) {833k = token.p11.C_DecryptUpdate(session.id(), 0,834padBuffer, 0, padBufferLen, 0, padBuffer, 0,835padBuffer.length);836}837// Some implementations such as the NSS Software Token do not838// cancel the operation upon a C_DecryptUpdate failure (as839// required by the PKCS#11 standard). Cancel is not needed840// only after this point. See JDK-8258833 for further841// information.842doCancel = false;843k += token.p11.C_DecryptFinal(session.id(), 0, padBuffer, k,844padBuffer.length - k);845846int actualPadLen = paddingObj.unpad(padBuffer, k);847k -= actualPadLen;848System.arraycopy(padBuffer, 0, out, outOfs, k);849} else {850doCancel = false;851k = token.p11.C_DecryptFinal(session.id(), 0, out, outOfs,852outLen);853}854}855return k;856} catch (PKCS11Exception e) {857handleException(e);858throw new ProviderException("doFinal() failed", e);859} finally {860reset(doCancel);861}862}863864private int implDoFinal(ByteBuffer outBuffer)865throws ShortBufferException, IllegalBlockSizeException,866BadPaddingException {867int outLen = outBuffer.remaining();868int requiredOutLen = doFinalLength(0);869if (outLen < requiredOutLen) {870throw new ShortBufferException();871}872873boolean doCancel = true;874try {875ensureInitialized();876877long outAddr = 0;878byte[] outArray = null;879int outOfs = 0;880if (outBuffer instanceof DirectBuffer) {881outAddr = ((DirectBuffer) outBuffer).address();882outOfs = outBuffer.position();883} else {884if (outBuffer.hasArray()) {885outArray = outBuffer.array();886outOfs = outBuffer.position() + outBuffer.arrayOffset();887} else {888outArray = new byte[outLen];889}890}891892int k = 0;893894if (encrypt) {895if (paddingObj != null) {896int startOff = 0;897if (reqBlockUpdates) {898startOff = padBufferLen;899}900int actualPadLen = paddingObj.setPaddingBytes(padBuffer,901startOff, requiredOutLen - bytesBuffered);902k = token.p11.C_EncryptUpdate(session.id(),9030, padBuffer, 0, startOff + actualPadLen,904outAddr, outArray, outOfs, outLen);905}906// Some implementations such as the NSS Software Token do not907// cancel the operation upon a C_EncryptUpdate failure (as908// required by the PKCS#11 standard). Cancel is not needed909// only after this point. See JDK-8258833 for further910// information.911doCancel = false;912k += token.p11.C_EncryptFinal(session.id(),913outAddr, outArray, (outOfs + k), (outLen - k));914} else {915// Special handling to match SunJCE provider behavior916if (bytesBuffered == 0 && padBufferLen == 0) {917return 0;918}919920if (paddingObj != null) {921if (padBufferLen != 0) {922k = token.p11.C_DecryptUpdate(session.id(),9230, padBuffer, 0, padBufferLen,9240, padBuffer, 0, padBuffer.length);925padBufferLen = 0;926}927// Some implementations such as the NSS Software Token do not928// cancel the operation upon a C_DecryptUpdate failure (as929// required by the PKCS#11 standard). Cancel is not needed930// only after this point. See JDK-8258833 for further931// information.932doCancel = false;933k += token.p11.C_DecryptFinal(session.id(),9340, padBuffer, k, padBuffer.length - k);935936int actualPadLen = paddingObj.unpad(padBuffer, k);937k -= actualPadLen;938outArray = padBuffer;939outOfs = 0;940} else {941doCancel = false;942k = token.p11.C_DecryptFinal(session.id(),943outAddr, outArray, outOfs, outLen);944}945}946if ((!encrypt && paddingObj != null) ||947(!(outBuffer instanceof DirectBuffer) &&948!outBuffer.hasArray())) {949outBuffer.put(outArray, outOfs, k);950} else {951outBuffer.position(outBuffer.position() + k);952}953return k;954} catch (PKCS11Exception e) {955handleException(e);956throw new ProviderException("doFinal() failed", e);957} finally {958reset(doCancel);959}960}961962private void handleException(PKCS11Exception e)963throws ShortBufferException, IllegalBlockSizeException {964long errorCode = e.getErrorCode();965if (errorCode == CKR_BUFFER_TOO_SMALL) {966throw (ShortBufferException)967(new ShortBufferException().initCause(e));968} else if (errorCode == CKR_DATA_LEN_RANGE ||969errorCode == CKR_ENCRYPTED_DATA_LEN_RANGE) {970throw (IllegalBlockSizeException)971(new IllegalBlockSizeException(e.toString()).initCause(e));972}973}974975// see JCE spec976protected byte[] engineWrap(Key key) throws IllegalBlockSizeException,977InvalidKeyException {978// XXX key wrapping979throw new UnsupportedOperationException("engineWrap()");980}981982// see JCE spec983protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,984int wrappedKeyType)985throws InvalidKeyException, NoSuchAlgorithmException {986// XXX key unwrapping987throw new UnsupportedOperationException("engineUnwrap()");988}989990// see JCE spec991@Override992protected int engineGetKeySize(Key key) throws InvalidKeyException {993int n = P11SecretKeyFactory.convertKey994(token, key, keyAlgorithm).length();995return n;996}997998private final void bufferInputBytes(byte[] in, int inOfs, int len) {999System.arraycopy(in, inOfs, padBuffer, padBufferLen, len);1000padBufferLen += len;1001bytesBuffered += len;1002}10031004private final void bufferInputBytes(ByteBuffer inBuffer, int len) {1005inBuffer.get(padBuffer, padBufferLen, len);1006padBufferLen += len;1007bytesBuffered += len;1008}1009}101010111012