/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* Cipher implementation class. This class currently supports
* DES, DESede, AES, ARCFOUR, and Blowfish.
*
* This class is designed to support ECB, CBC, CTR with NoPadding
* and ECB, CBC with PKCS5Padding. It will use its own padding impl
* if the native mechanism does not support padding.
*
* Note that PKCS#11 currently only supports ECB, CBC, and CTR.
* There are no provisions for other modes such as CFB, OFB, and PCBC.
*
* @author Andreas Sterbenz
* @since 1.5
*/
// mode constant for ECB mode
// mode constant for CBC mode
// mode constant for CTR mode
// padding constant for NoPadding
// padding constant for PKCS5Padding
private static interface Padding {
// ENC: format the specified buffer with padding bytes and return the
// actual padding length
// DEC: return the length of trailing padding bytes given the specified
// padded data
}
private final int blockSize;
throws NoSuchPaddingException {
if (blockSize == 0) {
throw new NoSuchPaddingException
("PKCS#5 padding not supported with stream ciphers");
}
}
return padLen;
}
throws BadPaddingException, IllegalBlockSizeException {
throw new IllegalBlockSizeException
("Input length must be multiples of " + blockSize);
}
throw new BadPaddingException("Invalid pad value!");
}
// sanity check padding bytes
for (int i = padStartIndex; i < len; i++) {
if (paddedData[i] != padValue) {
throw new BadPaddingException("Invalid pad bytes!");
}
}
return padValue;
}
}
// token instance
// algorithm name
// mechanism id
private final long mechanism;
// associated session, if any
// key, if init() was called
// flag indicating whether an operation is initialized
private boolean initialized;
// falg indicating encrypt or decrypt mode
private boolean encrypt;
// mode, one of MODE_* above (MODE_ECB for stream ciphers)
private int blockMode;
// block size, 0 for stream ciphers
private final int blockSize;
// padding type, on of PAD_* above (PAD_NONE for stream ciphers)
private int paddingType;
// when the padding is requested but unsupported by the native mechanism,
// we use the following to do padding and necessary data buffering.
// padding object which generate padding and unpad the decrypted data
// buffer for holding back the block which contains padding bytes
private byte[] padBuffer;
private int padBufferLen;
// original IV, if in MODE_CBC or MODE_CTR
private byte[] iv;
// number of bytes buffered internally by the native mechanism and padBuffer
// if we do the padding
private int bytesBuffered;
throws PKCS11Exception, NoSuchAlgorithmException {
super();
blockSize = 16;
blockSize = 0;
} else { // DES, DESede, Blowfish
blockSize = 8;
}
this.blockMode =
try {
} catch (NoSuchPaddingException nspe) {
// should not happen
throw new ProviderException(nspe);
}
}
// Disallow change of mode for now since currently it's explicitly
// defined in transformation strings
}
int result;
if (blockSize == 0) {
throw new NoSuchAlgorithmException
("CBC mode not supported with stream ciphers");
}
} else {
}
return result;
}
// see JCE spec
throws NoSuchPaddingException {
paddingObj = null;
throw new NoSuchPaddingException
("PKCS#5 padding not supported with CTR mode");
}
mechanism != CKM_AES_CBC_PAD) {
// no native padding support; use our own padding impl
}
} else {
}
}
// see JCE spec
protected int engineGetBlockSize() {
return blockSize;
}
// see JCE spec
return doFinalLength(inputLen);
}
// see JCE spec
protected byte[] engineGetIV() {
}
// see JCE spec
return null;
}
try {
return params;
} catch (GeneralSecurityException e) {
// NoSuchAlgorithmException, NoSuchProviderException
// InvalidParameterSpecException
throw new ProviderException("Could not encode parameters", e);
}
}
// see JCE spec
throws InvalidKeyException {
try {
} catch (InvalidAlgorithmParameterException e) {
throw new InvalidKeyException("init() failed", e);
}
}
// see JCE spec
byte[] ivValue;
if (params instanceof IvParameterSpec == false) {
throw new InvalidAlgorithmParameterException
("Only IvParameterSpec supported");
}
} else {
}
}
// see JCE spec
byte[] ivValue;
try {
} catch (InvalidParameterSpecException e) {
throw new InvalidAlgorithmParameterException
("Could not decode IV", e);
}
} else {
}
}
// actual init() implementation
switch (opmode) {
case Cipher.ENCRYPT_MODE:
encrypt = true;
break;
case Cipher.DECRYPT_MODE:
encrypt = false;
break;
default:
throw new InvalidAlgorithmParameterException
("Unsupported mode: " + opmode);
}
if (blockSize == 0) {
throw new InvalidAlgorithmParameterException
("IV not used with stream ciphers");
} else {
throw new InvalidAlgorithmParameterException
("IV not used in ECB mode");
}
}
} else { // MODE_CBC or MODE_CTR
if (encrypt == false) {
"IV must be specified for decryption in CBC mode" :
"IV must be specified for decryption in CTR mode");
throw new InvalidAlgorithmParameterException(exMsg);
}
// generate random IV
random = new SecureRandom();
}
} else {
throw new InvalidAlgorithmParameterException
("IV length must match block size");
}
}
}
try {
initialize();
} catch (PKCS11Exception e) {
throw new InvalidKeyException("Could not initialize cipher", e);
}
}
private void cancelOperation() {
if (initialized == false) {
return;
}
initialized = false;
return;
}
// cancel operation by finishing it
try {
if (encrypt) {
} else {
}
} catch (PKCS11Exception e) {
throw new ProviderException("Cancel failed", e);
} finally {
reset();
}
}
if (initialized == false) {
initialize();
}
}
}
try {
if (encrypt) {
} else {
}
} catch (PKCS11Exception ex) {
// release session when initialization failed
throw ex;
}
bytesBuffered = 0;
padBufferLen = 0;
initialized = true;
}
// if update(inLen) is called, how big does the output buffer have to be?
if (inLen <= 0) {
return 0;
}
if (blockSize != 0) {
// minus the number of bytes in the last incomplete block.
}
return result;
}
// if doFinal(inLen) is called, how big does the output buffer have to be?
if (inLen < 0) {
return 0;
}
// add the number of bytes to make the last block complete.
}
return result;
}
// reset the states to the pre-initialized values
private void reset() {
initialized = false;
bytesBuffered = 0;
padBufferLen = 0;
}
}
// see JCE spec
try {
} catch (ShortBufferException e) {
// convert since the output length is calculated by updateLength()
throw new ProviderException(e);
}
}
// see JCE spec
int outOfs) throws ShortBufferException {
}
// see JCE spec
throws ShortBufferException {
}
// see JCE spec
throws IllegalBlockSizeException, BadPaddingException {
try {
} catch (ShortBufferException e) {
// convert since the output length is calculated by doFinalLength()
throw new ProviderException(e);
}
}
// see JCE spec
int n = 0;
outOfs += n;
}
return n;
}
// see JCE spec
n += implDoFinal(outBuffer);
return n;
}
throw new ShortBufferException();
}
try {
int k = 0;
if (encrypt) {
} else {
int newPadBufferLen = 0;
if (paddingObj != null) {
if (padBufferLen != 0) {
// NSS throws up when called with data not in multiple
// of blocks. Try to work around this by holding the
// extra data in padBuffer.
if (inLen > bufCapacity) {
inOfs += bufCapacity;
inLen -= bufCapacity;
} else {
return 0;
}
}
padBufferLen = 0;
}
if (newPadBufferLen == 0) {
}
inLen -= newPadBufferLen;
}
if (inLen > 0) {
}
// update 'padBuffer' if using our own padding impl.
if (paddingObj != null) {
}
}
bytesBuffered += (inLen - k);
return k;
} catch (PKCS11Exception e) {
if (e.getErrorCode() == CKR_BUFFER_TOO_SMALL) {
throw (ShortBufferException)
(new ShortBufferException().initCause(e));
}
reset();
throw new ProviderException("update() failed", e);
}
}
throws ShortBufferException {
if (inLen <= 0) {
return 0;
}
throw new ShortBufferException();
}
try {
long inAddr = 0;
int inOfs = 0;
if (inBuffer instanceof DirectBuffer) {
}
long outAddr = 0;
int outOfs = 0;
if (outBuffer instanceof DirectBuffer) {
} else {
} else {
}
}
int k = 0;
if (encrypt) {
} else {
}
} else {
int newPadBufferLen = 0;
if (paddingObj != null) {
if (padBufferLen != 0) {
// NSS throws up when called with data not in multiple
// of blocks. Try to work around this by holding the
// extra data in padBuffer.
if (inLen > bufCapacity) {
inOfs += bufCapacity;
inLen -= bufCapacity;
} else {
return 0;
}
}
padBufferLen = 0;
}
if (newPadBufferLen == 0) {
}
inLen -= newPadBufferLen;
}
if (inLen > 0) {
} else {
}
}
// update 'padBuffer' if using our own padding impl.
}
}
bytesBuffered += (inLen - k);
if (!(outBuffer instanceof DirectBuffer) &&
} else {
}
return k;
} catch (PKCS11Exception e) {
// Reset input buffer to its original position for
if (e.getErrorCode() == CKR_BUFFER_TOO_SMALL) {
throw (ShortBufferException)
(new ShortBufferException().initCause(e));
}
reset();
throw new ProviderException("update() failed", e);
}
}
if (outLen < requiredOutLen) {
throw new ShortBufferException();
}
try {
int k = 0;
if (encrypt) {
if (paddingObj != null) {
}
} else {
if (paddingObj != null) {
if (padBufferLen != 0) {
}
k -= actualPadLen;
} else {
outLen);
}
}
return k;
} catch (PKCS11Exception e) {
handleException(e);
throw new ProviderException("doFinal() failed", e);
} finally {
reset();
}
}
if (outLen < requiredOutLen) {
throw new ShortBufferException();
}
try {
long outAddr = 0;
int outOfs = 0;
if (outBuffer instanceof DirectBuffer) {
} else {
} else {
}
}
int k = 0;
if (encrypt) {
if (paddingObj != null) {
}
} else {
if (paddingObj != null) {
if (padBufferLen != 0) {
padBufferLen = 0;
}
k -= actualPadLen;
outOfs = 0;
} else {
}
}
(!(outBuffer instanceof DirectBuffer) &&
} else {
}
return k;
} catch (PKCS11Exception e) {
handleException(e);
throw new ProviderException("doFinal() failed", e);
} finally {
reset();
}
}
long errorCode = e.getErrorCode();
if (errorCode == CKR_BUFFER_TOO_SMALL) {
throw (ShortBufferException)
(new ShortBufferException().initCause(e));
} else if (errorCode == CKR_DATA_LEN_RANGE ||
throw (IllegalBlockSizeException)
}
}
// see JCE spec
// XXX key wrapping
throw new UnsupportedOperationException("engineWrap()");
}
// see JCE spec
int wrappedKeyType)
throws InvalidKeyException, NoSuchAlgorithmException {
// XXX key unwrapping
throw new UnsupportedOperationException("engineUnwrap()");
}
// see JCE spec
int n = P11SecretKeyFactory.convertKey
return n;
}
padBufferLen += len;
bytesBuffered += len;
}
padBufferLen += len;
bytesBuffered += len;
}
}