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.

AES

Applets Development Guide

Moderator: product

liuyuanyuan
Posts: 3
Joined: Fri Oct 12, 2018 3:03 am
Points :40
Contact:

AES

Post by liuyuanyuan » Wed Oct 17, 2018 7:33 am

Hello, I am a newcomer to learn java card, now I have a problem, I want to ask for your help, thank you!
When I run the AES encryption algorithm on JCIDE, when I download the applet, I have a problem with the installation failure. I received a reply from 6A 80. How should I solve this problem? Thanks!Here's the overall code.

Code: Select all

package com.AES.LY;

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

public class AESSample extends Applet
{
   private static final byte INS_SET_AES_KEY              = (byte)0x10;
    private static final byte INS_SET_AES_ICV              = (byte)0x11;
    private static final byte INS_DO_AES_CIPHER            = (byte)0x12;
        
    private byte aesKeyLen;
    private byte[] aesKey;
    private byte[] aesICV;

    private Cipher aesEcbCipher;
    private Cipher aesCbcCipher;

    private Key tempAesKey1;
    private Key tempAesKey2;
    private Key tempAesKey3;
    
    public AESSample()
    {
        aesKey = new byte[32];    //给byte型数组aesKey分配一个大小为32的内存空间
        aesICV = new byte[16];    //给byte型数组aesICV分配一个大小为16的内存空间
        aesKeyLen = 0;            //给byte型变量aesKeyLen赋值为0
		
        //Create a AES ECB/CBS object instance of the AES algorithm.(创建AES ECB/CBS对象实例的AES算法)
        aesEcbCipher = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_ECB_NOPAD, false);
        aesCbcCipher = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false);
		
      //Create uninitialized cryptographic keys for AES algorithms(为AES算法创建未初始化的加密密钥)
        tempAesKey1 = KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT, KeyBuilder.LENGTH_AES_128, false);
        tempAesKey2 = KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT, KeyBuilder.LENGTH_AES_192, false);
        tempAesKey3 = KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT, KeyBuilder.LENGTH_AES_256, false);

        JCSystem.requestObjectDeletion();
    }
    
   public static void install(byte[] bArray, short bOffset, byte bLength) 
   {
      new AESSample().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_SET_AES_KEY:
           // SET_AES_KEY
            setAesKey(apdu, len);
            break;
        case INS_SET_AES_ICV:
           // SET_AES_ICV
            setAesICV(apdu, len);
            break;
        case INS_DO_AES_CIPHER:
           //DO_AES_CIPHER
            doAesCipher(apdu, len);
            break;
      default:
         ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
      }
   }
   
   //Set the key of AES Encrypt/Decrypt(设置AES加密/解密密钥)
    private void setAesKey(APDU apdu, short len)
    {
        byte[] buffer = apdu.getBuffer();
        byte keyLen = 0;
        switch (buffer[ISO7816.OFFSET_P1])
        {
        case (byte)0x01:
            if (len != 16) // The length of key is 16 bytes
            {
                ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
            }
            keyLen = (byte)16;
            break;
        case (byte)0x02:
            if (len != 24) //The length of key is 24 bytes
            {
                ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
            }
            keyLen = (byte)24;
            break;
        case (byte)0x03:
            if (len != 32) //The length of key is 32 bytes
            {
                ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
            }
            keyLen = (byte)32;
            break;
        default:
            ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
            break;
        }

        JCSystem.beginTransaction();
        //Copy the incoming AES Key value to the global variable 'aesKey'(将传入的AES密钥值复制到全局变量“aesKey”)
        Util.arrayCopy(buffer, ISO7816.OFFSET_CDATA, aesKey, (short)0, len);
        aesKeyLen = keyLen;
        JCSystem.commitTransaction();
    }

   //Set AES ICV, ICV is the initial vector(设置AES ICV,ICV是初始向量)
    private void setAesICV(APDU apdu, short len)
    {
        if (len != 16)
        {
            ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
        }
        //Copy the incoming ICV value to the global variable 'aesICV'(将传入的ICV值复制到全局变量'aesICV')
        Util.arrayCopy(apdu.getBuffer(), ISO7816.OFFSET_CDATA, aesICV, (short)0, (short)16);
    }

   //Sets the Key data, and return the AESKey object. The plaintext length of input key data is 16/24/32 bytes.
    private Key getAesKey()
    {
        Key tempAesKey = null;
        switch (aesKeyLen)
        {
        case (byte)16:
            tempAesKey = tempAesKey1;
            break;
        case (byte)24:
            tempAesKey = tempAesKey2;
            break;
        case (byte)32:
            tempAesKey = tempAesKey3;
            break;
        default:
            ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
            break;
        }
      //Set the 'aesKey' key data value into the internal representation
        ((AESKey)tempAesKey).setKey(aesKey, (short)0);
        return tempAesKey;
    }
   
   //AES algorithm encrypt and decrypt
    private void doAesCipher(APDU apdu, short len)
    {
       //The byte length to be encrypted/decrypted must be a multiple of 16
        if (len <= 0 || len % 16 != 0)
        {
            ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
        }

        byte[] buffer = apdu.getBuffer();
        Key key = getAesKey();
        byte mode = buffer[ISO7816.OFFSET_P1] == (byte)0x00 ? Cipher.MODE_ENCRYPT : Cipher.MODE_DECRYPT;
        Cipher cipher = buffer[ISO7816.OFFSET_P2] == (byte)0x00 ? aesEcbCipher : aesCbcCipher;
        //Initializes the 'cipher' object with the appropriate Key and algorithm specific parameters.
        //AES algorithms in CBC mode expect a 16-byte parameter value for the initial vector(IV)
        if (cipher == aesCbcCipher)
        {
            cipher.init(key, mode, aesICV, (short)0, (short)16);
        }
        else
        {
            cipher.init(key, mode);
        }
        //This method must be invoked to complete a cipher operation. Generates encrypted/decrypted output from all/last input data. 
        cipher.doFinal(buffer, ISO7816.OFFSET_CDATA, len, buffer, (short)0);
        apdu.setOutgoingAndSend((short)0, len);
    }

}
Here's the code shown by the debug shell

