Our Online Store have the new products: RFID antenna board. Currently it can work with JC10M24R and JCOP4 card chips.
Compared with normal cards, the antenna board module has a smaller size and fixed holes, which is easy to integrate in the IOT(Internet Of Things) project.

The ALgorithm of RSA Sample Code

Applets Development Guide

Moderator: product

User avatar
JavaCardOS
Posts: 273
Joined: Thu Apr 30, 2015 12:00 pm
Points :2403
Contact:

The ALgorithm of RSA Sample Code

Post by JavaCardOS » Sat Jul 09, 2016 6:01 am

The following code is the ALgorithm of RSA Sample Code in JavaCard API Specification.

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 .
You do not have the required permissions to view the files attached to this post. Please login first.

noabrw
Posts: 2
Joined: Wed Jan 03, 2018 5:31 am
Points :104
Contact:

Re: The ALgorithm of RSA Sample Code

Post by noabrw » Mon Jan 22, 2018 4:31 am

how can i run this code and install it in card?

User avatar
JavaCardOS
Posts: 273
Joined: Thu Apr 30, 2015 12:00 pm
Points :2403
Contact:

Re: The ALgorithm of RSA Sample Code

Post by JavaCardOS » Tue Jan 23, 2018 4:12 am

Hi,
You can use JCIDE to build this project and download the CAP file to java card.
You can refer to this forum:
viewforum.php?f=3

sdellava
Posts: 8
Joined: Sat Oct 20, 2018 9:17 am
Points :228
Contact:

Re: The ALgorithm of RSA Sample Code

Post by sdellava » Sat Dec 08, 2018 11:24 am

Good morning.

I'm trying to modify the RSA encrypt function using the private key instead of the public. Then I want to use the public to decrypt the message.

some suggestion?

tnx,

tay00000
Posts: 161
Joined: Tue Sep 27, 2016 10:58 am
Points :2324
Contact:

Re: The ALgorithm of RSA Sample Code

Post by tay00000 » Mon Dec 10, 2018 6:34 am

@sdellava,

I would recommend you to read about asymmetric cryptography and start from learning basic cryptography first and how they work.

Public keys are used to encrypt a message and not for decrypting messages. Private keys are the ones you must turn to for decrypting messages.

You will not be able to use the RSA Public Key to decrypt an enciphered message in the RSA encryption scheme and get back the original plaintext and if a proper padding is applied, it will be rejected by the padding scheme as well.

If you need help with development of a particular card application however, you can approach this online forum for help.

owlstead
Posts: 9
Joined: Sun Jan 27, 2019 10:57 am
Points :32
Contact:

Re: The ALgorithm of RSA Sample Code

Post by owlstead » Sun Jan 27, 2019 6:19 pm

sdellava wrote:
Sat Dec 08, 2018 11:24 am
I'm trying to modify the RSA encrypt function using the private key instead of the public. Then I want to use the public to decrypt the message.

some suggestion?
Yes. Don't.

There is no such thing as encrypting with a private key. Anybody has the public key, and if they don't then they can easily create it, especially if they already have the private key.

If you need a signature, then use a Signature instance.

If you really, really, really need to implement a signature using raw / textbook RSA then the RSA without padding is already mentioned in the otherwise horrible example.

Don't forget to implement your own secure signature padding scheme or you'll fail basic security requirements. Any padding used for RSA encryption is not valid for signature generation.

Good luck; you'll need it.

mbsysde99
Posts: 40
Joined: Tue Oct 24, 2017 1:10 pm
Points :480
Contact:

Re: The ALgorithm of RSA Sample Code

Post by mbsysde99 » Wed Feb 09, 2022 7:22 pm

sdellava wrote:
Sat Dec 08, 2018 11:24 am
Good morning.

I'm trying to modify the RSA encrypt function using the private key instead of the public. Then I want to use the public to decrypt the message.

some suggestion?

tnx,
The proccess RSA as encrypt/decrypt as follows:

1. Create RSA instance and Generate KeyPair (Pubic Key and Private Key) in your Applet (Java Card).
2. Send only Public Key to your Host (Reader), maybe use C++ or C# app in your host.
3. In your Host, Import that that Public Key to your RSA instance, and use that to Encrypt your Plain Text, then send to your Java Card as Cipher Text.
4. In Java Card, use Private Key to decrypt that Cipher Text to get Plain Text.

Note:
Plain Text = Original text
Cipher Text = Encrypted text

Encrypt = Change plain text to cipher Text
Decrypt = Change cipher text to plain text

Public key = To encrypt plain text and result is cipher text
Private key = To decrypt cipher text and result is plain text

Post Reply Previous topicNext topic

Who is online

Users browsing this forum: No registered users and 4 guests

JavaCard OS : Disclaimer