4 Replies Latest reply: Apr 18, 2013 2:57 PM by safarmer RSS

    How to debug a java card applet??

    1001851
      I writing a java card applet to create a set of RSA keys and to copy it from one card to another card.
      the problem i face is that, i have 2 sets of oberthur java cards; one is Oberthur caospolIC64v5.2, the other is a newer version whose spec i dont know.
      Now when i try to copy from newer set of card i am unable to copy whereas i am able to do the same in older cards. kindly help.

      1. On what basis the newer card may vary from the older cards??
      2. where should i look into to know the about the problem above mentioned??

      Edited by: 998848 on Apr 8, 2013 9:15 PM
        • 1. Re: How to debug a java card applet??
          925183
          1. try to get information about card version by atr/ats
          2. you get the card diffrences from product sheets if you know the version through answer1
          3. javacard api is the same for every vendor, they just choose which functions to support
          4. you cannot copy from one card to another-> you need to copy from your host to every card
          5. post code
          • 2. Re: How to debug a java card applet??
            1001851
            I use netbeans for my debugiing environment.. could u suggest me some other debugging environment and steps to set up.

            Atr of the card that i use: *3b db 96 00 80 b1 fe 45 1f 83 00 31 c0 64 ba fc 10 00 01 90 00 09*
            package classicapplet3;
            
            import javacard.framework.*;
            import javacard.security.*;
            import javacardx.crypto.Cipher;
            
            /**
             *
             * @author SBritto
             */
            public class SignApplet1 extends Applet {
            
                //Constant definitions
                private static byte[] pubExp     = {(byte)0x00, (byte)0x01, (byte)0x00, (byte)0x01};
                 
                // CLA supported. 00 Alone is supported currently.
                final static byte CLA_ISO_00          = (byte) 0x00;
            
                //List of supported INS values.
                final static byte INS_READ_KEY          = (byte) 0xB2;  // Read Rec
                final static byte INS_WRITE_KEY          = (byte) 0xD2;  // Write Rec
                final static byte INS_GEN_KEY          = (byte) 0xD0;  // Read Bin
                
                // Security and Cryptography objects
                private static KeyPair               kp;
                private static RSAPrivateKey          privKey;
                private static RSAPublicKey               pubKey;
                private static Cipher               rsaCipher;
                private static DESKey               dupCardKey;
                private static Cipher               DESCipher;
            
                //Buffers required during different card operations
                private static byte[] buf;
                 private static byte[] shabuf;
                private static byte[] locFile;
                private static byte[] byTestArray;
                private static byte[] byEncArray;
                private static byte[] byDecArray;
            
                /**
                 * Installs this applet.
                 * 
                 * @param bArray
                 *            the array containing installation parameters
                 * @param bOffset
                 *            the starting offset in bArray
                 * @param bLength
                 *            the length in bytes of the parameter data in bArray
                 */
                public static void install(byte[] bArray, short bOffset, byte bLength) {
                    new SignApplet1();
                }
            
                /**
                 * Only this class's install method should create the applet object.
                 */
                protected SignApplet1() {
                    register();
                }
                
                private static void signInitialize()
                {
            
                    rsaCipher = Cipher.getInstance(Cipher.ALG_RSA_PKCS1, true);
                    privKey     = (RSAPrivateKey)KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_CRT_PRIVATE, KeyBuilder.LENGTH_RSA_2048, false);
                    pubKey     = (RSAPublicKey)KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PUBLIC, KeyBuilder.LENGTH_RSA_2048, false);
                    pubKey.setExponent(pubExp, (short)0, (short)4);
            
                    kp = new KeyPair(pubKey, privKey);
                    kp.genKeyPair();
            
                    privKey     = (RSAPrivateKey)kp.getPrivate();
                    pubKey     = (RSAPublicKey)kp.getPublic();
                }
            
                /**
                 * Processes an incoming APDU.
                 * 
                 * @see APDU
                 * @param apdu
                 *            the incoming APDU
                 */
                public void process(APDU apdu) {
                    //Insert your code here
                    byte[] buffer = apdu.getBuffer();
                    short option     = 0;
                    
                    if(this.selectingApplet())
                        return;
                    
                    if(buffer[ISO7816.OFFSET_CLA] != CLA_ISO_00)
                           ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
            
                    switch(buffer[ISO7816.OFFSET_INS])
                    {
                            case INS_READ_KEY:
                                    ReadKeyInfo(buffer,apdu);
                                    break;
            
                            case INS_WRITE_KEY:
                                    apdu.setIncomingAndReceive();
                                    WriteKeyInfo(buffer);
                                    break;
            
                            case INS_GEN_KEY:
                                    option = (short)(buffer[ISO7816.OFFSET_P1] & 0x00FF);
                                    switch (option) //P
                                    {
                                            case 0: // ValidateKey
                                                    ValidateKey(apdu);
                                                    break;
            
                                            case 1:// Validate the input and Generate Key
                                                    ValidateInputAndGenerateKey(buffer);
                                                    break;
            
                                            default:
                                                    ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
                                                    break;
                                    }
                                    break;
            
                            default:
                                    ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
                    }
                    ISOException.throwIt(ISO7816.SW_NO_ERROR);    
                }
                
                private void ValidateInputAndGenerateKey(byte[] buffer)
                {
            
                        // P2 should be FF and LC should be 0x07.
                        // Stringent checks are made to ensure the keys are not
                        // generated accidentally.
                        if(0xFF ==(buffer[ISO7816.OFFSET_P2] & 0x00FF) &&
                                0x07 ==(buffer[ISO7816.OFFSET_LC] & 0x00FF))
                        {
                                privKey = null;
                                pubKey  = null;
                                kp         = null;
                                signInitialize();
            
                        }
                        else
                        {
                                ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
                        }
                }
            
                private void ValidateKey(APDU apdu)
                {
                        short nSize, nLength;
            
                        Util.arrayFillNonAtomic(byTestArray, (short)0, (short)0x20, (byte)0x31);
                        nSize = rsaEncrypt(byTestArray, byEncArray, (short)0x20);
                        nSize = rsaDecrypt(byEncArray, byDecArray, nSize);
            
                        if(nSize != (short)0x20)
                        {
                                ISOException.throwIt(ISO7816.SW_DATA_INVALID);
                        }
                        else
                        {
                                if(Util.arrayCompare(byDecArray, (short)0, byTestArray, (short)0, (short)nSize) != 0)
                                {
                                        ISOException.throwIt(ISO7816.SW_DATA_INVALID);
                                }
                        }
                }
            
                private void ReadKeyInfo(byte[] buffer, APDU theApdu)
                {
                        short     option, P2;
                        short     shOutput = 0;
            
            
                        // Specifies what portion of the RSA public/private keys are to be retrieved.
                        option = (short)(buffer[ISO7816.OFFSET_P1] & 0x00FF);
            
                        // P2 specifies Whether to Encrypt the data.
                        // This option can be used for Public key exponent and modulus.
                        // The LOC info is always un encrypted. The Private keys are always encrypted.
                        P2 = (short)(buffer[ISO7816.OFFSET_P2] & 0x00FF);
            
                        Util.arrayFillNonAtomic(buf, (short)0, (short)0xFF, (byte)0);
            
                        switch(option)
                        {
                                // once a component of private key is read, it cannot be read again
                                case 0 ://PrivExp
                                        shOutput     = privKey.getExponent(buf, (short)0);
                                        break;
            
                                case 1 ://privMod
                                        shOutput     = privKey.getModulus(buf, (short)0);
                                        break;
            
                                case 2 ://PubExp
                                        shOutput     = pubKey.getExponent(buf, (short)0);
                                        break;
            
                                case 3 ://PubMod
                                        shOutput     = pubKey.getModulus(buf, (short)0);
                                        break;
            
                                case 4 ://LOCFile
                                        Util.arrayCopy(locFile, (short)0, buf, (short)0, (short)0x80);
                                        shOutput = (short)0x80;
                                        break;
            
                                default:
                                        ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
                        }
            
                        cmdREAD(buf, (short)0, (short)0, shOutput, theApdu);
                        
                }
            
                private void WriteKeyInfo(byte[] buffer)
                {
                    short     shSize = 0, option = 0;
            
                      option = (short)(buffer[ISO7816.OFFSET_P1] & 0x00FF);
                      shSize = (short)(buffer[ISO7816.OFFSET_LC] & 0xFF);
            
                      Util.arrayCopy(buffer, (short)((ISO7816.OFFSET_CDATA) & 0x00FF), shabuf, (short)(0), shSize);
            
                      if((0xFF == shSize))
                      {
                           // copy the last byte of the key
                           shabuf[0xFF] = buffer[ISO7816.OFFSET_P2];
                           shSize ++;
                      }
            
                      switch (option) //P1
                      {
                           case 0 ://PrivExp
                                
                                privKey = null;
                                pubKey     = null;
                                kp          = null;
            
                                privKey.setExponent(buf, (short)0, shSize);
                                break;
            
                           case 1 ://PrivMod               
                                privKey.setModulus(buf, (short)0, shSize);
                                break;
            
                           case 2 ://PubExp
                                pubKey.setExponent(buf, (short)0, (short)0x04);
                                break;
            
                           case 3 ://PubMod
                                pubKey.setModulus(buf, (short)0, (short)shSize);
                                break;
            
                           case 4 ://LOC File Information
                                Util.arrayCopy(shabuf, (short)0, locFile, (short)0, (short)0x80);
                                break;
            
                           default:
                                ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
                      }    
                }
                
                private void cmdREAD(byte[] byBuf, short Base, short Offset, short Size, APDU apdu)
                {
                        // set transmission to outgoing data
                        apdu.setOutgoing();
            
                        // set the number of bytes to send to the IFD
                        apdu.setOutgoingLength((short) Size);
            
                        // send the requested the number of bytes to the IFD
                        apdu.sendBytesLong(byBuf, (short)(Base + Offset), (short) Size);
                }
            
                private static short rsaDecrypt(byte[] byInput, byte[] byOutput, short nSize)
                {
                        short i = 0;
                        // decrypt
                        short decsize=0;
            
                        try
                        {
                            rsaCipher.init(pubKey, Cipher.MODE_DECRYPT);
                            decsize = rsaCipher.doFinal(byInput, (short)0, (short)nSize, byOutput, (short)0);
                        }
                        catch (CryptoException ce)
                        {
                                if(ce.getReason() == CryptoException.UNINITIALIZED_KEY)
                                {
                                        ISOException.throwIt((short)((short)0x9000+10));
                                }
                                else if(ce.getReason() == CryptoException.INVALID_INIT)
                                {
                                        ISOException.throwIt((short)((short)0x9000+11));
                                }
                                else if(ce.getReason() == CryptoException.ILLEGAL_USE)
                                {
                                        ISOException.throwIt((short)((short)0x9000+12));
                                }
                                else
                                {
                                        ISOException.throwIt((short)((short)0x9000+(short)ce.getReason()));
                                }
                        }
                        return decsize;
                }
            
                private static short rsaEncrypt(byte[] byInput, byte[] byOutput, short nSize)
                {
                        short i = 0;
                        short encsize=0;
            
                        try
                        {
                            // encrypt
                            rsaCipher.init(privKey, Cipher.MODE_ENCRYPT);
                            encsize = rsaCipher.doFinal(byInput, (short) 0, nSize, byOutput, (short)0);
                        }
                        catch (CryptoException ce)
                        {
                                if(ce.getReason() == CryptoException.UNINITIALIZED_KEY)
                                {
                                        ISOException.throwIt((short)((short)0x9000+0x20));
                                }
                                else if(ce.getReason() == CryptoException.INVALID_INIT)
                                {
                                        ISOException.throwIt((short)((short)0x9000+0x21));
                                }
                                else if(ce.getReason() == CryptoException.ILLEGAL_USE)
                                {
                                        ISOException.throwIt((short)((short)0x9000+0x22));
                                }
                                else
                                {
                                        ISOException.throwIt((short)((short)0x9000+0x23));
                                }
                        }
                        return encsize;
                }
                
            }
            Edited by: 998848 on Apr 11, 2013 1:41 AM

            Edited by: Martial on Apr 11, 2013 1:42 AM
            • 3. Re: How to debug a java card applet??
              925183
              for debugging you need a jc simulator+debug possibilites, Eclipse with JCOP tools plugin has such. apparantly its hard to get out there :/
              at which point do you fail?
              installation / gen keys?
              • 4. Re: How to debug a java card applet??
                safarmer
                Another option is to throw an ISO exception as this will set the SW. You can then see where your applet got to in the execution flow and can also give some contextual information. It may even be possible to send some data at this point as well. This is of course the last resort when you do not have a simulator or the issue only presents on real hardware that is not debugable.

                - Shane