Code: Select all

>> install 4A617661436172644F53 4A617661436172644F5302 4A617661436172644F5302 00 
>> 80 E6 0C 00 29 0A 4A 61 76 61 43 61 72 64 4F 53 0B 4A 61 76 61 43 61 72 64 4F 53 02 0B 4A 61 76 61 43 61 72 64 4F 53 02 01 00 02 C9 00 00 00
<< 6A 80   wrong data

>> cardinfo
>> 80 F2 80 00 02 4F 00 00
<< 08 A0 00 00 00 03 00 00 00 01 9A 90 00   

>> 80 F2 40 00 02 4F 00 00
<< 90 00   

>> 80 F2 10 00 02 4F 00 00
<< 0A 4A 61 76 61 43 61 72 64 4F 53 01 00 01 0B 4A 61 76 61 43 61 72 64 4F 53 02 90 00   

Card Manager AID   :  A000000003000000
Card Manager state :  OP_READY

    Load File  :      LOADED (--------) 4A617661436172644F53
     Module    :                        4A617661436172644F5302



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

Re: AES

Post by tay00000 » Tue Oct 23, 2018 11:20 am

Which card are you using ?

liuyuanyuan
Posts: 3
Joined: Fri Oct 12, 2018 3:03 am
Points :40
Contact:

Re: AES

Post by liuyuanyuan » Thu Nov 01, 2018 5:14 am

I think I already know how to solve it. My JCIDE version is too old, and it succeeds after update.Thank you all the same.Also, I would like to ask how you can call the encryption algorithm in the electronic wallet, such as using the AES encryption algorithm to encrypt the APDU command between the card and the card reader to prevent eavesdropping.I once consulted a teacher, who told me that I should write a function in the e-wallet code to call the AES encryption algorithm, but I did not understand the Java code very well, could you give me some guidance?

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

Re: AES

Post by tay00000 » Thu Nov 01, 2018 9:25 am

Here are the generic steps for you to encrypt your APDU commands.

