0N/A/*
4589N/A * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/Apackage sun.security.pkcs11;
0N/A
0N/Aimport java.nio.ByteBuffer;
149N/Aimport java.util.Arrays;
2619N/Aimport java.util.Locale;
0N/A
0N/Aimport java.security.*;
0N/Aimport java.security.spec.*;
0N/A
0N/Aimport javax.crypto.*;
0N/Aimport javax.crypto.spec.*;
0N/A
0N/Aimport sun.nio.ch.DirectBuffer;
0N/Aimport sun.security.pkcs11.wrapper.*;
0N/Aimport static sun.security.pkcs11.wrapper.PKCS11Constants.*;
0N/A
0N/A/**
0N/A * Cipher implementation class. This class currently supports
0N/A * DES, DESede, AES, ARCFOUR, and Blowfish.
0N/A *
3645N/A * This class is designed to support ECB, CBC, CTR with NoPadding
3645N/A * and ECB, CBC with PKCS5Padding. It will use its own padding impl
3645N/A * if the native mechanism does not support padding.
0N/A *
3645N/A * Note that PKCS#11 currently only supports ECB, CBC, and CTR.
3645N/A * There are no provisions for other modes such as CFB, OFB, and PCBC.
0N/A *
0N/A * @author Andreas Sterbenz
0N/A * @since 1.5
0N/A */
0N/Afinal class P11Cipher extends CipherSpi {
0N/A
0N/A // mode constant for ECB mode
0N/A private final static int MODE_ECB = 3;
0N/A // mode constant for CBC mode
0N/A private final static int MODE_CBC = 4;
3645N/A // mode constant for CTR mode
3645N/A private final static int MODE_CTR = 5;
0N/A
0N/A // padding constant for NoPadding
149N/A private final static int PAD_NONE = 5;
0N/A // padding constant for PKCS5Padding
0N/A private final static int PAD_PKCS5 = 6;
0N/A
149N/A private static interface Padding {
149N/A // ENC: format the specified buffer with padding bytes and return the
149N/A // actual padding length
149N/A int setPaddingBytes(byte[] paddingBuffer, int padLen);
149N/A
149N/A // DEC: return the length of trailing padding bytes given the specified
149N/A // padded data
156N/A int unpad(byte[] paddedData, int len)
3103N/A throws BadPaddingException, IllegalBlockSizeException;
149N/A }
149N/A
149N/A private static class PKCS5Padding implements Padding {
149N/A
149N/A private final int blockSize;
149N/A
149N/A PKCS5Padding(int blockSize)
149N/A throws NoSuchPaddingException {
149N/A if (blockSize == 0) {
149N/A throw new NoSuchPaddingException
149N/A ("PKCS#5 padding not supported with stream ciphers");
149N/A }
149N/A this.blockSize = blockSize;
149N/A }
149N/A
149N/A public int setPaddingBytes(byte[] paddingBuffer, int padLen) {
149N/A Arrays.fill(paddingBuffer, 0, padLen, (byte) (padLen & 0x007f));
149N/A return padLen;
149N/A }
149N/A
156N/A public int unpad(byte[] paddedData, int len)
3103N/A throws BadPaddingException, IllegalBlockSizeException {
3103N/A if ((len < 1) || (len % blockSize != 0)) {
3103N/A throw new IllegalBlockSizeException
3103N/A ("Input length must be multiples of " + blockSize);
156N/A }
156N/A byte padValue = paddedData[len - 1];
149N/A if (padValue < 1 || padValue > blockSize) {
149N/A throw new BadPaddingException("Invalid pad value!");
149N/A }
149N/A // sanity check padding bytes
156N/A int padStartIndex = len - padValue;
149N/A for (int i = padStartIndex; i < len; i++) {
149N/A if (paddedData[i] != padValue) {
149N/A throw new BadPaddingException("Invalid pad bytes!");
149N/A }
149N/A }
149N/A return padValue;
149N/A }
149N/A }
149N/A
0N/A // token instance
0N/A private final Token token;
0N/A
0N/A // algorithm name
0N/A private final String algorithm;
0N/A
0N/A // name of the key algorithm, e.g. DES instead of algorithm DES/CBC/...
0N/A private final String keyAlgorithm;
0N/A
0N/A // mechanism id
0N/A private final long mechanism;
0N/A
0N/A // associated session, if any
0N/A private Session session;
0N/A
0N/A // key, if init() was called
0N/A private P11Key p11Key;
0N/A
0N/A // flag indicating whether an operation is initialized
0N/A private boolean initialized;
0N/A
0N/A // falg indicating encrypt or decrypt mode
0N/A private boolean encrypt;
0N/A
0N/A // mode, one of MODE_* above (MODE_ECB for stream ciphers)
0N/A private int blockMode;
0N/A
0N/A // block size, 0 for stream ciphers
0N/A private final int blockSize;
0N/A
0N/A // padding type, on of PAD_* above (PAD_NONE for stream ciphers)
0N/A private int paddingType;
0N/A
149N/A // when the padding is requested but unsupported by the native mechanism,
149N/A // we use the following to do padding and necessary data buffering.
149N/A // padding object which generate padding and unpad the decrypted data
149N/A private Padding paddingObj;
149N/A // buffer for holding back the block which contains padding bytes
149N/A private byte[] padBuffer;
149N/A private int padBufferLen;
149N/A
3645N/A // original IV, if in MODE_CBC or MODE_CTR
0N/A private byte[] iv;
0N/A
149N/A // number of bytes buffered internally by the native mechanism and padBuffer
149N/A // if we do the padding
149N/A private int bytesBuffered;
0N/A
0N/A P11Cipher(Token token, String algorithm, long mechanism)
149N/A throws PKCS11Exception, NoSuchAlgorithmException {
0N/A super();
0N/A this.token = token;
0N/A this.algorithm = algorithm;
0N/A this.mechanism = mechanism;
149N/A
149N/A String algoParts[] = algorithm.split("/");
149N/A keyAlgorithm = algoParts[0];
149N/A
0N/A if (keyAlgorithm.equals("AES")) {
0N/A blockSize = 16;
149N/A } else if (keyAlgorithm.equals("RC4") ||
149N/A keyAlgorithm.equals("ARCFOUR")) {
0N/A blockSize = 0;
0N/A } else { // DES, DESede, Blowfish
0N/A blockSize = 8;
149N/A }
149N/A this.blockMode =
149N/A (algoParts.length > 1 ? parseMode(algoParts[1]) : MODE_ECB);
149N/A
149N/A String defPadding = (blockSize == 0 ? "NoPadding" : "PKCS5Padding");
149N/A String paddingStr =
149N/A (algoParts.length > 2 ? algoParts[2] : defPadding);
149N/A try {
149N/A engineSetPadding(paddingStr);
149N/A } catch (NoSuchPaddingException nspe) {
149N/A // should not happen
149N/A throw new ProviderException(nspe);
0N/A }
0N/A }
0N/A
0N/A protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
149N/A // Disallow change of mode for now since currently it's explicitly
149N/A // defined in transformation strings
149N/A throw new NoSuchAlgorithmException("Unsupported mode " + mode);
149N/A }
149N/A
149N/A private int parseMode(String mode) throws NoSuchAlgorithmException {
2619N/A mode = mode.toUpperCase(Locale.ENGLISH);
149N/A int result;
0N/A if (mode.equals("ECB")) {
149N/A result = MODE_ECB;
0N/A } else if (mode.equals("CBC")) {
0N/A if (blockSize == 0) {
0N/A throw new NoSuchAlgorithmException
0N/A ("CBC mode not supported with stream ciphers");
0N/A }
149N/A result = MODE_CBC;
3645N/A } else if (mode.equals("CTR")) {
3645N/A result = MODE_CTR;
0N/A } else {
0N/A throw new NoSuchAlgorithmException("Unsupported mode " + mode);
0N/A }
149N/A return result;
0N/A }
0N/A
0N/A // see JCE spec
0N/A protected void engineSetPadding(String padding)
0N/A throws NoSuchPaddingException {
149N/A paddingObj = null;
149N/A padBuffer = null;
2619N/A padding = padding.toUpperCase(Locale.ENGLISH);
149N/A if (padding.equals("NOPADDING")) {
0N/A paddingType = PAD_NONE;
149N/A } else if (padding.equals("PKCS5PADDING")) {
3645N/A if (this.blockMode == MODE_CTR) {
3645N/A throw new NoSuchPaddingException
3645N/A ("PKCS#5 padding not supported with CTR mode");
3645N/A }
149N/A paddingType = PAD_PKCS5;
149N/A if (mechanism != CKM_DES_CBC_PAD && mechanism != CKM_DES3_CBC_PAD &&
149N/A mechanism != CKM_AES_CBC_PAD) {
149N/A // no native padding support; use our own padding impl
149N/A paddingObj = new PKCS5Padding(blockSize);
149N/A padBuffer = new byte[blockSize];
0N/A }
0N/A } else {
0N/A throw new NoSuchPaddingException("Unsupported padding " + padding);
0N/A }
0N/A }
0N/A
0N/A // see JCE spec
0N/A protected int engineGetBlockSize() {
0N/A return blockSize;
0N/A }
0N/A
0N/A // see JCE spec
0N/A protected int engineGetOutputSize(int inputLen) {
0N/A return doFinalLength(inputLen);
0N/A }
0N/A
0N/A // see JCE spec
0N/A protected byte[] engineGetIV() {
149N/A return (iv == null) ? null : (byte[]) iv.clone();
0N/A }
0N/A
0N/A // see JCE spec
0N/A protected AlgorithmParameters engineGetParameters() {
0N/A if (iv == null) {
0N/A return null;
0N/A }
0N/A IvParameterSpec ivSpec = new IvParameterSpec(iv);
0N/A try {
149N/A AlgorithmParameters params =
149N/A AlgorithmParameters.getInstance(keyAlgorithm,
149N/A P11Util.getSunJceProvider());
0N/A params.init(ivSpec);
0N/A return params;
0N/A } catch (GeneralSecurityException e) {
0N/A // NoSuchAlgorithmException, NoSuchProviderException
0N/A // InvalidParameterSpecException
0N/A throw new ProviderException("Could not encode parameters", e);
0N/A }
0N/A }
0N/A
0N/A // see JCE spec
0N/A protected void engineInit(int opmode, Key key, SecureRandom random)
0N/A throws InvalidKeyException {
0N/A try {
0N/A implInit(opmode, key, null, random);
0N/A } catch (InvalidAlgorithmParameterException e) {
0N/A throw new InvalidKeyException("init() failed", e);
0N/A }
0N/A }
0N/A
0N/A // see JCE spec
0N/A protected void engineInit(int opmode, Key key,
0N/A AlgorithmParameterSpec params, SecureRandom random)
0N/A throws InvalidKeyException, InvalidAlgorithmParameterException {
149N/A byte[] ivValue;
0N/A if (params != null) {
0N/A if (params instanceof IvParameterSpec == false) {
0N/A throw new InvalidAlgorithmParameterException
0N/A ("Only IvParameterSpec supported");
0N/A }
149N/A IvParameterSpec ivSpec = (IvParameterSpec) params;
149N/A ivValue = ivSpec.getIV();
0N/A } else {
149N/A ivValue = null;
0N/A }
149N/A implInit(opmode, key, ivValue, random);
0N/A }
0N/A
0N/A // see JCE spec
0N/A protected void engineInit(int opmode, Key key, AlgorithmParameters params,
0N/A SecureRandom random)
0N/A throws InvalidKeyException, InvalidAlgorithmParameterException {
149N/A byte[] ivValue;
0N/A if (params != null) {
0N/A try {
0N/A IvParameterSpec ivSpec = (IvParameterSpec)
0N/A params.getParameterSpec(IvParameterSpec.class);
149N/A ivValue = ivSpec.getIV();
0N/A } catch (InvalidParameterSpecException e) {
0N/A throw new InvalidAlgorithmParameterException
0N/A ("Could not decode IV", e);
0N/A }
0N/A } else {
149N/A ivValue = null;
0N/A }
149N/A implInit(opmode, key, ivValue, random);
0N/A }
0N/A
0N/A // actual init() implementation
0N/A private void implInit(int opmode, Key key, byte[] iv,
0N/A SecureRandom random)
0N/A throws InvalidKeyException, InvalidAlgorithmParameterException {
0N/A cancelOperation();
0N/A switch (opmode) {
149N/A case Cipher.ENCRYPT_MODE:
149N/A encrypt = true;
149N/A break;
149N/A case Cipher.DECRYPT_MODE:
149N/A encrypt = false;
149N/A break;
149N/A default:
149N/A throw new InvalidAlgorithmParameterException
149N/A ("Unsupported mode: " + opmode);
0N/A }
0N/A if (blockMode == MODE_ECB) { // ECB or stream cipher
0N/A if (iv != null) {
0N/A if (blockSize == 0) {
0N/A throw new InvalidAlgorithmParameterException
149N/A ("IV not used with stream ciphers");
0N/A } else {
0N/A throw new InvalidAlgorithmParameterException
149N/A ("IV not used in ECB mode");
0N/A }
0N/A }
3645N/A } else { // MODE_CBC or MODE_CTR
0N/A if (iv == null) {
0N/A if (encrypt == false) {
3645N/A String exMsg =
3645N/A (blockMode == MODE_CBC ?
3645N/A "IV must be specified for decryption in CBC mode" :
3645N/A "IV must be specified for decryption in CTR mode");
3645N/A throw new InvalidAlgorithmParameterException(exMsg);
0N/A }
0N/A // generate random IV
0N/A if (random == null) {
0N/A random = new SecureRandom();
0N/A }
0N/A iv = new byte[blockSize];
0N/A random.nextBytes(iv);
0N/A } else {
0N/A if (iv.length != blockSize) {
0N/A throw new InvalidAlgorithmParameterException
149N/A ("IV length must match block size");
0N/A }
0N/A }
0N/A }
0N/A this.iv = iv;
0N/A p11Key = P11SecretKeyFactory.convertKey(token, key, keyAlgorithm);
0N/A try {
0N/A initialize();
0N/A } catch (PKCS11Exception e) {
0N/A throw new InvalidKeyException("Could not initialize cipher", e);
0N/A }
0N/A }
0N/A
0N/A private void cancelOperation() {
0N/A if (initialized == false) {
0N/A return;
0N/A }
0N/A initialized = false;
0N/A if ((session == null) || (token.explicitCancel == false)) {
0N/A return;
0N/A }
0N/A // cancel operation by finishing it
0N/A int bufLen = doFinalLength(0);
0N/A byte[] buffer = new byte[bufLen];
0N/A try {
0N/A if (encrypt) {
0N/A token.p11.C_EncryptFinal(session.id(), 0, buffer, 0, bufLen);
0N/A } else {
0N/A token.p11.C_DecryptFinal(session.id(), 0, buffer, 0, bufLen);
0N/A }
0N/A } catch (PKCS11Exception e) {
0N/A throw new ProviderException("Cancel failed", e);
3332N/A } finally {
3332N/A reset();
0N/A }
0N/A }
0N/A
0N/A private void ensureInitialized() throws PKCS11Exception {
0N/A if (initialized == false) {
0N/A initialize();
0N/A }
0N/A }
0N/A
0N/A private void initialize() throws PKCS11Exception {
0N/A if (session == null) {
0N/A session = token.getOpSession();
0N/A }
3645N/A CK_MECHANISM mechParams = (blockMode == MODE_CTR?
3645N/A new CK_MECHANISM(mechanism, new CK_AES_CTR_PARAMS(iv)) :
3645N/A new CK_MECHANISM(mechanism, iv));
3645N/A
3332N/A try {
3332N/A if (encrypt) {
3645N/A token.p11.C_EncryptInit(session.id(), mechParams, p11Key.keyID);
3332N/A } else {
3645N/A token.p11.C_DecryptInit(session.id(), mechParams, p11Key.keyID);
3332N/A }
3332N/A } catch (PKCS11Exception ex) {
3332N/A // release session when initialization failed
3332N/A session = token.releaseSession(session);
3332N/A throw ex;
0N/A }
149N/A bytesBuffered = 0;
149N/A padBufferLen = 0;
0N/A initialized = true;
0N/A }
0N/A
0N/A // if update(inLen) is called, how big does the output buffer have to be?
0N/A private int updateLength(int inLen) {
0N/A if (inLen <= 0) {
0N/A return 0;
0N/A }
149N/A
149N/A int result = inLen + bytesBuffered;
149N/A if (blockSize != 0) {
149N/A // minus the number of bytes in the last incomplete block.
149N/A result -= (result & (blockSize - 1));
0N/A }
149N/A return result;
0N/A }
0N/A
0N/A // if doFinal(inLen) is called, how big does the output buffer have to be?
0N/A private int doFinalLength(int inLen) {
0N/A if (inLen < 0) {
0N/A return 0;
0N/A }
149N/A
149N/A int result = inLen + bytesBuffered;
149N/A if (blockSize != 0 && encrypt && paddingType != PAD_NONE) {
149N/A // add the number of bytes to make the last block complete.
149N/A result += (blockSize - (result & (blockSize - 1)));
149N/A }
149N/A return result;
0N/A }
0N/A
3332N/A // reset the states to the pre-initialized values
3332N/A private void reset() {
3332N/A initialized = false;
3332N/A bytesBuffered = 0;
3332N/A padBufferLen = 0;
3332N/A if (session != null) {
3332N/A session = token.releaseSession(session);
3332N/A }
3332N/A }
3332N/A
0N/A // see JCE spec
0N/A protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) {
0N/A try {
0N/A byte[] out = new byte[updateLength(inLen)];
0N/A int n = engineUpdate(in, inOfs, inLen, out, 0);
0N/A return P11Util.convert(out, 0, n);
0N/A } catch (ShortBufferException e) {
149N/A // convert since the output length is calculated by updateLength()
0N/A throw new ProviderException(e);
0N/A }
0N/A }
0N/A
0N/A // see JCE spec
0N/A protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out,
0N/A int outOfs) throws ShortBufferException {
0N/A int outLen = out.length - outOfs;
0N/A return implUpdate(in, inOfs, inLen, out, outOfs, outLen);
0N/A }
0N/A
0N/A // see JCE spec
149N/A @Override
0N/A protected int engineUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer)
0N/A throws ShortBufferException {
0N/A return implUpdate(inBuffer, outBuffer);
0N/A }
0N/A
0N/A // see JCE spec
0N/A protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen)
0N/A throws IllegalBlockSizeException, BadPaddingException {
0N/A try {
0N/A byte[] out = new byte[doFinalLength(inLen)];
0N/A int n = engineDoFinal(in, inOfs, inLen, out, 0);
0N/A return P11Util.convert(out, 0, n);
0N/A } catch (ShortBufferException e) {
149N/A // convert since the output length is calculated by doFinalLength()
0N/A throw new ProviderException(e);
0N/A }
0N/A }
0N/A
0N/A // see JCE spec
0N/A protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out,
149N/A int outOfs) throws ShortBufferException, IllegalBlockSizeException,
149N/A BadPaddingException {
0N/A int n = 0;
0N/A if ((inLen != 0) && (in != null)) {
0N/A n = engineUpdate(in, inOfs, inLen, out, outOfs);
0N/A outOfs += n;
0N/A }
0N/A n += implDoFinal(out, outOfs, out.length - outOfs);
0N/A return n;
0N/A }
0N/A
0N/A // see JCE spec
149N/A @Override
0N/A protected int engineDoFinal(ByteBuffer inBuffer, ByteBuffer outBuffer)
149N/A throws ShortBufferException, IllegalBlockSizeException,
149N/A BadPaddingException {
0N/A int n = engineUpdate(inBuffer, outBuffer);
0N/A n += implDoFinal(outBuffer);
0N/A return n;
0N/A }
0N/A
0N/A private int implUpdate(byte[] in, int inOfs, int inLen,
0N/A byte[] out, int outOfs, int outLen) throws ShortBufferException {
0N/A if (outLen < updateLength(inLen)) {
0N/A throw new ShortBufferException();
0N/A }
0N/A try {
0N/A ensureInitialized();
149N/A int k = 0;
0N/A if (encrypt) {
149N/A k = token.p11.C_EncryptUpdate(session.id(), 0, in, inOfs, inLen,
149N/A 0, out, outOfs, outLen);
0N/A } else {
149N/A int newPadBufferLen = 0;
149N/A if (paddingObj != null) {
149N/A if (padBufferLen != 0) {
149N/A // NSS throws up when called with data not in multiple
149N/A // of blocks. Try to work around this by holding the
149N/A // extra data in padBuffer.
149N/A if (padBufferLen != padBuffer.length) {
149N/A int bufCapacity = padBuffer.length - padBufferLen;
149N/A if (inLen > bufCapacity) {
149N/A bufferInputBytes(in, inOfs, bufCapacity);
149N/A inOfs += bufCapacity;
149N/A inLen -= bufCapacity;
149N/A } else {
149N/A bufferInputBytes(in, inOfs, inLen);
149N/A return 0;
149N/A }
149N/A }
149N/A k = token.p11.C_DecryptUpdate(session.id(),
149N/A 0, padBuffer, 0, padBufferLen,
149N/A 0, out, outOfs, outLen);
149N/A padBufferLen = 0;
149N/A }
149N/A newPadBufferLen = inLen & (blockSize - 1);
149N/A if (newPadBufferLen == 0) {
149N/A newPadBufferLen = padBuffer.length;
149N/A }
149N/A inLen -= newPadBufferLen;
149N/A }
149N/A if (inLen > 0) {
149N/A k += token.p11.C_DecryptUpdate(session.id(), 0, in, inOfs,
149N/A inLen, 0, out, (outOfs + k), (outLen - k));
149N/A }
149N/A // update 'padBuffer' if using our own padding impl.
149N/A if (paddingObj != null) {
149N/A bufferInputBytes(in, inOfs + inLen, newPadBufferLen);
149N/A }
0N/A }
149N/A bytesBuffered += (inLen - k);
0N/A return k;
0N/A } catch (PKCS11Exception e) {
149N/A if (e.getErrorCode() == CKR_BUFFER_TOO_SMALL) {
149N/A throw (ShortBufferException)
149N/A (new ShortBufferException().initCause(e));
149N/A }
3332N/A reset();
0N/A throw new ProviderException("update() failed", e);
0N/A }
0N/A }
0N/A
0N/A private int implUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer)
0N/A throws ShortBufferException {
0N/A int inLen = inBuffer.remaining();
0N/A if (inLen <= 0) {
0N/A return 0;
0N/A }
0N/A
0N/A int outLen = outBuffer.remaining();
0N/A if (outLen < updateLength(inLen)) {
0N/A throw new ShortBufferException();
0N/A }
149N/A int origPos = inBuffer.position();
0N/A try {
0N/A ensureInitialized();
0N/A
0N/A long inAddr = 0;
149N/A int inOfs = 0;
0N/A byte[] inArray = null;
149N/A
0N/A if (inBuffer instanceof DirectBuffer) {
149N/A inAddr = ((DirectBuffer) inBuffer).address();
149N/A inOfs = origPos;
149N/A } else if (inBuffer.hasArray()) {
149N/A inArray = inBuffer.array();
149N/A inOfs = (origPos + inBuffer.arrayOffset());
0N/A }
0N/A
0N/A long outAddr = 0;
149N/A int outOfs = 0;
0N/A byte[] outArray = null;
0N/A if (outBuffer instanceof DirectBuffer) {
149N/A outAddr = ((DirectBuffer) outBuffer).address();
149N/A outOfs = outBuffer.position();
0N/A } else {
0N/A if (outBuffer.hasArray()) {
0N/A outArray = outBuffer.array();
149N/A outOfs = (outBuffer.position() + outBuffer.arrayOffset());
0N/A } else {
0N/A outArray = new byte[outLen];
0N/A }
0N/A }
0N/A
149N/A int k = 0;
0N/A if (encrypt) {
149N/A if (inAddr == 0 && inArray == null) {
149N/A inArray = new byte[inLen];
149N/A inBuffer.get(inArray);
149N/A } else {
149N/A inBuffer.position(origPos + inLen);
149N/A }
149N/A k = token.p11.C_EncryptUpdate(session.id(),
149N/A inAddr, inArray, inOfs, inLen,
149N/A outAddr, outArray, outOfs, outLen);
0N/A } else {
149N/A int newPadBufferLen = 0;
149N/A if (paddingObj != null) {
149N/A if (padBufferLen != 0) {
149N/A // NSS throws up when called with data not in multiple
149N/A // of blocks. Try to work around this by holding the
149N/A // extra data in padBuffer.
149N/A if (padBufferLen != padBuffer.length) {
149N/A int bufCapacity = padBuffer.length - padBufferLen;
149N/A if (inLen > bufCapacity) {
149N/A bufferInputBytes(inBuffer, bufCapacity);
149N/A inOfs += bufCapacity;
149N/A inLen -= bufCapacity;
149N/A } else {
149N/A bufferInputBytes(inBuffer, inLen);
149N/A return 0;
149N/A }
149N/A }
149N/A k = token.p11.C_DecryptUpdate(session.id(), 0,
149N/A padBuffer, 0, padBufferLen, outAddr, outArray,
149N/A outOfs, outLen);
149N/A padBufferLen = 0;
149N/A }
149N/A newPadBufferLen = inLen & (blockSize - 1);
149N/A if (newPadBufferLen == 0) {
149N/A newPadBufferLen = padBuffer.length;
149N/A }
149N/A inLen -= newPadBufferLen;
149N/A }
149N/A if (inLen > 0) {
149N/A if (inAddr == 0 && inArray == null) {
149N/A inArray = new byte[inLen];
149N/A inBuffer.get(inArray);
149N/A } else {
149N/A inBuffer.position(inBuffer.position() + inLen);
149N/A }
149N/A k += token.p11.C_DecryptUpdate(session.id(), inAddr,
149N/A inArray, inOfs, inLen, outAddr, outArray,
149N/A (outOfs + k), (outLen - k));
149N/A }
149N/A // update 'padBuffer' if using our own padding impl.
149N/A if (paddingObj != null && newPadBufferLen != 0) {
149N/A bufferInputBytes(inBuffer, newPadBufferLen);
149N/A }
0N/A }
149N/A bytesBuffered += (inLen - k);
0N/A if (!(outBuffer instanceof DirectBuffer) &&
149N/A !outBuffer.hasArray()) {
0N/A outBuffer.put(outArray, outOfs, k);
0N/A } else {
0N/A outBuffer.position(outBuffer.position() + k);
0N/A }
0N/A return k;
0N/A } catch (PKCS11Exception e) {
149N/A // Reset input buffer to its original position for
149N/A inBuffer.position(origPos);
149N/A if (e.getErrorCode() == CKR_BUFFER_TOO_SMALL) {
149N/A throw (ShortBufferException)
149N/A (new ShortBufferException().initCause(e));
0N/A }
3332N/A reset();
0N/A throw new ProviderException("update() failed", e);
0N/A }
0N/A }
0N/A
0N/A private int implDoFinal(byte[] out, int outOfs, int outLen)
149N/A throws ShortBufferException, IllegalBlockSizeException,
149N/A BadPaddingException {
149N/A int requiredOutLen = doFinalLength(0);
149N/A if (outLen < requiredOutLen) {
0N/A throw new ShortBufferException();
0N/A }
0N/A try {
0N/A ensureInitialized();
149N/A int k = 0;
0N/A if (encrypt) {
149N/A if (paddingObj != null) {
149N/A int actualPadLen = paddingObj.setPaddingBytes(padBuffer,
149N/A requiredOutLen - bytesBuffered);
149N/A k = token.p11.C_EncryptUpdate(session.id(),
149N/A 0, padBuffer, 0, actualPadLen,
149N/A 0, out, outOfs, outLen);
149N/A }
149N/A k += token.p11.C_EncryptFinal(session.id(),
149N/A 0, out, (outOfs + k), (outLen - k));
0N/A } else {
149N/A if (paddingObj != null) {
149N/A if (padBufferLen != 0) {
149N/A k = token.p11.C_DecryptUpdate(session.id(), 0,
149N/A padBuffer, 0, padBufferLen, 0, padBuffer, 0,
149N/A padBuffer.length);
149N/A }
149N/A k += token.p11.C_DecryptFinal(session.id(), 0, padBuffer, k,
149N/A padBuffer.length - k);
156N/A int actualPadLen = paddingObj.unpad(padBuffer, k);
149N/A k -= actualPadLen;
149N/A System.arraycopy(padBuffer, 0, out, outOfs, k);
149N/A } else {
149N/A k = token.p11.C_DecryptFinal(session.id(), 0, out, outOfs,
149N/A outLen);
149N/A }
0N/A }
149N/A return k;
0N/A } catch (PKCS11Exception e) {
0N/A handleException(e);
0N/A throw new ProviderException("doFinal() failed", e);
0N/A } finally {
3332N/A reset();
0N/A }
0N/A }
0N/A
0N/A private int implDoFinal(ByteBuffer outBuffer)
149N/A throws ShortBufferException, IllegalBlockSizeException,
149N/A BadPaddingException {
0N/A int outLen = outBuffer.remaining();
149N/A int requiredOutLen = doFinalLength(0);
149N/A if (outLen < requiredOutLen) {
0N/A throw new ShortBufferException();
0N/A }
0N/A
0N/A try {
0N/A ensureInitialized();
0N/A
0N/A long outAddr = 0;
0N/A byte[] outArray = null;
149N/A int outOfs = 0;
0N/A if (outBuffer instanceof DirectBuffer) {
149N/A outAddr = ((DirectBuffer) outBuffer).address();
149N/A outOfs = outBuffer.position();
0N/A } else {
0N/A if (outBuffer.hasArray()) {
0N/A outArray = outBuffer.array();
149N/A outOfs = outBuffer.position() + outBuffer.arrayOffset();
0N/A } else {
0N/A outArray = new byte[outLen];
0N/A }
0N/A }
0N/A
149N/A int k = 0;
149N/A
0N/A if (encrypt) {
149N/A if (paddingObj != null) {
149N/A int actualPadLen = paddingObj.setPaddingBytes(padBuffer,
149N/A requiredOutLen - bytesBuffered);
149N/A k = token.p11.C_EncryptUpdate(session.id(),
149N/A 0, padBuffer, 0, actualPadLen,
149N/A outAddr, outArray, outOfs, outLen);
149N/A }
149N/A k += token.p11.C_EncryptFinal(session.id(),
149N/A outAddr, outArray, (outOfs + k), (outLen - k));
0N/A } else {
149N/A if (paddingObj != null) {
149N/A if (padBufferLen != 0) {
149N/A k = token.p11.C_DecryptUpdate(session.id(),
149N/A 0, padBuffer, 0, padBufferLen,
149N/A 0, padBuffer, 0, padBuffer.length);
149N/A padBufferLen = 0;
149N/A }
149N/A k += token.p11.C_DecryptFinal(session.id(),
149N/A 0, padBuffer, k, padBuffer.length - k);
156N/A int actualPadLen = paddingObj.unpad(padBuffer, k);
149N/A k -= actualPadLen;
149N/A outArray = padBuffer;
149N/A outOfs = 0;
149N/A } else {
149N/A k = token.p11.C_DecryptFinal(session.id(),
149N/A outAddr, outArray, outOfs, outLen);
149N/A }
0N/A }
149N/A if ((!encrypt && paddingObj != null) ||
149N/A (!(outBuffer instanceof DirectBuffer) &&
149N/A !outBuffer.hasArray())) {
0N/A outBuffer.put(outArray, outOfs, k);
0N/A } else {
0N/A outBuffer.position(outBuffer.position() + k);
0N/A }
0N/A return k;
0N/A } catch (PKCS11Exception e) {
0N/A handleException(e);
0N/A throw new ProviderException("doFinal() failed", e);
0N/A } finally {
3332N/A reset();
0N/A }
0N/A }
0N/A
0N/A private void handleException(PKCS11Exception e)
149N/A throws ShortBufferException, IllegalBlockSizeException {
0N/A long errorCode = e.getErrorCode();
149N/A if (errorCode == CKR_BUFFER_TOO_SMALL) {
149N/A throw (ShortBufferException)
149N/A (new ShortBufferException().initCause(e));
157N/A } else if (errorCode == CKR_DATA_LEN_RANGE ||
157N/A errorCode == CKR_ENCRYPTED_DATA_LEN_RANGE) {
149N/A throw (IllegalBlockSizeException)
149N/A (new IllegalBlockSizeException(e.toString()).initCause(e));
0N/A }
0N/A }
0N/A
0N/A // see JCE spec
0N/A protected byte[] engineWrap(Key key) throws IllegalBlockSizeException,
0N/A InvalidKeyException {
0N/A // XXX key wrapping
0N/A throw new UnsupportedOperationException("engineWrap()");
0N/A }
0N/A
0N/A // see JCE spec
0N/A protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
0N/A int wrappedKeyType)
0N/A throws InvalidKeyException, NoSuchAlgorithmException {
0N/A // XXX key unwrapping
0N/A throw new UnsupportedOperationException("engineUnwrap()");
0N/A }
0N/A
0N/A // see JCE spec
149N/A @Override
0N/A protected int engineGetKeySize(Key key) throws InvalidKeyException {
0N/A int n = P11SecretKeyFactory.convertKey
4589N/A (token, key, keyAlgorithm).length();
0N/A return n;
0N/A }
0N/A
149N/A private final void bufferInputBytes(byte[] in, int inOfs, int len) {
149N/A System.arraycopy(in, inOfs, padBuffer, padBufferLen, len);
149N/A padBufferLen += len;
149N/A bytesBuffered += len;
149N/A }
149N/A
149N/A private final void bufferInputBytes(ByteBuffer inBuffer, int len) {
149N/A inBuffer.get(padBuffer, padBufferLen, len);
149N/A padBufferLen += len;
149N/A bytesBuffered += len;
149N/A }
0N/A}