Path: blob/master/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java
41154 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// falg 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;372default:373throw new InvalidAlgorithmParameterException374("Unsupported mode: " + opmode);375}376if (blockMode == MODE_ECB) { // ECB or stream cipher377if (iv != null) {378if (blockSize == 0) {379throw new InvalidAlgorithmParameterException380("IV not used with stream ciphers");381} else {382throw new InvalidAlgorithmParameterException383("IV not used in ECB mode");384}385}386} else { // MODE_CBC or MODE_CTR387if (iv == null) {388if (encrypt == false) {389String exMsg =390(blockMode == MODE_CBC ?391"IV must be specified for decryption in CBC mode" :392"IV must be specified for decryption in CTR mode");393throw new InvalidAlgorithmParameterException(exMsg);394}395// generate random IV396if (random == null) {397random = JCAUtil.getSecureRandom();398}399iv = new byte[blockSize];400random.nextBytes(iv);401} else {402if (iv.length != blockSize) {403throw new InvalidAlgorithmParameterException404("IV length must match block size");405}406}407}408this.iv = iv;409p11Key = P11SecretKeyFactory.convertKey(token, key, keyAlgorithm);410try {411initialize();412} catch (PKCS11Exception e) {413throw new InvalidKeyException("Could not initialize cipher", e);414}415}416417// reset the states to the pre-initialized values418// need to be called after doFinal or prior to re-init419private void reset(boolean doCancel) {420if (!initialized) {421return;422}423initialized = false;424425try {426if (session == null) {427return;428}429430if (doCancel && token.explicitCancel) {431cancelOperation();432}433} finally {434p11Key.releaseKeyID();435session = token.releaseSession(session);436bytesBuffered = 0;437padBufferLen = 0;438}439}440441private void cancelOperation() {442token.ensureValid();443// cancel operation by finishing it; avoid killSession as some444// hardware vendors may require re-login445try {446int bufLen = doFinalLength(0);447byte[] buffer = new byte[bufLen];448if (encrypt) {449token.p11.C_EncryptFinal(session.id(), 0, buffer, 0, bufLen);450} else {451token.p11.C_DecryptFinal(session.id(), 0, buffer, 0, bufLen);452}453} catch (PKCS11Exception e) {454if (e.getErrorCode() == CKR_OPERATION_NOT_INITIALIZED) {455// Cancel Operation may be invoked after an error on a PKCS#11456// call. If the operation inside the token was already cancelled,457// do not fail here. This is part of a defensive mechanism for458// PKCS#11 libraries that do not strictly follow the standard.459return;460}461if (encrypt) {462throw new ProviderException("Cancel failed", e);463}464// ignore failure for decryption465}466}467468private void ensureInitialized() throws PKCS11Exception {469if (!initialized) {470initialize();471}472}473474private void initialize() throws PKCS11Exception {475if (p11Key == null) {476throw new ProviderException(477"Operation cannot be performed without"478+ " calling engineInit first");479}480token.ensureValid();481long p11KeyID = p11Key.getKeyID();482try {483if (session == null) {484session = token.getOpSession();485}486CK_MECHANISM mechParams = (blockMode == MODE_CTR?487new CK_MECHANISM(mechanism, new CK_AES_CTR_PARAMS(iv)) :488new CK_MECHANISM(mechanism, iv));489if (encrypt) {490token.p11.C_EncryptInit(session.id(), mechParams, p11KeyID);491} else {492token.p11.C_DecryptInit(session.id(), mechParams, p11KeyID);493}494} catch (PKCS11Exception e) {495p11Key.releaseKeyID();496session = token.releaseSession(session);497throw e;498}499initialized = true;500bytesBuffered = 0;501padBufferLen = 0;502}503504// if update(inLen) is called, how big does the output buffer have to be?505private int updateLength(int inLen) {506if (inLen <= 0) {507return 0;508}509510int result = inLen + bytesBuffered;511if (blockSize != 0 && blockMode != MODE_CTR) {512// minus the number of bytes in the last incomplete block.513result -= (result & (blockSize - 1));514}515return result;516}517518// if doFinal(inLen) is called, how big does the output buffer have to be?519private int doFinalLength(int inLen) {520if (inLen < 0) {521return 0;522}523524int result = inLen + bytesBuffered;525if (blockSize != 0 && encrypt && paddingType != PAD_NONE) {526// add the number of bytes to make the last block complete.527result += (blockSize - (result & (blockSize - 1)));528}529return result;530}531532// see JCE spec533protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) {534try {535byte[] out = new byte[updateLength(inLen)];536int n = engineUpdate(in, inOfs, inLen, out, 0);537return P11Util.convert(out, 0, n);538} catch (ShortBufferException e) {539// convert since the output length is calculated by updateLength()540throw new ProviderException(e);541}542}543544// see JCE spec545protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out,546int outOfs) throws ShortBufferException {547int outLen = out.length - outOfs;548return implUpdate(in, inOfs, inLen, out, outOfs, outLen);549}550551// see JCE spec552@Override553protected int engineUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer)554throws ShortBufferException {555return implUpdate(inBuffer, outBuffer);556}557558// see JCE spec559protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen)560throws IllegalBlockSizeException, BadPaddingException {561try {562byte[] out = new byte[doFinalLength(inLen)];563int n = engineDoFinal(in, inOfs, inLen, out, 0);564return P11Util.convert(out, 0, n);565} catch (ShortBufferException e) {566// convert since the output length is calculated by doFinalLength()567throw new ProviderException(e);568}569}570571// see JCE spec572protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out,573int outOfs) throws ShortBufferException, IllegalBlockSizeException,574BadPaddingException {575int n = 0;576if ((inLen != 0) && (in != null)) {577n = engineUpdate(in, inOfs, inLen, out, outOfs);578outOfs += n;579}580n += implDoFinal(out, outOfs, out.length - outOfs);581return n;582}583584// see JCE spec585@Override586protected int engineDoFinal(ByteBuffer inBuffer, ByteBuffer outBuffer)587throws ShortBufferException, IllegalBlockSizeException,588BadPaddingException {589int n = engineUpdate(inBuffer, outBuffer);590n += implDoFinal(outBuffer);591return n;592}593594private int implUpdate(byte[] in, int inOfs, int inLen,595byte[] out, int outOfs, int outLen) throws ShortBufferException {596if (outLen < updateLength(inLen)) {597throw new ShortBufferException();598}599try {600ensureInitialized();601int k = 0;602int newPadBufferLen = 0;603if (paddingObj != null && (!encrypt || reqBlockUpdates)) {604if (padBufferLen != 0) {605if (padBufferLen != padBuffer.length) {606int bufCapacity = padBuffer.length - padBufferLen;607if (inLen > bufCapacity) {608bufferInputBytes(in, inOfs, bufCapacity);609inOfs += bufCapacity;610inLen -= bufCapacity;611} else {612bufferInputBytes(in, inOfs, inLen);613return 0;614}615}616if (encrypt) {617k = token.p11.C_EncryptUpdate(session.id(),6180, padBuffer, 0, padBufferLen,6190, out, outOfs, outLen);620} else {621k = token.p11.C_DecryptUpdate(session.id(),6220, padBuffer, 0, padBufferLen,6230, out, outOfs, outLen);624}625padBufferLen = 0;626}627newPadBufferLen = inLen & (blockSize - 1);628if (!encrypt && newPadBufferLen == 0) {629// While decrypting with implUpdate, the last encrypted block630// is always held in a buffer. If it's the final one (unknown631// at this point), it may contain padding bytes and need further632// processing. In implDoFinal (where we know it's the final one)633// the buffer is decrypted, unpadded and returned.634newPadBufferLen = padBuffer.length;635}636inLen -= newPadBufferLen;637}638if (inLen > 0) {639if (encrypt) {640k += token.p11.C_EncryptUpdate(session.id(), 0, in, inOfs,641inLen, 0, out, (outOfs + k), (outLen - k));642} else {643k += token.p11.C_DecryptUpdate(session.id(), 0, in, inOfs,644inLen, 0, out, (outOfs + k), (outLen - k));645}646}647// update 'padBuffer' if using our own padding impl.648if (paddingObj != null && newPadBufferLen > 0) {649bufferInputBytes(in, inOfs + inLen, newPadBufferLen);650}651bytesBuffered += (inLen - k);652return k;653} catch (PKCS11Exception e) {654if (e.getErrorCode() == CKR_BUFFER_TOO_SMALL) {655throw (ShortBufferException)656(new ShortBufferException().initCause(e));657}658// Some implementations such as the NSS Software Token do not659// cancel the operation upon a C_EncryptUpdate/C_DecryptUpdate660// failure (as required by the PKCS#11 standard). See JDK-8258833661// for further information.662reset(true);663throw new ProviderException("update() failed", e);664}665}666667private int implUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer)668throws ShortBufferException {669int inLen = inBuffer.remaining();670if (inLen <= 0) {671return 0;672}673674int outLen = outBuffer.remaining();675if (outLen < updateLength(inLen)) {676throw new ShortBufferException();677}678int origPos = inBuffer.position();679try {680ensureInitialized();681682long inAddr = 0;683int inOfs = 0;684byte[] inArray = null;685686if (inBuffer instanceof DirectBuffer) {687inAddr = ((DirectBuffer) inBuffer).address();688inOfs = origPos;689} else if (inBuffer.hasArray()) {690inArray = inBuffer.array();691inOfs = (origPos + inBuffer.arrayOffset());692}693694long outAddr = 0;695int outOfs = 0;696byte[] outArray = null;697if (outBuffer instanceof DirectBuffer) {698outAddr = ((DirectBuffer) outBuffer).address();699outOfs = outBuffer.position();700} else {701if (outBuffer.hasArray()) {702outArray = outBuffer.array();703outOfs = (outBuffer.position() + outBuffer.arrayOffset());704} else {705outArray = new byte[outLen];706}707}708709int k = 0;710int newPadBufferLen = 0;711if (paddingObj != null && (!encrypt || reqBlockUpdates)) {712if (padBufferLen != 0) {713if (padBufferLen != padBuffer.length) {714int bufCapacity = padBuffer.length - padBufferLen;715if (inLen > bufCapacity) {716bufferInputBytes(inBuffer, bufCapacity);717inOfs += bufCapacity;718inLen -= bufCapacity;719} else {720bufferInputBytes(inBuffer, inLen);721return 0;722}723}724if (encrypt) {725k = token.p11.C_EncryptUpdate(session.id(), 0,726padBuffer, 0, padBufferLen, outAddr, outArray,727outOfs, outLen);728} else {729k = token.p11.C_DecryptUpdate(session.id(), 0,730padBuffer, 0, padBufferLen, outAddr, outArray,731outOfs, outLen);732}733padBufferLen = 0;734}735newPadBufferLen = inLen & (blockSize - 1);736if (!encrypt && newPadBufferLen == 0) {737// While decrypting with implUpdate, the last encrypted block738// is always held in a buffer. If it's the final one (unknown739// at this point), it may contain padding bytes and need further740// processing. In implDoFinal (where we know it's the final one)741// the buffer is decrypted, unpadded and returned.742newPadBufferLen = padBuffer.length;743}744inLen -= newPadBufferLen;745}746if (inLen > 0) {747if (inAddr == 0 && inArray == null) {748inArray = new byte[inLen];749inBuffer.get(inArray);750} else {751inBuffer.position(inBuffer.position() + inLen);752}753if (encrypt) {754k += token.p11.C_EncryptUpdate(session.id(), inAddr,755inArray, inOfs, inLen, outAddr, outArray,756(outOfs + k), (outLen - k));757} else {758k += token.p11.C_DecryptUpdate(session.id(), inAddr,759inArray, inOfs, inLen, outAddr, outArray,760(outOfs + k), (outLen - k));761}762}763// update 'padBuffer' if using our own padding impl.764if (paddingObj != null && newPadBufferLen > 0) {765bufferInputBytes(inBuffer, newPadBufferLen);766}767bytesBuffered += (inLen - k);768if (!(outBuffer instanceof DirectBuffer) &&769!outBuffer.hasArray()) {770outBuffer.put(outArray, outOfs, k);771} else {772outBuffer.position(outBuffer.position() + k);773}774return k;775} catch (PKCS11Exception e) {776// Reset input buffer to its original position for777inBuffer.position(origPos);778if (e.getErrorCode() == CKR_BUFFER_TOO_SMALL) {779throw (ShortBufferException)780(new ShortBufferException().initCause(e));781}782// Some implementations such as the NSS Software Token do not783// cancel the operation upon a C_EncryptUpdate/C_DecryptUpdate784// failure (as required by the PKCS#11 standard). See JDK-8258833785// for further information.786reset(true);787throw new ProviderException("update() failed", e);788}789}790791private int implDoFinal(byte[] out, int outOfs, int outLen)792throws ShortBufferException, IllegalBlockSizeException,793BadPaddingException {794int requiredOutLen = doFinalLength(0);795if (outLen < requiredOutLen) {796throw new ShortBufferException();797}798boolean doCancel = true;799try {800ensureInitialized();801int k = 0;802if (encrypt) {803if (paddingObj != null) {804int startOff = 0;805if (reqBlockUpdates) {806startOff = padBufferLen;807}808int actualPadLen = paddingObj.setPaddingBytes(padBuffer,809startOff, requiredOutLen - bytesBuffered);810k = token.p11.C_EncryptUpdate(session.id(),8110, padBuffer, 0, startOff + actualPadLen,8120, out, outOfs, outLen);813}814// Some implementations such as the NSS Software Token do not815// cancel the operation upon a C_EncryptUpdate failure (as816// required by the PKCS#11 standard). Cancel is not needed817// only after this point. See JDK-8258833 for further818// information.819doCancel = false;820k += token.p11.C_EncryptFinal(session.id(),8210, out, (outOfs + k), (outLen - k));822} else {823// Special handling to match SunJCE provider behavior824if (bytesBuffered == 0 && padBufferLen == 0) {825return 0;826}827if (paddingObj != null) {828if (padBufferLen != 0) {829k = token.p11.C_DecryptUpdate(session.id(), 0,830padBuffer, 0, padBufferLen, 0, padBuffer, 0,831padBuffer.length);832}833// Some implementations such as the NSS Software Token do not834// cancel the operation upon a C_DecryptUpdate failure (as835// required by the PKCS#11 standard). Cancel is not needed836// only after this point. See JDK-8258833 for further837// information.838doCancel = false;839k += token.p11.C_DecryptFinal(session.id(), 0, padBuffer, k,840padBuffer.length - k);841842int actualPadLen = paddingObj.unpad(padBuffer, k);843k -= actualPadLen;844System.arraycopy(padBuffer, 0, out, outOfs, k);845} else {846doCancel = false;847k = token.p11.C_DecryptFinal(session.id(), 0, out, outOfs,848outLen);849}850}851return k;852} catch (PKCS11Exception e) {853handleException(e);854throw new ProviderException("doFinal() failed", e);855} finally {856reset(doCancel);857}858}859860private int implDoFinal(ByteBuffer outBuffer)861throws ShortBufferException, IllegalBlockSizeException,862BadPaddingException {863int outLen = outBuffer.remaining();864int requiredOutLen = doFinalLength(0);865if (outLen < requiredOutLen) {866throw new ShortBufferException();867}868869boolean doCancel = true;870try {871ensureInitialized();872873long outAddr = 0;874byte[] outArray = null;875int outOfs = 0;876if (outBuffer instanceof DirectBuffer) {877outAddr = ((DirectBuffer) outBuffer).address();878outOfs = outBuffer.position();879} else {880if (outBuffer.hasArray()) {881outArray = outBuffer.array();882outOfs = outBuffer.position() + outBuffer.arrayOffset();883} else {884outArray = new byte[outLen];885}886}887888int k = 0;889890if (encrypt) {891if (paddingObj != null) {892int startOff = 0;893if (reqBlockUpdates) {894startOff = padBufferLen;895}896int actualPadLen = paddingObj.setPaddingBytes(padBuffer,897startOff, requiredOutLen - bytesBuffered);898k = token.p11.C_EncryptUpdate(session.id(),8990, padBuffer, 0, startOff + actualPadLen,900outAddr, outArray, outOfs, outLen);901}902// Some implementations such as the NSS Software Token do not903// cancel the operation upon a C_EncryptUpdate failure (as904// required by the PKCS#11 standard). Cancel is not needed905// only after this point. See JDK-8258833 for further906// information.907doCancel = false;908k += token.p11.C_EncryptFinal(session.id(),909outAddr, outArray, (outOfs + k), (outLen - k));910} else {911// Special handling to match SunJCE provider behavior912if (bytesBuffered == 0 && padBufferLen == 0) {913return 0;914}915916if (paddingObj != null) {917if (padBufferLen != 0) {918k = token.p11.C_DecryptUpdate(session.id(),9190, padBuffer, 0, padBufferLen,9200, padBuffer, 0, padBuffer.length);921padBufferLen = 0;922}923// Some implementations such as the NSS Software Token do not924// cancel the operation upon a C_DecryptUpdate failure (as925// required by the PKCS#11 standard). Cancel is not needed926// only after this point. See JDK-8258833 for further927// information.928doCancel = false;929k += token.p11.C_DecryptFinal(session.id(),9300, padBuffer, k, padBuffer.length - k);931932int actualPadLen = paddingObj.unpad(padBuffer, k);933k -= actualPadLen;934outArray = padBuffer;935outOfs = 0;936} else {937doCancel = false;938k = token.p11.C_DecryptFinal(session.id(),939outAddr, outArray, outOfs, outLen);940}941}942if ((!encrypt && paddingObj != null) ||943(!(outBuffer instanceof DirectBuffer) &&944!outBuffer.hasArray())) {945outBuffer.put(outArray, outOfs, k);946} else {947outBuffer.position(outBuffer.position() + k);948}949return k;950} catch (PKCS11Exception e) {951handleException(e);952throw new ProviderException("doFinal() failed", e);953} finally {954reset(doCancel);955}956}957958private void handleException(PKCS11Exception e)959throws ShortBufferException, IllegalBlockSizeException {960long errorCode = e.getErrorCode();961if (errorCode == CKR_BUFFER_TOO_SMALL) {962throw (ShortBufferException)963(new ShortBufferException().initCause(e));964} else if (errorCode == CKR_DATA_LEN_RANGE ||965errorCode == CKR_ENCRYPTED_DATA_LEN_RANGE) {966throw (IllegalBlockSizeException)967(new IllegalBlockSizeException(e.toString()).initCause(e));968}969}970971// see JCE spec972protected byte[] engineWrap(Key key) throws IllegalBlockSizeException,973InvalidKeyException {974// XXX key wrapping975throw new UnsupportedOperationException("engineWrap()");976}977978// see JCE spec979protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,980int wrappedKeyType)981throws InvalidKeyException, NoSuchAlgorithmException {982// XXX key unwrapping983throw new UnsupportedOperationException("engineUnwrap()");984}985986// see JCE spec987@Override988protected int engineGetKeySize(Key key) throws InvalidKeyException {989int n = P11SecretKeyFactory.convertKey990(token, key, keyAlgorithm).length();991return n;992}993994private final void bufferInputBytes(byte[] in, int inOfs, int len) {995System.arraycopy(in, inOfs, padBuffer, padBufferLen, len);996padBufferLen += len;997bytesBuffered += len;998}9991000private final void bufferInputBytes(ByteBuffer inBuffer, int len) {1001inBuffer.get(padBuffer, padBufferLen, len);1002padBufferLen += len;1003bytesBuffered += len;1004}1005}100610071008