Firstly, you can use the card's SCP protocol to open a secure channel into the card but it seems like from your question, you are more interested in creating your own secure channel so we will assume you want to make your own encrypted secure channel.

It is more secure to use an asymmetric keypair than a symmetric secret key to open a secure channel because an asymmetric keypair may give you the ability to provision more card users if you decide to expand it's scope.

I will assume the use of the asymmetric keyed method to create a secure channel of your own preference into the card. The outline of the protocol is by no means production capable and is pretty advance so you may need a lot of help on this but the ease of use of the protocol by the end user is quite simple.

You will need some knowledge of cryptography to process the following information otherwise the methods described below is as good as meaningless.

We will use an ECC algorithm to establish a Key Exchange between the card and the user's desktop application. To do so, you will need the card to own it's own ECDSA keypair and your user will also need to own their own ECDSA keypair.

For the card to own it's own ECDSA keypair, you need the card to randomly generate an ECC keypair during card applet installation and also an APDU command for extracting the card's ECDSA Public Key.

For the user to own their own ECDSA keypair, you will as the user via a desktop application to enter in a strong password they can remember and then use Scrypt function to derive a data stream from the strong password and execute a SHA-256 hash on the data stream to get a random 256-bit ECDSA private key on the user's desktop application (not card).

You proceed to derive the 512 bit public key from the 256 bit ECDSA private key with a sample here. With the user's ECDSA public key, you upload the user's Public Key to the card and you download the card's Public Key and make a note of the card's Public Key.

Once you have uploaded the user's ECDSA public key into the card, you may want to set aside a reserved card status byte to show that the card has been personalized and prevent the future uploading of the user's ECDSA public key to prevent malicious attackers from trying to manipulate the security state of the card.

Whenever the user wants to securely communicate with the card, the user would randomly generate an ECDH keypair and use the user's own ECDSA private key to sign the ECDH public key and hand over to the card the temporary ECDH public key. Likewise, the card will respond to the user by generating it's own temporary ECDH keypair, using it's own ECDSA private key to sign the card's own temporary ECDH public key.

After exchanging the signed ECDH public keys by both sides and both side has verified that the ECDH public key's ECDSA signatures are genuine, they establish an ECDH based Shared Secret whereby the card would take the verified user's ECDH public key and perform a generateSecret() function while using the user's ECDH public key as input. Likewise, the user will also perform a generateSecret() by accepting the card's temporary ECDH public key as input. By doing so, a shared session secret would be derived from the above Key Exchange.

Because the default ECDH derives a 20 byte shared secret, this will not be enough for an AES-256 key so you will need to further SHA-512 hash the shared session secret into a final version of the shared session secret on the card and user desktop application's side.

By executing SHA-512 hash on the shared session secret to derive a final version of the shared session secret, you can accommodate for a 256 bit encryption key and also a 256 bit HMAC key.

Now, with a finalized shared secret, you can use the 256-bit encryption key to encrypt in AES-256 or any other 256-bit key capable encryption algorithm the plaintext APDU bytes and use the HMAC key over HMAC-SHA256 on the encrypted APDU bytes to create a tamper detecting HMAC code to append to the back of your encrypted APDU as additional payload so that the card can detect if the cophertext have been tampered with or not.

Likewise, the card may now be able to encrypt and HMAC it's response in the same manner to provide data confidentiality and data integrity mechanisms to the secure channel.

The merit of this system is that the card user only needs to remember his/her own strong password and could be able to re-generate their card user's keypair to estabblish a secure session with their cards anytime, anywhere with only needing to carry a card, card reader and have a desktop application installed.

This above secure channel algorithm still have flaws like how to prevent replay attacks via random nonces and how to proof that the card's ECDSA Public Key is genuine from a card. These are all the finer details that if you are interested, you will need to seek professional help.

Please do not use the above methods in real world scenario as the above is just something brief and would take little efforts to be broken by highly skilled professionals.

Post Reply Previous topicNext topic

Who is online

Users browsing this forum: No registered users and 21 guests

JavaCard OS : Disclaimer