You can copy and use it directly or you can download the JCIDE project from the attachment and build it.
Code: Select all
/*
 * @file  RSASample.java
 * @version v1.0
 * Package AID: 4A617661436172644F53 
 * Applet AID:  4A617661436172644F5303
 * @brief The ALgorithm of RSA Sample Code in JavaCard API Specification
 * @comment The purpose of this example is only used to show the usage of API functions and there is no practical significance.
 * @copyright Copyright(C) 2016 JavaCardOS Technologies Co., Ltd. All rights reserved.
 */
 
package JavaCardOS.Sample.Algorithm;
import javacard.framework.*;
import javacard.security.KeyBuilder;
import javacard.security.*;
import javacardx.crypto.*;
public class RSASample extends Applet
{
   private static final byte INS_GEN_RSA_KEYPAIR          = (byte)0x30;
    private static final byte INS_GET_RSA_PUBKEY           = (byte)0x31;
    private static final byte INS_GET_RSA_PRIKEY           = (byte)0x32;
    private static final byte INS_SET_RSA_PUBKEY           = (byte)0x33;
    private static final byte INS_SET_RSA_PRIKEY           = (byte)0x34;
    private static final byte INS_RSA_SIGN                 = (byte)0x35;
    private static final byte INS_RSA_VERIFY               = (byte)0x36;
    private static final byte INS_DO_RSA_CIPHER            = (byte)0x37;
   private byte[] tempBuffer;
    private byte[] flags;
    private static final short OFF_INS    = (short)0;
    private static final short OFF_P1     = (short)1;
    private static final short OFF_P2     = (short)2;
    private static final short OFF_LEN    = (short)3;
    private static final short FLAGS_SIZE = (short)5;
   private static final byte ID_N   = 0;
    private static final byte ID_D   = 1;
    private static final byte ID_P   = 2;
    private static final byte ID_Q   = 3;
    private static final byte ID_PQ  = 4;
    private static final byte ID_DP1 = 5;
    private static final byte ID_DQ1 = 6;
    
   private byte[] rsaPubKey;
    private short rsaPubKeyLen;
    private byte[] rsaPriKey;
    private short rsaPriKeyLen;
    private boolean isRSAPriKeyCRT;
    private Cipher rsaCipher;    
    private Signature rsaSignature;
    
   private static final short SW_REFERENCE_DATA_NOT_FOUND = (short)0x6A88;
   
   public RSASample()
    {
       //Create a transient byte array to store the temporary data
        tempBuffer = JCSystem.makeTransientByteArray((short)256, JCSystem.CLEAR_ON_DESELECT);
        flags = JCSystem.makeTransientByteArray(FLAGS_SIZE, JCSystem.CLEAR_ON_DESELECT);
        rsaPubKey = new byte[(short)   (256 + 32)];
        rsaPriKey = new byte[(short)(128 * 5)];
        rsaPubKeyLen = 0;
        rsaPriKeyLen = 0;
        isRSAPriKeyCRT = false;
        rsaSignature = null;
        //Create a RSA(not pad) object instance
        rsaCipher = Cipher.getInstance(Cipher.ALG_RSA_NOPAD, false);
        JCSystem.requestObjectDeletion();
    }
    
   public static void install(byte[] bArray, short bOffset, byte bLength) 
   {
      new RSASample().register(bArray, (short) (bOffset + 1), bArray[bOffset]);
   }
   public void process(APDU apdu)
   {
      if (selectingApplet())
      {
         return;
      }
      byte[] buf = apdu.getBuffer();
      short len = apdu.setIncomingAndReceive();
      switch (buf[ISO7816.OFFSET_INS])
      {
      case INS_GEN_RSA_KEYPAIR:
           //GEN_RSA_KEYPAIR
           genRsaKeyPair(apdu, len);
            break;
        case INS_GET_RSA_PUBKEY:
           //GET_RSA_PUBKEY
            getRsaPubKey(apdu, len);
            break;
        case INS_GET_RSA_PRIKEY:
           //GET_RSA_PRIKEY
           getRsaPriKey(apdu, len);
            break;
        case INS_SET_RSA_PUBKEY:
           // SET_RSA_PUBKEY
            setRsaPubKey(apdu, len);
            break;
        case INS_SET_RSA_PRIKEY:
           //SET_RSA_PRIKEY
            setRsaPriKey(apdu, len);
            break;
        case INS_RSA_SIGN:
           //RSA_SIGN
            rsaSign(apdu, len);
            break;
        case INS_RSA_VERIFY:
           //RSA_VERIFY
            rsaVerify(apdu, len);
            break;
        case INS_DO_RSA_CIPHER:   
           //RSA_CIPHER
           doRSACipher(apdu, len);
           break;
      default:
         ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
      }
   }
   
