/* * Copyright 2011 Licel LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.licel.jcardsim.crypto; import javacard.framework.JCSystem; import javacard.framework.Util; import javacard.security.CryptoException; import javacard.security.Key; import javacardx.crypto.Cipher; import org.bouncycastle.crypto.AsymmetricBlockCipher; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.encodings.PKCS1Encoding; import org.bouncycastle.crypto.engines.RSAEngine; import org.bouncycastle.crypto.paddings.BlockCipherPadding; /* * Implementation <code>Cipher</code> with asymmetric keys based * on BouncyCastle CryptoAPI. * @see Cipher */ public class AsymmetricCipherImpl extends Cipher { byte algorithm; AsymmetricBlockCipher engine; BlockCipherPadding paddingEngine; boolean isInitialized; byte[] buffer; short bufferPos; public AsymmetricCipherImpl(byte algorithm) { this.algorithm = algorithm; switch (algorithm) { case ALG_RSA_NOPAD: engine = new RSAEngine(); paddingEngine = null; break; case ALG_RSA_PKCS1: engine = new PKCS1Encoding(new RSAEngine()); paddingEngine = null; break; default: CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); break; } } public void init(Key theKey, byte theMode) throws CryptoException { if (theKey == null) { CryptoException.throwIt(CryptoException.UNINITIALIZED_KEY); } if (!theKey.isInitialized()) { CryptoException.throwIt(CryptoException.UNINITIALIZED_KEY); } if (!(theKey instanceof KeyWithParameters)) { CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } KeyWithParameters key = (KeyWithParameters) theKey; engine.init(theMode == MODE_ENCRYPT, key.getParameters()); buffer = JCSystem.makeTransientByteArray((short) engine.getInputBlockSize(), JCSystem.CLEAR_ON_DESELECT); bufferPos = 0; isInitialized = true; } public void init(Key theKey, byte theMode, byte[] bArray, short bOff, short bLen) throws CryptoException { CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } public byte getAlgorithm() { return algorithm; } public short doFinal(byte[] inBuff, short inOffset, short inLength, byte[] outBuff, short outOffset) throws CryptoException { if (!isInitialized) { CryptoException.throwIt(CryptoException.INVALID_INIT); } if ((outBuff.length - outOffset) < engine.getOutputBlockSize()) { CryptoException.throwIt(CryptoException.ILLEGAL_USE); } update(inBuff, inOffset, inLength, outBuff, outOffset); if (algorithm != ALG_RSA_PKCS1) { if ((bufferPos < engine.getInputBlockSize()) && (paddingEngine == null)) { CryptoException.throwIt(CryptoException.ILLEGAL_USE); } else if (bufferPos < engine.getInputBlockSize()) { paddingEngine.addPadding(buffer, bufferPos); } } try { byte[] data = engine.processBlock(buffer, (short) 0, bufferPos); Util.arrayCopyNonAtomic(data, (short) 0, outBuff, outOffset, (short) data.length); bufferPos = 0; return (short) data.length; } catch (InvalidCipherTextException ex) { CryptoException.throwIt(CryptoException.ILLEGAL_USE); } return -1; } public short update(byte[] inBuff, short inOffset, short inLength, byte[] outBuff, short outOffset) throws CryptoException { if (!isInitialized) { CryptoException.throwIt(CryptoException.INVALID_INIT); } if (inLength > (buffer.length - bufferPos)) { CryptoException.throwIt(CryptoException.ILLEGAL_USE); } bufferPos = (short) (bufferPos + Util.arrayCopyNonAtomic(inBuff, inOffset, buffer, bufferPos, inLength)); return bufferPos; } public byte getPaddingAlgorithm() { throw new UnsupportedOperationException("Not supported yet."); } public byte getCipherAlgorithm() { throw new UnsupportedOperationException("Not supported yet."); } }