1 2 3 4 Previous Next 57 Replies Latest reply: Feb 13, 2011 5:55 AM by Sebastien_Lorquet RSS

    RSA implementation basics ...

    843851
      Hi,

      Iam totally new to the Java Card programming. I want to find out how is RSA implemented. Now if I need to get some information from card (eg. serial number) and check the same. How do I implement the same using the Host and Smart Card.
      Any light on the same would be appreciated. Also, if anyone has example of implementation of RSA between Host and Smart card would be appreciated (in Delphi and Java) ...

      Thanks
        • 1. Re: RSA implementation basics ...
          safarmer
          Hi,

          To help answer this question, what do you already know about RSA?

          Cheers,
          Shane
          • 2. Re: RSA implementation basics ...
            843851
            Shane,

            I have been able to download a sample program for encrypting and decrypting. The code is in Java and implemented as Applet (within the card). I understood a little bit on the same, considering iam new to java programming.
            I need to write a program that will encrypt a string on the client side, send the same to the card, decrypt it in the card.

            Am i making sense here?

            narsee
            • 3. Re: RSA implementation basics ...
              843851
              Hi,

              I have written a code based on a sample. The program has a client which accepts a string at frontend and sends the information to be encrypted at card, then writes the encrypted information to the card. To decrypt the same, there is an option at the frontend to read the string from card, so the program, gets the string from the card (in encrypted form), then sends the string to card decrypt the same. Iam getting an Techincal error (error 38) while decrypting. Can you please help? I need a solution immediately. I been trying to work on the same for last few days.

              I have pasted the code below for reference. Appreciate if some one could respond quickly.

              package rsa_encrypt_decrypt;

              import javacard.framework.*;
              import javacard.security.*;
              import javacardx.crypto.Cipher;

              Host Call:
              --------------
              iopCard.SendCardAPDU(0x00,0xAA,0x02,P2,iArray,iArray.length);

              Card Applet:
              ------------------
              public class RSAEncryptDecrypt extends javacard.framework.Applet
              {

                   // This applet is designed to respond to the following
                   // class of instructions.

                   final static byte GETSET_CLA = (byte) 0x85;

                   final static byte CRYPT_CLA = (byte) 0x00;

                   // Instruction set for SimpleString

                   final static byte SET = (byte)0x10;
                   final static byte GET = (byte)0x20;
                   final static byte SELECT = (byte) 0xA4;

              // This buffer contains the string data on the card
                   byte TheBuffer[];     

                   //globals
                   RSAPrivateCrtKey rsa_PrivateCrtKey;
                   RSAPublicKey rsa_PublicKey;
                   KeyPair rsa_KeyPair;
                   Cipher cipherRSA;
                   final short dataOffset = (short) ISO7816.OFFSET_CDATA;
                   
                   //constructor
                   private HandsonRSAEncryptDecrypt(byte bArray[], short bOffset, byte bLength)
                   {

                   TheBuffer = new byte[100];

                   //generate own rsa_keypair
              rsa_KeyPair = new KeyPair( KeyPair.ALG_RSA_CRT, KeyBuilder.LENGTH_RSA_1024 );
              rsa_KeyPair.genKeyPair();
                        rsa_PublicKey = (RSAPublicKey) rsa_KeyPair.getPublic();
                        rsa_PrivateCrtKey = (RSAPrivateCrtKey) rsa_KeyPair.getPrivate();
                        cipherRSA = Cipher.getInstance(Cipher.ALG_RSA_PKCS1, false);
                        register(bArray, (short) (bOffset + 1), bArray[bOffset]);
                   }

                   //install
                   public static void install(byte bArray[], short bOffset, byte bLength)
                   {
                        new HandsonRSAEncryptDecrypt(bArray, bOffset, bLength);
                   }


                   public void process(APDU apdu)
                   {


                        if (selectingApplet())
                        {
                             return;
                        }

                        byte[] buf = apdu.getBuffer();

                        byte cla = buf[ISO7816.OFFSET_CLA];

                        byte ins = buf[ISO7816.OFFSET_INS];

                        if ((buf[ISO7816.OFFSET_CLA] != 0) && (buf[ISO7816.OFFSET_CLA] != GETSET_CLA)) ISOException.throwIt (ISO7816.SW_CLA_NOT_SUPPORTED);

                        if ((buf[ISO7816.OFFSET_INS] != (byte) (0xAA)) && (buf[ISO7816.OFFSET_INS] != (byte) (0x10)) && (buf[ISO7816.OFFSET_INS] != (byte) (0x20))) ISOException.throwIt (ISO7816.SW_INS_NOT_SUPPORTED);



                        switch (cla)
                        {
                             case GETSET_CLA:
                                  switch (ins)
                                  {
                                       case SET:
                                            SetString(apdu);
                                            break;
                                       case GET:
                                            GetString(apdu);
                                            break;
                                  }
                             case CRYPT_CLA:
                                  switch (buf[ISO7816.OFFSET_P1])
                                  {
                                       case (byte) 0x01:
                                            encryptRSA(apdu);
                                            return;
                                       case (byte) 0x02:
                                            decryptRSA(apdu);
                                            return;
                                  }

                        }
                   }
                   

                   private void encryptRSA(APDU apdu)
                   {
                        byte a[] = apdu.getBuffer();
                        short byteRead = (short) (apdu.setIncomingAndReceive());
                        cipherRSA.init(rsa_PrivateCrtKey, Cipher.MODE_ENCRYPT);
                        short cyphertext = cipherRSA.doFinal(a, (short) dataOffset, byteRead, a, (short) dataOffset);

                        // Send results
                        apdu.setOutgoing();
                        apdu.setOutgoingLength((short) cyphertext);
                        apdu.sendBytesLong(a, (short) dataOffset, (short) cyphertext);
                        //SetString(apdu);

                   }
                   
                   private void decryptRSA(APDU apdu)
                   {
                        byte a[] = apdu.getBuffer();
                   
                        short byteRead = (short) (apdu.setIncomingAndReceive());
                        cipherRSA.init(rsa_PublicKey, Cipher.MODE_DECRYPT);
                        cipherRSA.doFinal(a, (short) dataOffset, byteRead, a, (short) dataOffset);

                        // Send results
                        apdu.setOutgoing();
                        apdu.setOutgoingLength((short) 24);
                        apdu.sendBytesLong(a, (short) dataOffset, (short) 24);

                   }

                   // SetString stores the string on the card.

                   private void SetString(APDU apdu) {

                        byte buffer[] = apdu.getBuffer();

                        byte size = (byte)(apdu.setIncomingAndReceive());

                        byte index;

                        // Store the length of the string and the string itself

                        TheBuffer[0] = size;

                        for (index = 0; index < size; index++)
                             TheBuffer[(byte)(index + 1)] = buffer[(byte)(ISO7816.OFFSET_CDATA + index)];

                        return;

                   }

                   //     1. Client sends a GetString APDU with a length of 0
                   //     2. Card responds with a Status Word of 0x62YY, where YY is the length
                   //          of the string (in hex).
                   //     3. The client sends its GetString APDU again, but this time with the
                   //          correct length.
                   //

                   private void GetString(APDU apdu) {

                        byte buffer[] = apdu.getBuffer();

                        byte numBytes = buffer[ISO7816.OFFSET_LC];


                        if (numBytes == (byte)0) {
                             ISOException.throwIt((short)(0x6200 + TheBuffer[0]));
                        }

                        apdu.setOutgoing();
                        apdu.setOutgoingLength(numBytes);
                        

                        byte index;

                        for (index = 0; index <= numBytes; index++)
                             buffer[index] = TheBuffer[(byte)(index + 1)];

                        apdu.sendBytes((short)0,(short)numBytes);


                        return;
                   }


              }
              • 4. Re: RSA implementation basics ...
                safarmer
                Hi,

                Just a tip for pasting code. Use the CODE button to place code between { code } (without the spaces) tags to make the code a little more readable.

                Cheers,
                Shane
                package test;
                
                import javacard.framework.APDU;
                import javacard.framework.ISO7816;
                import javacard.framework.ISOException;
                import javacard.security.KeyBuilder;
                import javacard.security.KeyPair;
                import javacard.security.RSAPrivateCrtKey;
                import javacard.security.RSAPublicKey;
                import javacardx.crypto.Cipher;
                
                /*
                 * Title:        RSAEncryptDecrypt
                 * Description:  Description.
                 * Copyright:    Copyright (c) 2010
                 * Company:      Queensland Transport
                 */
                
                public class RSAEncryptDecrypt extends javacard.framework.Applet {
                
                    // This applet is designed to respond to the following
                    // class of instructions.
                
                    final static byte GETSET_CLA = (byte) 0x85;
                
                    final static byte CRYPT_CLA = (byte) 0x00;
                
                    // Instruction set for SimpleString
                
                    final static byte SET = (byte) 0x10;
                    final static byte GET = (byte) 0x20;
                    final static byte SELECT = (byte) 0xA4;
                
                    // This buffer contains the string data on the card
                    byte TheBuffer[];
                
                    // globals
                    RSAPrivateCrtKey rsa_PrivateCrtKey;
                    RSAPublicKey rsa_PublicKey;
                    KeyPair rsa_KeyPair;
                    Cipher cipherRSA;
                    final short dataOffset = (short) ISO7816.OFFSET_CDATA;
                
                    // constructor
                    private RSAEncryptDecrypt(byte bArray[], short bOffset, byte bLength) {
                
                        TheBuffer = new byte[100];
                
                        // generate own rsa_keypair
                        rsa_KeyPair = new KeyPair(KeyPair.ALG_RSA_CRT, KeyBuilder.LENGTH_RSA_1024);
                        rsa_KeyPair.genKeyPair();
                        rsa_PublicKey = (RSAPublicKey) rsa_KeyPair.getPublic();
                        rsa_PrivateCrtKey = (RSAPrivateCrtKey) rsa_KeyPair.getPrivate();
                        cipherRSA = Cipher.getInstance(Cipher.ALG_RSA_PKCS1, false);
                        register(bArray, (short) (bOffset + 1), bArray[bOffset]);
                    }
                
                    // install
                    public static void install(byte bArray[], short bOffset, byte bLength) {
                        new RSAEncryptDecrypt(bArray, bOffset, bLength);
                    }
                
                    public void process(APDU apdu) {
                
                        if (selectingApplet()) {
                            return;
                        }
                
                        byte[] buf = apdu.getBuffer();
                
                        byte cla = buf[ISO7816.OFFSET_CLA];
                
                        byte ins = buf[ISO7816.OFFSET_INS];
                
                        if ((buf[ISO7816.OFFSET_CLA] != 0) && (buf[ISO7816.OFFSET_CLA] != GETSET_CLA))
                            ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
                
                        if ((buf[ISO7816.OFFSET_INS] != (byte) (0xAA)) && (buf[ISO7816.OFFSET_INS] != (byte) (0x10))
                                && (buf[ISO7816.OFFSET_INS] != (byte) (0x20)))
                            ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
                
                        switch (cla) {
                            case GETSET_CLA:
                                switch (ins) {
                                    case SET:
                                        SetString(apdu);
                                        break;
                                    case GET:
                                        GetString(apdu);
                                        break;
                                }
                            case CRYPT_CLA:
                                switch (buf[ISO7816.OFFSET_P1]) {
                                    case (byte) 0x01:
                                        encryptRSA(apdu);
                                        return;
                                    case (byte) 0x02:
                                        decryptRSA(apdu);
                                        return;
                                }
                
                        }
                    }
                
                    private void encryptRSA(APDU apdu) {
                        byte a[] = apdu.getBuffer();
                        short byteRead = (short) (apdu.setIncomingAndReceive());
                        cipherRSA.init(rsa_PrivateCrtKey, Cipher.MODE_ENCRYPT);
                        short cyphertext = cipherRSA.doFinal(a, (short) dataOffset, byteRead, a, (short) dataOffset);
                
                        // Send results
                        apdu.setOutgoing();
                        apdu.setOutgoingLength((short) cyphertext);
                        apdu.sendBytesLong(a, (short) dataOffset, (short) cyphertext);
                        // SetString(apdu);
                
                    }
                
                    private void decryptRSA(APDU apdu) {
                        byte a[] = apdu.getBuffer();
                
                        short byteRead = (short) (apdu.setIncomingAndReceive());
                        cipherRSA.init(rsa_PublicKey, Cipher.MODE_DECRYPT);
                        cipherRSA.doFinal(a, (short) dataOffset, byteRead, a, (short) dataOffset);
                
                        // Send results
                        apdu.setOutgoing();
                        apdu.setOutgoingLength((short) 24);
                        apdu.sendBytesLong(a, (short) dataOffset, (short) 24);
                
                    }
                
                    // SetString stores the string on the card.
                
                    private void SetString(APDU apdu) {
                
                        byte buffer[] = apdu.getBuffer();
                
                        byte size = (byte) (apdu.setIncomingAndReceive());
                
                        byte index;
                
                        // Store the length of the string and the string itself
                
                        TheBuffer[0] = size;
                
                        for (index = 0; index < size; index++)
                            TheBuffer[(byte) (index + 1)] = buffer[(byte) (ISO7816.OFFSET_CDATA + index)];
                
                        return;
                
                    }
                
                    // 1. Client sends a GetString APDU with a length of 0
                    // 2. Card responds with a Status Word of 0x62YY, where YY is the length
                    // of the string (in hex).
                    // 3. The client sends its GetString APDU again, but this time with the
                    // correct length.
                    //
                
                    private void GetString(APDU apdu) {
                
                        byte buffer[] = apdu.getBuffer();
                
                        byte numBytes = buffer[ISO7816.OFFSET_LC];
                
                        if (numBytes == (byte) 0) {
                            ISOException.throwIt((short) (0x6200 + TheBuffer[0]));
                        }
                
                        apdu.setOutgoing();
                        apdu.setOutgoingLength(numBytes);
                
                        byte index;
                
                        for (index = 0; index <= numBytes; index++)
                            buffer[index] = TheBuffer[(byte) (index + 1)];
                
                        apdu.sendBytes((short) 0, (short) numBytes);
                
                        return;
                    }
                }
                • 5. Re: RSA implementation basics ...
                  safarmer
                  Hi,

                  To find out what is going wrong, you should place your crypto code in a try/catch block and inspect the error code from the CryptoException. If you can tell me what error code you are getting. Also, use the value returned from the cipherRSA.doFinal method when returning the response as the padding will be stripped from the plain text during the decryption process (since you are using PKCS1 padding).

                  This bit of code will return 0x91XX where XX is the reason for the exception.
                      private void decryptRSA(APDU apdu) {
                          byte a[] = apdu.getBuffer();
                  
                          short byteRead = (short) (apdu.setIncomingAndReceive());
                          short len = 0;
                          try {
                              cipherRSA.init(rsa_PublicKey, Cipher.MODE_DECRYPT);
                              len = cipherRSA.doFinal(a, ISO7816.OFFSET_CDATA, byteRead, a, (short) 0);
                          } catch (CryptoException e) {
                              short sw = (short) 0x9100;
                              sw |= e.getReason();
                              ISOException.throwIt(sw);
                          }
                  
                          // Send results
                          apdu.setOutgoing();
                          apdu.setOutgoingLength(len);
                          apdu.sendBytesLong(a, (short) 0, len);
                  
                      }
                  One thing to note about RSA encryption, you encrypt with a public key so that only the private key holder can decrypt the message. Since the public key by definition is publicly available, encrypting with the private key means anyone can decrypt the message.

                  If your card will be the only thing encrypting and decrypting the data you could also get away with something like AES or 3TDEA if your card does not support AES.

                  Cheers,
                  Shane
                  • 6. Re: RSA implementation basics ...
                    843851
                    This bit of code will return 0x91XX where XX is the reason for the exception.
                    dude i get 9103 when i try to create an AESKEY but when i call the AES algorithm using CIPHER there are no issues

                    {try {
                                   Cipher cipher = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD , false);
                                   AESKey key = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES,KeyBuilder.LENGTH_AES_128,false);
                                 } catch (CryptoException e) {
                         short sw = (short) 0x9100;
                         sw |= e.getReason();
                         ISOException.throwIt(sw);
                         }
                    }

                    status i get it 9103
                    on the otherhand


                    {try {
                                    Cipher cipher = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD , false);
                                        //AESKey key = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES,KeyBuilder.LENGTH_AES_128,false);
                                 } catch (CryptoException e) {
                         short sw = (short) 0x9100;
                         sw |= e.getReason();
                         ISOException.throwIt(sw);
                         }
                    }

                    here i get no exception, but ofc i cant use the key coz its not built

                    Let me know if this means that the AES hardware is avialable in card and if so is there any other way to build this AES key....

                    Thanks in advance
                    cheers
                    Bharat
                    • 7. Re: RSA implementation basics ...
                      safarmer
                      That means your card does not support AES.

                      Cheers,
                      Shane
                      • 8. Re: RSA implementation basics ...
                        843851
                        err... k dude wat other symmetric alogos can i use... i know DES (no pad) but it doesn accept input if its size not a multiple of 8byte... i thot these cards had AES... btw i got jcop v.2.3.1 manual says AES is there...:(

                        cheers
                        Bharat
                        • 9. Re: RSA implementation basics ...
                          843851
                          It depends what JCOP v2.3.1 configuration you have. Paste the /identify response.

                          To my knowledge AES is supported on the following JCOP v2.3.1 configurations: JCOP 21/xx, JCOP 41/xx
                          • 10. Re: RSA implementation basics ...
                            safarmer
                            Code_Addict wrote:
                            err... k dude wat other symmetric alogos can i use... i know DES (no pad) but it doesn accept input if its size not a multiple of 8byte... i thot these cards had AES... btw i got jcop v.2.3.1 manual says AES is there...:(
                            Check the Java Doc for javacardx.crypto.Cipher. There are some ALG_DES_* constants. Try ALG_DES_ECB_PKCS5.

                            Cheers,
                            Shane
                            • 11. Re: RSA implementation basics ...
                              843851
                              {

                              try {


                              Cipher cipher = Cipher.+getInstance+(Cipher.+ALG_DES_ECB_PKCS5+ , false);


                              } catch (CryptoException e) {


                              short sw = (*short*) 0x9100;


                              sw |= e.getReason();


                              ISOException.+throwIt+(sw);


                              }

                              }

                              dude the sw is 9103... that means this algo not there? how come? n even the simulator doesn accept... atleast the AES algo part came out successfully...

                              cheers
                              Bharat
                              • 12. Re: RSA implementation basics ...
                                843851
                                cm> /identify
                                => 00 A4 04 00 09 A0 00 00 01 67 41 30 00 FF .........gA0..
                                (259460 nsec)
                                <= C1 11 01 28 00 00 00 00 50 48 36 32 39 41 00 00 ...(....PH629A..
                                6A 82 j.
                                Status: File not found
                                FABKEY ID: 0xC1
                                PATCH ID: 0x11
                                TARGET ID: 0x01 (smartmx)
                                MASK ID: 0x28 (40)
                                CUSTOM MASK: 00000000
                                MASK NAME: PH629A
                                FUSE STATE: not fused
                                ROM INFO: -
                                COMBO NAME: smartmx-m28.C1.11-PH629A


                                This is the response on the simulator for JCOP 21 36k Version 2.3.1
                                If u need the response from the actual card i can get dat as well lemme know if this helps...

                                cheers
                                Bharat
                                • 13. Re: RSA implementation basics ...
                                  safarmer
                                  Try the other algorithms. Go for one with CBC mode.

                                  Cheers,
                                  Shane
                                  • 14. Re: RSA implementation basics ...
                                    843851
                                    The following doesnt work
                                    ALG_DES_CBC_PKCS5, ALG_DES_ECB_PKCS5

                                    These work:
                                    ALG_DES_CBC_ISO9797_M1, ALG_DES_CBC_ISO9797_M2 , ALG_DES_CBC_NOPAD , ALG_DES_ECB_ISO9797_M1, ALG_DES_ECB_ISO9797_M2 , ALG_DES_ECB_NOPAD

                                    On using those which work, cant use input which aint multiple of 8( size in bytes)

                                    this is the response
                                    => 00 12 00 00 ....
                                    (4023 usec)
                                    <= 6F 00 o.
                                    Status: No precise diagnosis

                                    Ok kool dude i've been wastin my time as well as yours... anyways let me know if there is anythin possible ... i'm gonna add 0s in front of the input to make it a 8-byte multiple n continue... hopin there are no issues... havin a deadline...

                                    Cheers
                                    Bharat
                                    1 2 3 4 Previous Next