   //RSA algorithm encrypt and decrypt
   private void doRSACipher(APDU apdu, short len)
    {
       byte[] buffer = apdu.getBuffer();
        byte p1Tmp = buffer[ISO7816.OFFSET_P1];
        boolean hasMoreCmd = (p1Tmp & 0x80) != 0;
        boolean isEncrypt = (p1Tmp & 0x01) != 1;
       short keyLen = (p1Tmp & 0x08) == (byte)0x00 ? KeyBuilder.LENGTH_RSA_1024 : KeyBuilder.LENGTH_RSA_2048;
       short offset = (p1Tmp & 0x08) == (byte)0x00 ? (short)128 : (short)256;
       
        if (len <= 0)
        {
            ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
        }
        //RSA encrypt, Public Key will be used
        if (isEncrypt)
      {
         //Create uninitialized public key for signature and cipher algorithms.
         RSAPublicKey pubKey = (RSAPublicKey)KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PUBLIC, keyLen, false);
         pubKey.setModulus(rsaPubKey, (short)0, offset);
         pubKey.setExponent(rsaPubKey, offset, (short)3);
         if (buffer[ISO7816.OFFSET_P2] == 0x00)
         {
            //In multiple-part encryption/decryption operations, only the fist APDU command will be used.
            rsaCipher.init(pubKey, Cipher.MODE_ENCRYPT); 
         }
         
         if (hasMoreCmd)
         {
            //This method is intended for multiple-part encryption/decryption operations.
            rsaCipher.update(buffer, ISO7816.OFFSET_CDATA, len, tempBuffer, (short)0);
         }
         else
         {
            //Generates encrypted output from all input data.
            short outlen = rsaCipher.doFinal(buffer, ISO7816.OFFSET_CDATA, len, buffer, (short)0);
            apdu.setOutgoingAndSend((short)0, outlen);   
         }
      }
      else//RSA decrypt, Private Key will be used
      {
         if (!isRSAPriKeyCRT)
            {
               //RSA Alogrithm, create uninitialized private key for decypt
               RSAPrivateKey priKey = (RSAPrivateKey)KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PRIVATE, keyLen, false);
               //Set the modulus value of the key.
            priKey.setModulus(rsaPriKey, (short)0, offset);
            //Sets the private exponent value of the key
            priKey.setExponent(rsaPriKey, offset, offset);
            if (buffer[ISO7816.OFFSET_P2] == 0x00)
            {
               //In multiple-part encryption/decryption operations, only the fist APDU command will be used.
               rsaCipher.init(priKey, Cipher.MODE_DECRYPT);
            }
            if (hasMoreCmd)
            {
               //This method is intended for multiple-part encryption/decryption operations.
               rsaCipher.update(buffer, ISO7816.OFFSET_CDATA, len, tempBuffer, (short)0);
            }
            else
            {
               short outlen = rsaCipher.doFinal(buffer, ISO7816.OFFSET_CDATA, len, buffer, (short)0);
               apdu.setOutgoingAndSend((short)0, outlen);   
            }
            }
            else 
            {
               //RSA CRT Algorithm, need to create uninitialized private key and set the value of some parameters, such as P Q PQ DP DQ.执行解密运算前,设置私钥
               RSAPrivateCrtKey priCrtKey = (RSAPrivateCrtKey)KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_CRT_PRIVATE, keyLen, false);
                priCrtKey.setP(rsaPriKey, (short)0, (short)(offset / 2));
                priCrtKey.setQ(rsaPriKey, (short)(offset / 2), (short)(offset / 2));
                priCrtKey.setPQ(rsaPriKey, (short)offset, (short)(offset / 2));
                priCrtKey.setDP1(rsaPriKey, (short)(offset + offset / 2), (short)(offset / 2));
                priCrtKey.setDQ1(rsaPriKey, (short)(offset * 2), (short)(offset / 2));
                
