Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/pkcs11/P11Cipher.java
38919 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 startOff, 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 startOff, int padLen) {94Arrays.fill(paddingBuffer, startOff, startOff + 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;170171// Indicates whether the underlying PKCS#11 library requires block-sized172// updates during multi-part operations. In such case, we buffer data in173// padBuffer up to a block-size. This may be needed only if padding is174// applied on the Java side. An example of the previous is when the175// CKM_AES_ECB mechanism is used and the PKCS#11 library is NSS. See more176// on JDK-8261355.177private boolean reqBlockUpdates = false;178179P11Cipher(Token token, String algorithm, long mechanism)180throws PKCS11Exception, NoSuchAlgorithmException {181super();182this.token = token;183this.algorithm = algorithm;184this.mechanism = mechanism;185186String algoParts[] = algorithm.split("/");187188if (algoParts[0].startsWith("AES")) {189blockSize = 16;190int index = algoParts[0].indexOf('_');191if (index != -1) {192// should be well-formed since we specify what we support193fixedKeySize = Integer.parseInt(algoParts[0].substring(index+1))/8;194}195keyAlgorithm = "AES";196} else {197keyAlgorithm = algoParts[0];198if (keyAlgorithm.equals("RC4") ||199keyAlgorithm.equals("ARCFOUR")) {200blockSize = 0;201} else { // DES, DESede, Blowfish202blockSize = 8;203}204}205this.blockMode =206(algoParts.length > 1 ? parseMode(algoParts[1]) : MODE_ECB);207String defPadding = (blockSize == 0 ? "NoPadding" : "PKCS5Padding");208String paddingStr =209(algoParts.length > 2 ? algoParts[2] : defPadding);210try {211engineSetPadding(paddingStr);212} catch (NoSuchPaddingException nspe) {213// should not happen214throw new ProviderException(nspe);215}216}217218protected void engineSetMode(String mode) throws NoSuchAlgorithmException {219// Disallow change of mode for now since currently it's explicitly220// defined in transformation strings221throw new NoSuchAlgorithmException("Unsupported mode " + mode);222}223224private int parseMode(String mode) throws NoSuchAlgorithmException {225mode = mode.toUpperCase(Locale.ENGLISH);226int result;227if (mode.equals("ECB")) {228result = MODE_ECB;229} else if (mode.equals("CBC")) {230if (blockSize == 0) {231throw new NoSuchAlgorithmException232("CBC mode not supported with stream ciphers");233}234result = MODE_CBC;235} else if (mode.equals("CTR")) {236result = MODE_CTR;237} else {238throw new NoSuchAlgorithmException("Unsupported mode " + mode);239}240return result;241}242243// see JCE spec244protected void engineSetPadding(String padding)245throws NoSuchPaddingException {246paddingObj = null;247padBuffer = null;248padding = padding.toUpperCase(Locale.ENGLISH);249if (padding.equals("NOPADDING")) {250paddingType = PAD_NONE;251} else if (padding.equals("PKCS5PADDING")) {252if (this.blockMode == MODE_CTR) {253throw new NoSuchPaddingException254("PKCS#5 padding not supported with CTR mode");255}256paddingType = PAD_PKCS5;257if (mechanism != CKM_DES_CBC_PAD && mechanism != CKM_DES3_CBC_PAD &&258mechanism != CKM_AES_CBC_PAD) {259// no native padding support; use our own padding impl260paddingObj = new PKCS5Padding(blockSize);261padBuffer = new byte[blockSize];262char[] tokenLabel = token.tokenInfo.label;263// NSS requires block-sized updates in multi-part operations.264reqBlockUpdates = ((tokenLabel[0] == 'N' && tokenLabel[1] == 'S'265&& tokenLabel[2] == 'S') ? true : false);266}267} else {268throw new NoSuchPaddingException("Unsupported padding " + padding);269}270}271272// see JCE spec273protected int engineGetBlockSize() {274return blockSize;275}276277// see JCE spec278protected int engineGetOutputSize(int inputLen) {279return doFinalLength(inputLen);280}281282// see JCE spec283protected byte[] engineGetIV() {284return (iv == null) ? null : iv.clone();285}286287// see JCE spec288protected AlgorithmParameters engineGetParameters() {289if (iv == null) {290return null;291}292IvParameterSpec ivSpec = new IvParameterSpec(iv);293try {294AlgorithmParameters params =295AlgorithmParameters.getInstance(keyAlgorithm,296P11Util.getSunJceProvider());297params.init(ivSpec);298return params;299} catch (GeneralSecurityException e) {300// NoSuchAlgorithmException, NoSuchProviderException301// InvalidParameterSpecException302throw new ProviderException("Could not encode parameters", e);303}304}305306// see JCE spec307protected void engineInit(int opmode, Key key, SecureRandom random)308throws InvalidKeyException {309try {310implInit(opmode, key, null, random);311} catch (InvalidAlgorithmParameterException e) {312throw new InvalidKeyException("init() failed", e);313}314}315316// see JCE spec317protected void engineInit(int opmode, Key key,318AlgorithmParameterSpec params, SecureRandom random)319throws InvalidKeyException, InvalidAlgorithmParameterException {320byte[] ivValue;321if (params != null) {322if (params instanceof IvParameterSpec == false) {323throw new InvalidAlgorithmParameterException324("Only IvParameterSpec supported");325}326IvParameterSpec ivSpec = (IvParameterSpec) params;327ivValue = ivSpec.getIV();328} else {329ivValue = null;330}331implInit(opmode, key, ivValue, random);332}333334// see JCE spec335protected void engineInit(int opmode, Key key, AlgorithmParameters params,336SecureRandom random)337throws InvalidKeyException, InvalidAlgorithmParameterException {338byte[] ivValue;339if (params != null) {340try {341IvParameterSpec ivSpec =342params.getParameterSpec(IvParameterSpec.class);343ivValue = ivSpec.getIV();344} catch (InvalidParameterSpecException e) {345throw new InvalidAlgorithmParameterException346("Could not decode IV", e);347}348} else {349ivValue = null;350}351implInit(opmode, key, ivValue, random);352}353354// actual init() implementation355private void implInit(int opmode, Key key, byte[] iv,356SecureRandom random)357throws InvalidKeyException, InvalidAlgorithmParameterException {358reset(true);359if (fixedKeySize != -1 &&360((key instanceof P11Key) ? ((P11Key) key).length() >> 3 :361key.getEncoded().length) != fixedKeySize) {362throw new InvalidKeyException("Key size is invalid");363}364switch (opmode) {365case Cipher.ENCRYPT_MODE:366encrypt = true;367break;368case Cipher.DECRYPT_MODE:369encrypt = false;370break;371default:372throw new InvalidAlgorithmParameterException373("Unsupported mode: " + opmode);374}375if (blockMode == MODE_ECB) { // ECB or stream cipher376if (iv != null) {377if (blockSize == 0) {378throw new InvalidAlgorithmParameterException379("IV not used with stream ciphers");380} else {381throw new InvalidAlgorithmParameterException382("IV not used in ECB mode");383}384}385} else { // MODE_CBC or MODE_CTR386if (iv == null) {387if (encrypt == false) {388String exMsg =389(blockMode == MODE_CBC ?390"IV must be specified for decryption in CBC mode" :391"IV must be specified for decryption in CTR mode");392throw new InvalidAlgorithmParameterException(exMsg);393}394// generate random IV395if (random == null) {396random = JCAUtil.getSecureRandom();397}398iv = new byte[blockSize];399random.nextBytes(iv);400} else {401if (iv.length != blockSize) {402throw new InvalidAlgorithmParameterException403("IV length must match block size");404}405}406}407this.iv = iv;408p11Key = P11SecretKeyFactory.convertKey(token, key, keyAlgorithm);409try {410initialize();411} catch (PKCS11Exception e) {412throw new InvalidKeyException("Could not initialize cipher", e);413}414}415416// reset the states to the pre-initialized values417// need to be called after doFinal or prior to re-init418private void reset(boolean doCancel) {419if (!initialized) {420return;421}422initialized = false;423424try {425if (session == null) {426return;427}428429if (doCancel && token.explicitCancel) {430cancelOperation();431}432} finally {433p11Key.releaseKeyID();434session = token.releaseSession(session);435bytesBuffered = 0;436padBufferLen = 0;437}438}439440private void cancelOperation() {441token.ensureValid();442// cancel operation by finishing it; avoid killSession as some443// hardware vendors may require re-login444try {445int bufLen = doFinalLength(0);446byte[] buffer = new byte[bufLen];447if (encrypt) {448token.p11.C_EncryptFinal(session.id(), 0, buffer, 0, bufLen);449} else {450token.p11.C_DecryptFinal(session.id(), 0, buffer, 0, bufLen);451}452} catch (PKCS11Exception e) {453if (e.getErrorCode() == CKR_OPERATION_NOT_INITIALIZED) {454// Cancel Operation may be invoked after an error on a PKCS#11455// call. If the operation inside the token was already cancelled,456// do not fail here. This is part of a defensive mechanism for457// PKCS#11 libraries that do not strictly follow the standard.458return;459}460if (encrypt) {461throw new ProviderException("Cancel failed", e);462}463// ignore failure for decryption464}465}466467private void ensureInitialized() throws PKCS11Exception {468if (!initialized) {469initialize();470}471}472473private void initialize() throws PKCS11Exception {474if (p11Key == null) {475throw new ProviderException(476"Operation cannot be performed without"477+ " calling engineInit first");478}479token.ensureValid();480long p11KeyID = p11Key.getKeyID();481try {482if (session == null) {483session = token.getOpSession();484}485CK_MECHANISM mechParams = (blockMode == MODE_CTR?486new CK_MECHANISM(mechanism, new CK_AES_CTR_PARAMS(iv)) :487new CK_MECHANISM(mechanism, iv));488if (encrypt) {489token.p11.C_EncryptInit(session.id(), mechParams, p11KeyID);490} else {491token.p11.C_DecryptInit(session.id(), mechParams, p11KeyID);492}493} catch (PKCS11Exception e) {494p11Key.releaseKeyID();495session = token.releaseSession(session);496throw e;497}498initialized = true;499bytesBuffered = 0;500padBufferLen = 0;501}502503// if update(inLen) is called, how big does the output buffer have to be?504private int updateLength(int inLen) {505if (inLen <= 0) {506return 0;507}508509int result = inLen + bytesBuffered;510if (blockSize != 0 && blockMode != MODE_CTR) {511// minus the number of bytes in the last incomplete block.512result -= (result & (blockSize - 1));513}514return result;515}516517// if doFinal(inLen) is called, how big does the output buffer have to be?518private int doFinalLength(int inLen) {519if (inLen < 0) {520return 0;521}522523int result = inLen + bytesBuffered;524if (blockSize != 0 && encrypt && paddingType != PAD_NONE) {525// add the number of bytes to make the last block complete.526result += (blockSize - (result & (blockSize - 1)));527}528return result;529}530531// see JCE spec532protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) {533try {534byte[] out = new byte[updateLength(inLen)];535int n = engineUpdate(in, inOfs, inLen, out, 0);536return P11Util.convert(out, 0, n);537} catch (ShortBufferException e) {538// convert since the output length is calculated by updateLength()539throw new ProviderException(e);540}541}542543// see JCE spec544protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out,545int outOfs) throws ShortBufferException {546int outLen = out.length - outOfs;547return implUpdate(in, inOfs, inLen, out, outOfs, outLen);548}549550// see JCE spec551@Override552protected int engineUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer)553throws ShortBufferException {554return implUpdate(inBuffer, outBuffer);555}556557// see JCE spec558protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen)559throws IllegalBlockSizeException, BadPaddingException {560try {561byte[] out = new byte[doFinalLength(inLen)];562int n = engineDoFinal(in, inOfs, inLen, out, 0);563return P11Util.convert(out, 0, n);564} catch (ShortBufferException e) {565// convert since the output length is calculated by doFinalLength()566throw new ProviderException(e);567}568}569570// see JCE spec571protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out,572int outOfs) throws ShortBufferException, IllegalBlockSizeException,573BadPaddingException {574int n = 0;575if ((inLen != 0) && (in != null)) {576n = engineUpdate(in, inOfs, inLen, out, outOfs);577outOfs += n;578}579n += implDoFinal(out, outOfs, out.length - outOfs);580return n;581}582583// see JCE spec584@Override585protected int engineDoFinal(ByteBuffer inBuffer, ByteBuffer outBuffer)586throws ShortBufferException, IllegalBlockSizeException,587BadPaddingException {588int n = engineUpdate(inBuffer, outBuffer);589n += implDoFinal(outBuffer);590return n;591}592593private int implUpdate(byte[] in, int inOfs, int inLen,594byte[] out, int outOfs, int outLen) throws ShortBufferException {595if (outLen < updateLength(inLen)) {596throw new ShortBufferException();597}598try {599ensureInitialized();600int k = 0;601int newPadBufferLen = 0;602if (paddingObj != null && (!encrypt || reqBlockUpdates)) {603if (padBufferLen != 0) {604if (padBufferLen != padBuffer.length) {605int bufCapacity = padBuffer.length - padBufferLen;606if (inLen > bufCapacity) {607bufferInputBytes(in, inOfs, bufCapacity);608inOfs += bufCapacity;609inLen -= bufCapacity;610} else {611bufferInputBytes(in, inOfs, inLen);612return 0;613}614}615if (encrypt) {616k = token.p11.C_EncryptUpdate(session.id(),6170, padBuffer, 0, padBufferLen,6180, out, outOfs, outLen);619} else {620k = token.p11.C_DecryptUpdate(session.id(),6210, padBuffer, 0, padBufferLen,6220, out, outOfs, outLen);623}624padBufferLen = 0;625}626newPadBufferLen = inLen & (blockSize - 1);627if (!encrypt && newPadBufferLen == 0) {628// While decrypting with implUpdate, the last encrypted block629// is always held in a buffer. If it's the final one (unknown630// at this point), it may contain padding bytes and need further631// processing. In implDoFinal (where we know it's the final one)632// the buffer is decrypted, unpadded and returned.633newPadBufferLen = padBuffer.length;634}635inLen -= newPadBufferLen;636}637if (inLen > 0) {638if (encrypt) {639k += token.p11.C_EncryptUpdate(session.id(), 0, in, inOfs,640inLen, 0, out, (outOfs + k), (outLen - k));641} else {642k += token.p11.C_DecryptUpdate(session.id(), 0, in, inOfs,643inLen, 0, out, (outOfs + k), (outLen - k));644}645}646// update 'padBuffer' if using our own padding impl.647if (paddingObj != null && newPadBufferLen > 0) {648bufferInputBytes(in, inOfs + inLen, newPadBufferLen);649}650bytesBuffered += (inLen - k);651return k;652} catch (PKCS11Exception e) {653if (e.getErrorCode() == CKR_BUFFER_TOO_SMALL) {654throw (ShortBufferException)655(new ShortBufferException().initCause(e));656}657// Some implementations such as the NSS Software Token do not658// cancel the operation upon a C_EncryptUpdate/C_DecryptUpdate659// failure (as required by the PKCS#11 standard). See JDK-8258833660// for further information.661reset(true);662throw new ProviderException("update() failed", e);663}664}665666private int implUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer)667throws ShortBufferException {668int inLen = inBuffer.remaining();669if (inLen <= 0) {670return 0;671}672673int outLen = outBuffer.remaining();674if (outLen < updateLength(inLen)) {675throw new ShortBufferException();676}677int origPos = inBuffer.position();678try {679ensureInitialized();680681long inAddr = 0;682int inOfs = 0;683byte[] inArray = null;684685if (inBuffer instanceof DirectBuffer) {686inAddr = ((DirectBuffer) inBuffer).address();687inOfs = origPos;688} else if (inBuffer.hasArray()) {689inArray = inBuffer.array();690inOfs = (origPos + inBuffer.arrayOffset());691}692693long outAddr = 0;694int outOfs = 0;695byte[] outArray = null;696if (outBuffer instanceof DirectBuffer) {697outAddr = ((DirectBuffer) outBuffer).address();698outOfs = outBuffer.position();699} else {700if (outBuffer.hasArray()) {701outArray = outBuffer.array();702outOfs = (outBuffer.position() + outBuffer.arrayOffset());703} else {704outArray = new byte[outLen];705}706}707708int k = 0;709int newPadBufferLen = 0;710if (paddingObj != null && (!encrypt || reqBlockUpdates)) {711if (padBufferLen != 0) {712if (padBufferLen != padBuffer.length) {713int bufCapacity = padBuffer.length - padBufferLen;714if (inLen > bufCapacity) {715bufferInputBytes(inBuffer, bufCapacity);716inOfs += bufCapacity;717inLen -= bufCapacity;718} else {719bufferInputBytes(inBuffer, inLen);720return 0;721}722}723if (encrypt) {724k = token.p11.C_EncryptUpdate(session.id(), 0,725padBuffer, 0, padBufferLen, outAddr, outArray,726outOfs, outLen);727} else {728k = token.p11.C_DecryptUpdate(session.id(), 0,729padBuffer, 0, padBufferLen, outAddr, outArray,730outOfs, outLen);731}732padBufferLen = 0;733}734newPadBufferLen = inLen & (blockSize - 1);735if (!encrypt && newPadBufferLen == 0) {736// While decrypting with implUpdate, the last encrypted block737// is always held in a buffer. If it's the final one (unknown738// at this point), it may contain padding bytes and need further739// processing. In implDoFinal (where we know it's the final one)740// the buffer is decrypted, unpadded and returned.741newPadBufferLen = padBuffer.length;742}743inLen -= newPadBufferLen;744}745if (inLen > 0) {746if (inAddr == 0 && inArray == null) {747inArray = new byte[inLen];748inBuffer.get(inArray);749} else {750inBuffer.position(inBuffer.position() + inLen);751}752if (encrypt) {753k += token.p11.C_EncryptUpdate(session.id(), inAddr,754inArray, inOfs, inLen, outAddr, outArray,755(outOfs + k), (outLen - k));756} else {757k += token.p11.C_DecryptUpdate(session.id(), inAddr,758inArray, inOfs, inLen, outAddr, outArray,759(outOfs + k), (outLen - k));760}761}762// update 'padBuffer' if using our own padding impl.763if (paddingObj != null && newPadBufferLen > 0) {764bufferInputBytes(inBuffer, newPadBufferLen);765}766bytesBuffered += (inLen - k);767if (!(outBuffer instanceof DirectBuffer) &&768!outBuffer.hasArray()) {769outBuffer.put(outArray, outOfs, k);770} else {771outBuffer.position(outBuffer.position() + k);772}773return k;774} catch (PKCS11Exception e) {775// Reset input buffer to its original position for776inBuffer.position(origPos);777if (e.getErrorCode() == CKR_BUFFER_TOO_SMALL) {778throw (ShortBufferException)779(new ShortBufferException().initCause(e));780}781// Some implementations such as the NSS Software Token do not782// cancel the operation upon a C_EncryptUpdate/C_DecryptUpdate783// failure (as required by the PKCS#11 standard). See JDK-8258833784// for further information.785reset(true);786throw new ProviderException("update() failed", e);787}788}789790private int implDoFinal(byte[] out, int outOfs, int outLen)791throws ShortBufferException, IllegalBlockSizeException,792BadPaddingException {793int requiredOutLen = doFinalLength(0);794if (outLen < requiredOutLen) {795throw new ShortBufferException();796}797boolean doCancel = true;798try {799ensureInitialized();800int k = 0;801if (encrypt) {802if (paddingObj != null) {803int startOff = 0;804if (reqBlockUpdates) {805startOff = padBufferLen;806}807int actualPadLen = paddingObj.setPaddingBytes(padBuffer,808startOff, requiredOutLen - bytesBuffered);809k = token.p11.C_EncryptUpdate(session.id(),8100, padBuffer, 0, startOff + actualPadLen,8110, out, outOfs, outLen);812}813// Some implementations such as the NSS Software Token do not814// cancel the operation upon a C_EncryptUpdate failure (as815// required by the PKCS#11 standard). Cancel is not needed816// only after this point. See JDK-8258833 for further817// information.818doCancel = false;819k += token.p11.C_EncryptFinal(session.id(),8200, out, (outOfs + k), (outLen - k));821} else {822// Special handling to match SunJCE provider behavior823if (bytesBuffered == 0 && padBufferLen == 0) {824return 0;825}826if (paddingObj != null) {827if (padBufferLen != 0) {828k = token.p11.C_DecryptUpdate(session.id(), 0,829padBuffer, 0, padBufferLen, 0, padBuffer, 0,830padBuffer.length);831}832// Some implementations such as the NSS Software Token do not833// cancel the operation upon a C_DecryptUpdate failure (as834// required by the PKCS#11 standard). Cancel is not needed835// only after this point. See JDK-8258833 for further836// information.837doCancel = false;838k += token.p11.C_DecryptFinal(session.id(), 0, padBuffer, k,839padBuffer.length - k);840841int actualPadLen = paddingObj.unpad(padBuffer, k);842k -= actualPadLen;843System.arraycopy(padBuffer, 0, out, outOfs, k);844} else {845doCancel = false;846k = token.p11.C_DecryptFinal(session.id(), 0, out, outOfs,847outLen);848}849}850return k;851} catch (PKCS11Exception e) {852handleException(e);853throw new ProviderException("doFinal() failed", e);854} finally {855reset(doCancel);856}857}858859private int implDoFinal(ByteBuffer outBuffer)860throws ShortBufferException, IllegalBlockSizeException,861BadPaddingException {862int outLen = outBuffer.remaining();863int requiredOutLen = doFinalLength(0);864if (outLen < requiredOutLen) {865throw new ShortBufferException();866}867868boolean doCancel = true;869try {870ensureInitialized();871872long outAddr = 0;873byte[] outArray = null;874int outOfs = 0;875if (outBuffer instanceof DirectBuffer) {876outAddr = ((DirectBuffer) outBuffer).address();877outOfs = outBuffer.position();878} else {879if (outBuffer.hasArray()) {880outArray = outBuffer.array();881outOfs = outBuffer.position() + outBuffer.arrayOffset();882} else {883outArray = new byte[outLen];884}885}886887int k = 0;888889if (encrypt) {890if (paddingObj != null) {891int startOff = 0;892if (reqBlockUpdates) {893startOff = padBufferLen;894}895int actualPadLen = paddingObj.setPaddingBytes(padBuffer,896startOff, requiredOutLen - bytesBuffered);897k = token.p11.C_EncryptUpdate(session.id(),8980, padBuffer, 0, startOff + actualPadLen,899outAddr, outArray, outOfs, outLen);900}901// Some implementations such as the NSS Software Token do not902// cancel the operation upon a C_EncryptUpdate failure (as903// required by the PKCS#11 standard). Cancel is not needed904// only after this point. See JDK-8258833 for further905// information.906doCancel = false;907k += token.p11.C_EncryptFinal(session.id(),908outAddr, outArray, (outOfs + k), (outLen - k));909} else {910// Special handling to match SunJCE provider behavior911if (bytesBuffered == 0 && padBufferLen == 0) {912return 0;913}914915if (paddingObj != null) {916if (padBufferLen != 0) {917k = token.p11.C_DecryptUpdate(session.id(),9180, padBuffer, 0, padBufferLen,9190, padBuffer, 0, padBuffer.length);920padBufferLen = 0;921}922// Some implementations such as the NSS Software Token do not923// cancel the operation upon a C_DecryptUpdate failure (as924// required by the PKCS#11 standard). Cancel is not needed925// only after this point. See JDK-8258833 for further926// information.927doCancel = false;928k += token.p11.C_DecryptFinal(session.id(),9290, padBuffer, k, padBuffer.length - k);930931int actualPadLen = paddingObj.unpad(padBuffer, k);932k -= actualPadLen;933outArray = padBuffer;934outOfs = 0;935} else {936doCancel = false;937k = token.p11.C_DecryptFinal(session.id(),938outAddr, outArray, outOfs, outLen);939}940}941if ((!encrypt && paddingObj != null) ||942(!(outBuffer instanceof DirectBuffer) &&943!outBuffer.hasArray())) {944outBuffer.put(outArray, outOfs, k);945} else {946outBuffer.position(outBuffer.position() + k);947}948return k;949} catch (PKCS11Exception e) {950handleException(e);951throw new ProviderException("doFinal() failed", e);952} finally {953reset(doCancel);954}955}956957private void handleException(PKCS11Exception e)958throws ShortBufferException, IllegalBlockSizeException {959long errorCode = e.getErrorCode();960if (errorCode == CKR_BUFFER_TOO_SMALL) {961throw (ShortBufferException)962(new ShortBufferException().initCause(e));963} else if (errorCode == CKR_DATA_LEN_RANGE ||964errorCode == CKR_ENCRYPTED_DATA_LEN_RANGE) {965throw (IllegalBlockSizeException)966(new IllegalBlockSizeException(e.toString()).initCause(e));967}968}969970// see JCE spec971protected byte[] engineWrap(Key key) throws IllegalBlockSizeException,972InvalidKeyException {973// XXX key wrapping974throw new UnsupportedOperationException("engineWrap()");975}976977// see JCE spec978protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,979int wrappedKeyType)980throws InvalidKeyException, NoSuchAlgorithmException {981// XXX key unwrapping982throw new UnsupportedOperationException("engineUnwrap()");983}984985// see JCE spec986@Override987protected int engineGetKeySize(Key key) throws InvalidKeyException {988int n = P11SecretKeyFactory.convertKey989(token, key, keyAlgorithm).length();990return n;991}992993private final void bufferInputBytes(byte[] in, int inOfs, int len) {994System.arraycopy(in, inOfs, padBuffer, padBufferLen, len);995padBufferLen += len;996bytesBuffered += len;997}998999private final void bufferInputBytes(ByteBuffer inBuffer, int len) {1000inBuffer.get(padBuffer, padBufferLen, len);1001padBufferLen += len;1002bytesBuffered += len;1003}1004}100510061007