Page 1 of 1

AES sample code

Posted: Mon Oct 24, 2016 11:24 pm
by Valks
I am getting started with AES algorithm. Is there any guide or sample code for me to refer to?
thanks very much.

Re: AES sample code

Posted: Tue Oct 25, 2016 2:32 am
by JCaberham
FYR

Code: Select all

package crypto_aes;

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

public class CryptoAES extends javacard.framework.Applet
{

     //globals
     AESKey aesKey;
     Cipher cipherAES;
     RandomData random;
     static byte a[];
     final short dataOffset = (short) ISO7816.OFFSET_CDATA;

     //constructor
     private CryptoAES (byte bArray[], short bOffset, byte bLength)
     {
          aesKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_128, false);
          cipherAES = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false);
          a = new byte[ (short) 128];
          random.generateData(a, (short)0, (short)128);
          aesKey.setKey(a, (short) 0);
          register(bArray, (short) (bOffset + 1), bArray[bOffset]);
     }

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

     public void process(APDU apdu)
     {
          byte[] buf = apdu.getBuffer();
          if (selectingApplet())
          {
               return;
          }
          if (buf[ISO7816.OFFSET_CLA] != 0) ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
         
          if (buf[ISO7816.OFFSET_INS] != (byte) (0xAA)) ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
         
          switch (buf[ISO7816.OFFSET_P1])
          {
          case (byte) 0x01:
               doAES(apdu);
               return;
          default:
               ISOException.throwIt(ISO7816.SW_WRONG_P1P2);
          }
     }


     private void doAES(APDU apdu)
     {
         
          byte b[] = apdu.getBuffer();
         
          short incomingLength = (short) (apdu.setIncomingAndReceive());
          if (incomingLength != 24) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

          //perform encryption and append results in APDU Buffer a[] automatically
         
          cipherAES.init(aesKey, Cipher.MODE_ENCRYPT);
          cipherAES.doFinal(b, (short) dataOffset, incomingLength, a, (short) (dataOffset + 24));
          cipherAES.init(aesKey, Cipher.MODE_DECRYPT);
          cipherAES.doFinal(b, (short) (dataOffset + 24), incomingLength, a, (short) (dataOffset + 48));

          // Send results
          apdu.setOutgoing();
          apdu.setOutgoingLength((short) 72);
          apdu.sendBytesLong(b, (short) dataOffset, (short) 72);
     }

Re: AES sample code

Posted: Tue Oct 25, 2016 4:37 am
by Valks
Thanks so much JCaberham.
I will try this code out.

Re: AES sample code

Posted: Mon Oct 31, 2016 10:34 am
by tay00000

Code: Select all

a = new byte[ (short) 128];
random.generateData(a, (short)0, (short)128);


Not sure if you actually need so much bytes since AES is only 16 bytes for 128-bit key and 32 bytes for 256-bit key and in rare circumstances where AES-192 is used that will be 24 bytes. By creating so many bytes, it eats into system resource and when you run generateData for the RNG, it takes even longer (just by a bit more for most cases) to access the RNG's pool of random bytes and in some instances, some card's RNG have a smaller RNG pool and the RNG have to go through a few cycles to fill it's pool of random data then give you the random data. Best to only use what you need.

Also, it is best to generateData() into a transient array and not a permanent array to alleviate wear leveling on the EEPROM/Flash memory as every bit of longevity of the card really matters. Also the thing most people don't do is to leave the data buffer dirty with existing key data. It is best to make it a habit to run a Util.arrayFillNonAtomic() with zero bytes to wipe the buffer if it once contains key data to ensure it does not leak key bytes by some bad accidents. It ever happened before and it leaves a bad stinging taste if you accidentally send out key data bytes by accident.

Also for the doFinal() and update() method, just to add on, you can accept a return of processed bytes. One example ...

Code: Select all

// Buffers of short data type
short[] shortBuff = JCSystem.makeTransientShortArray((short) 1, JCSystem.MEMORY_TYPE_TRANSIENT_RESET);

... some other codes ...

cipherAES.doFinal(b, (short) (dataOffset + 24), incomingLength, a, (short) (dataOffset + 48));

// You do not need to calculate how many bytes to send out as this uses a short buffer object to hold the number of output bytes
apdu.setOutgoing();
apdu.setOutgoingLength((short) (shortBuff[0] & 0xFF));
apdu.sendBytesLong(b, (short) dataOffset, (short) (shortBuff[0] & 0xFF));