                if (buffer[ISO7816.OFFSET_P2] == 0x00)
            {
               //Initializes the Cipher object with the appropriate Key. 
               //In multiple-part encryption/decryption operations, only the fist APDU command will be used.
               rsaCipher.init(priCrtKey, Cipher.MODE_DECRYPT);
            }
            if (hasMoreCmd)
            {
               //This method is intended for multiple-part encryption/decryption operations.
               rsaCipher.update(buffer, ISO7816.OFFSET_CDATA, len, tempBuffer, (short)0);
            }
            else
            {
               //Generates decrypted output from all input data.
               short outlen = rsaCipher.doFinal(buffer, ISO7816.OFFSET_CDATA, len, buffer, (short)0);
               apdu.setOutgoingAndSend((short)0, outlen);   
            }
            }
      }        
    }
    
    //Get the value of RSA Public Key from the global variable 'rsaPubKey' 
    private void getRsaPubKey(APDU apdu, short len)
    {
        byte[] buffer = apdu.getBuffer();
        if (rsaPubKeyLen == 0)
        {
            ISOException.throwIt(SW_REFERENCE_DATA_NOT_FOUND);
        }
        short modLen = rsaPubKeyLen <= (128 + 32) ? (short)128 : (short)256;
        switch (buffer[ISO7816.OFFSET_P1])
        {
        case 0:
            Util.arrayCopyNonAtomic(rsaPubKey,(short)0,buffer,(short)0,modLen);
            apdu.setOutgoingAndSend((short)0,modLen);
            break;
        case 1:
            //get public key E
            short eLen = (short)(rsaPubKeyLen - modLen);
            Util.arrayCopyNonAtomic(rsaPubKey,modLen,buffer,(short)0,eLen);
            apdu.setOutgoingAndSend((short)0,eLen);
            break;
        default:
            ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
            break;
        }
    }
   //According to the different ID, returns the value/length of RSA Private component
    private short getRsaPriKeyComponent(byte id, byte[] outBuff, short outOff)
    {
        if (rsaPriKeyLen == 0)
        {
            return (short)0;
        }
        short modLen;
        if (isRSAPriKeyCRT)
        {
            if (rsaPriKeyLen == 64 * 5)
            {
                modLen = (short)128;
            }
            else
            {
                modLen = (short)256;
            }
        }
        else
        {
            if (rsaPriKeyLen == 128 * 2)
            {
                modLen = (short)128;
            }
            else
            {
                modLen = (short)256;
            }
        }
        short readOff;
        short readLen;
        switch (id)
        {
        case ID_N:
            //RSA private key N
            if (isRSAPriKeyCRT)
            {
                return (short)0;
            }
            readOff = (short)0;
            readLen = modLen;
            break;
        case ID_D:
            if (isRSAPriKeyCRT)
            {
                return (short)0;
            }
            //RSA private key D
            readOff = modLen;
            readLen = modLen;
            break;
        case ID_P:
            if (!isRSAPriKeyCRT)
            {
                return (short)0;
            }
            readOff = (short)0;
            readLen = (short)(modLen / 2);
            break;
        case ID_Q:
            if (!isRSAPriKeyCRT)
            {
                return (short)0;
            }
            readOff = (short)(modLen / 2);
            readLen = (short)(modLen / 2);
            break;
        case ID_PQ:
            if (!isRSAPriKeyCRT)
            {
                return (short)0;
            }
            readOff = (short)(modLen);
            readLen = (short)(modLen / 2);
            break;
        case ID_DP1:
            if (!isRSAPriKeyCRT)
            {
                return (short)0;
            }
            readOff = (short)(modLen / 2 * 3);
            readLen = (short)(modLen / 2);
            break;
        case ID_DQ1:
            if (!isRSAPriKeyCRT)
            {
                return (short)0;
            }
            readOff = (short)(modLen * 2);
            readLen = (short)(modLen / 2);
            break;
        default:
            return 0;
        }
        Util.arrayCopyNonAtomic(rsaPriKey, readOff, outBuff, outOff, readLen);
        return readLen;
    }
   //Get the value of RSA Private Key
    private void getRsaPriKey(APDU apdu, short len)
    {
        byte[] buffer = apdu.getBuffer();
        if ((buffer[ISO7816.OFFSET_P1] & 0xff) > 6)
        {
            ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
        }
        short ret = getRsaPriKeyComponent(buffer[ISO7816.OFFSET_P1], buffer, (short)0);
        if (ret == 0)
        {
            ISOException.throwIt(SW_REFERENCE_DATA_NOT_FOUND);
        }
        apdu.setOutgoingAndSend((short)0, ret);
    }
   //Set the value of RSA public key
    private void setRsaPubKey(APDU apdu, short len)
    {
        byte[] buffer = apdu.getBuffer();
        if (buffer[ISO7816.OFFSET_P2] == 0) // first block
        {
            rsaPubKeyLen = (short)0;
            Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_INS, flags, OFF_INS, (short)3);
            Util.setShort(flags, OFF_LEN, (short)0);
        }
        else
        {
            if (flags[OFF_INS] != buffer[ISO7816.OFFSET_INS]
                    || (flags[OFF_P1] & 0x7f) != (buffer[ISO7816.OFFSET_P1] & 0x7f)
                    || (short)(flags[OFF_P2] & 0xff) != (short)((buffer[ISO7816.OFFSET_P2] & 0xff) - 1))
            {
                Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0);
                ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
            }
            flags[OFF_P2] ++;
        }
        short loadedLen = Util.getShort(flags, OFF_LEN);
        if (loadedLen + len > rsaPubKey.length)
        {
            Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0);
            ISOException.throwIt(ISO7816.SW_WRONG_DATA);
        }
      //Copy the value of RSA public key  to the global variable 'rsaPubKey'. 
        Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, rsaPubKey, loadedLen, len);
        loadedLen += len;
        if ((buffer[ISO7816.OFFSET_P1] & 0x80) == 0) //last block
        {
            Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0);
            short modLen = (buffer[ISO7816.OFFSET_P1] & 0x01) == 0 ? (short)128 : (short)256;
            if (loadedLen < modLen + 3 || loadedLen > modLen + 32)
            {
                ISOException.throwIt(ISO7816.SW_WRONG_DATA);
            }
            rsaPubKeyLen = loadedLen;
        }
        else
        {
            Util.setShort(flags, OFF_LEN, loadedLen);
        }
    }
   //Set the value of RSA private key
    private void setRsaPriKey(APDU apdu, short len)
    {
        byte[] buffer = apdu.getBuffer();
        if (buffer[ISO7816.OFFSET_P2] == 0) // first block
        {
            rsaPriKeyLen = (short)0;
            Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_INS, flags, OFF_INS, (short)3);
            Util.setShort(flags, OFF_LEN, (short)0);
        }
        else
        {
            if (flags[OFF_INS] != buffer[ISO7816.OFFSET_INS]
                    || (flags[OFF_P1] & 0x7f) != (buffer[ISO7816.OFFSET_P1] & 0x7f)
                    || (short)(flags[OFF_P2] & 0xff) != (short)((buffer[ISO7816.OFFSET_P2] & 0xff) - 1))
            {
                Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0);
                ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
            }
            flags[OFF_P2] ++;
        }
        short loadedLen = Util.getShort(flags, OFF_LEN);
        if (loadedLen + len > rsaPriKey.length)
        {
            Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0);
            ISOException.throwIt(ISO7816.SW_WRONG_DATA);
        }
      //Copy the value of RSA private key  to the global variable 'rsaPriKey'.
      Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, rsaPriKey, loadedLen, len);
        loadedLen += len;
        if ((buffer[ISO7816.OFFSET_P1] & 0x80) == 0) //last block
        {
            Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0);
            short modLen = (buffer[ISO7816.OFFSET_P1] & 0x01) == 0 ? (short)128 : (short)256;
            boolean isCRT = (buffer[ISO7816.OFFSET_P1] & 0x40) != 0;
            if ((isCRT && (loadedLen != modLen / 2 * 5)) || (!isCRT && (loadedLen != modLen * 2)))
            {
                ISOException.throwIt(ISO7816.SW_WRONG_DATA);
            }
            isRSAPriKeyCRT = isCRT;
            rsaPriKeyLen = loadedLen;
        }
        else
        {
            Util.setShort(flags, OFF_LEN, loadedLen);
        }
    }
    //
   private void genRsaKeyPair(APDU apdu, short len)
    {
        byte[] buffer = apdu.getBuffer();
        short keyLen = buffer[ISO7816.OFFSET_P1] == 0 ? (short)1024 : (short)2048;
        byte alg = buffer[ISO7816.OFFSET_P2] == 0 ? KeyPair.ALG_RSA : KeyPair.ALG_RSA_CRT;
        KeyPair keyPair = new KeyPair(alg, keyLen);
        if (len > 32)
        {
            ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
        }
        if (len > 0)
        {
            ((RSAPublicKey)keyPair.getPublic()).setExponent(buffer, ISO7816.OFFSET_CDATA, len);
        }
        //(Re)Initializes the key objects encapsulated in this KeyPair instance with new key values.
        keyPair.genKeyPair();
        JCSystem.beginTransaction();
        rsaPubKeyLen = 0;
        rsaPriKeyLen = 0;
        JCSystem.commitTransaction();
        //Get a reference to the public key component of this 'keyPair' object.
        RSAPublicKey pubKey = (RSAPublicKey)keyPair.getPublic();
        short pubKeyLen = 0;
        //Store the RSA public key value in the global variable 'rsaPubKey', the public key contains modulo N and Exponent E
        pubKeyLen += pubKey.getModulus(rsaPubKey, pubKeyLen);
        pubKeyLen += pubKey.getExponent(rsaPubKey, pubKeyLen);
        short priKeyLen = 0;
        if (alg == KeyPair.ALG_RSA)
        {
           isRSAPriKeyCRT = false;
           //Returns a reference to the private key component of this KeyPair object.
            RSAPrivateKey priKey = (RSAPrivateKey)keyPair.getPrivate();
            //RSA Algorithm,  the Private Key contains N and D, and store these parameters value in global variable 'rsaPriKey'.
            priKeyLen += priKey.getModulus(rsaPriKey, priKeyLen);
            priKeyLen += priKey.getExponent(rsaPriKey, priKeyLen);
        }
        else //RSA CRT
        {
           isRSAPriKeyCRT =  true;
           //The RSAPrivateCrtKey interface is used to sign data using the RSA algorithm in its Chinese Remainder Theorem form.
            RSAPrivateCrtKey priKey = (RSAPrivateCrtKey)keyPair.getPrivate();
            //RSA CRT Algorithm,  the Private Key contains P Q PQ DP and DQ, and store these parameters value in global variable 'rsaPriKey'.
            priKeyLen += priKey.getP(rsaPriKey, priKeyLen);
            priKeyLen += priKey.getQ(rsaPriKey, priKeyLen);
            priKeyLen += priKey.getPQ(rsaPriKey, priKeyLen);
            priKeyLen += priKey.getDP1(rsaPriKey, priKeyLen);
            priKeyLen += priKey.getDQ1(rsaPriKey, priKeyLen);
        }
        JCSystem.beginTransaction();
        rsaPubKeyLen = pubKeyLen;
        rsaPriKeyLen = priKeyLen;
        JCSystem.commitTransaction();
        JCSystem.requestObjectDeletion();
    }
   //RSA Signature
    private void rsaSign(APDU apdu, short len)
    {
        byte[] buffer = apdu.getBuffer();
        if (rsaPriKeyLen == 0)
        {
            ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
        }
        boolean hasMoreCmd = (buffer[ISO7816.OFFSET_P1] & 0x80) != 0;
        short resultLen = 0;
        if (buffer[ISO7816.OFFSET_P2] == 0) //first block
        {
            Key key;
            if (!isRSAPriKeyCRT)
            {
                short ret;
                //Creates uninitialized private keys for signature algorithms.
                key = KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PRIVATE, (short)(rsaPriKeyLen / 2 * 8), false);
                ret = getRsaPriKeyComponent(ID_N, tempBuffer, (short)0);
                ((RSAPrivateKey)key).setModulus(tempBuffer, (short)0, ret);
                ret = getRsaPriKeyComponent(ID_D, tempBuffer, (short)0);
                ((RSAPrivateKey)key).setExponent(tempBuffer, (short)0, ret);
            }
            else
            {
                short ret;
                //Creates uninitialized private keys for signature algorithms.
                key = KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_CRT_PRIVATE, (short)(rsaPriKeyLen / 5 * 16), false);
                ret = getRsaPriKeyComponent(ID_P, tempBuffer, (short)0);
                ((RSAPrivateCrtKey)key).setP(tempBuffer, (short)0, ret);
                ret = getRsaPriKeyComponent(ID_Q, tempBuffer, (short)0);
                ((RSAPrivateCrtKey)key).setQ(tempBuffer, (short)0, ret);
                ret = getRsaPriKeyComponent(ID_DP1, tempBuffer, (short)0);
                ((RSAPrivateCrtKey)key).setDP1(tempBuffer, (short)0, ret);
                ret = getRsaPriKeyComponent(ID_DQ1, tempBuffer, (short)0);
                ((RSAPrivateCrtKey)key).setDQ1(tempBuffer, (short)0, ret);
                ret = getRsaPriKeyComponent(ID_PQ, tempBuffer, (short)0);
                ((RSAPrivateCrtKey)key).setPQ(tempBuffer, (short)0, ret);
            }
         // Creates a Signature object instance of the ALG_RSA_SHA_PKCS1 algorithm.
            rsaSignature = Signature.getInstance(Signature.ALG_RSA_SHA_PKCS1, false);
            JCSystem.requestObjectDeletion();
         //Initializ the Signature object.
            rsaSignature.init(key, Signature.MODE_SIGN);
            Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_INS, flags, OFF_INS, (short)3);
            JCSystem.requestObjectDeletion();
        }
        else
        {
            if (flags[OFF_INS] != buffer[ISO7816.OFFSET_INS]
                    || (flags[OFF_P1] & 0x7f) != (buffer[ISO7816.OFFSET_P1] & 0x7f)
                    || (short)(flags[OFF_P2] & 0xff) != (short)((buffer[ISO7816.OFFSET_P2] & 0xff) - 1))
            {
                Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0);
                ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
            }
            flags[OFF_P2] ++;
        }
        if (hasMoreCmd)
        {
           // Accumulates a signature of the input data. 
            rsaSignature.update(buffer, ISO7816.OFFSET_CDATA, len);
        }
        else
        {
           //Generates the signature of all input data.
            short ret = rsaSignature.sign(buffer, ISO7816.OFFSET_CDATA, len, buffer, (short)0);
            Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0);
            apdu.setOutgoingAndSend((short)0, ret);
        }
    }
    //RSA Signature and Verify
    private void rsaVerify(APDU apdu, short len)
    {
        byte[] buffer = apdu.getBuffer();
        if (rsaPubKeyLen == 0)
        {
            ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
        }
        boolean hasMoreCmd = (buffer[ISO7816.OFFSET_P1] & 0x80) != 0;
        short resultLen = 0;
        short offset = ISO7816.OFFSET_CDATA;
        short modLen = rsaPubKeyLen > 256 ? (short)256 : (short)128;
        if (buffer[ISO7816.OFFSET_P2] == 0) //first block
        {
            Key key;
            // Create uninitialized public keys for signature  algorithms.
            key = KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PUBLIC, (short)(modLen * 8), false);
            //Sets the modulus value of the key. 
            ((RSAPublicKey)key).setModulus(rsaPubKey, (short)0, modLen);
            //Sets the public exponent value of the key.
            ((RSAPublicKey)key).setExponent(rsaPubKey, modLen, (short)(rsaPubKeyLen - modLen));
         //Create a ALG_RSA_SHA_PKCS1 object instance.
            rsaSignature = Signature.getInstance(Signature.ALG_RSA_SHA_PKCS1, false);
            JCSystem.requestObjectDeletion();
            //Initializes the Signature object with the appropriate Key. 
            rsaSignature.init(key, Signature.MODE_VERIFY);
            Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_INS, flags, OFF_INS, (short)3);
            Util.setShort(flags, OFF_LEN, (short)0);
            JCSystem.requestObjectDeletion();
        }
        else
        {
            if (flags[OFF_INS] != buffer[ISO7816.OFFSET_INS]
                    || (flags[OFF_P1] & 0x7f) != (buffer[ISO7816.OFFSET_P1] & 0x7f)
                    || (short)(flags[OFF_P2] & 0xff) != (short)((buffer[ISO7816.OFFSET_P2] & 0xff) - 1))
            {
                Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0);
                ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
            }
            flags[OFF_P2] ++;
        }
        short sigLen = Util.getShort(flags, OFF_LEN);
        if (sigLen < modLen)
        {
            short readLen = (short)(modLen - sigLen);
            if (readLen > len)
            {
                readLen = len;
            }
            Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, tempBuffer, sigLen, readLen);
            sigLen += readLen;
            len -= readLen;
            Util.setShort(flags, OFF_LEN, sigLen);
            offset += readLen;
        }
        if (hasMoreCmd)
        {
            if (len > 0)
            {
               //Accumulates a signature of the input data. 
                rsaSignature.update(buffer, offset, len);
            }
        }
        else
        {
            if (sigLen != modLen)
            {
                Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0);
                ISOException.throwIt(ISO7816.SW_WRONG_DATA);
            }
            //Verify the signature of all/last input data against the passed in signature.
            boolean ret = rsaSignature.verify(buffer, offset, len, tempBuffer, (short)0, sigLen);
            Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0);
            buffer[(short)0] = ret ? (byte)1 : (byte)0;
            apdu.setOutgoingAndSend((short)0, (short)1);
        }
    }
    
}
Note:
The purpose of this example is only used to show the usage of RSA algorithm .


