Using Java smart cards to protect software

Tomcat

Professional
Messages
2,686
Reputation
10
Reaction score
702
Points
113

Chapter 1. General information.​


1. Introduction​


In this series of articles, we will discuss the use of Java smart cards (cheaper analogs of electronic keys) to protect software. The cycle is divided into several chapters.

To read and understand the information from the articles, you will need the following skills::
  • Basic software development for Windows (you only need to be able to program in any visual environment, such as Delphi or Visual Basic)
  • Basic knowledge of cryptography (what is a cipher, symmetric, asymmetric algorithm, initialization vector, CBC, etc. I recommend that you read Applied Cryptography by Bruce Schneier).
  • Basic programming skills in any language that even remotely resembles Java in syntax (Java, C++, C#, PHP, etc.)

The purpose of the series is to introduce the reader to Java cards (there is very little literature on their use in Russian). The cycle does not claim to be a "Guide for Developing Java-based Software Protection" or a "Java-based Card Reference".

Cycle composition:​

  • Chapter 1. Java card. General-information.
  • Chapter 2. Java card from the Applet Developer's Point of View
  • Chapter 3. Installing and Configuring the IDE
  • Chapter 4. Writing the first applet
  • Chapter 5. Security

2. Assumptions​


Not a single article in the series claims to be complete and accurate, although the author tried very hard to make all of them as complete and accurate as possible.
When using any information in this series of articles, please note that you do so at your own risk. The author is not responsible for any damage that the use of this information may cause you.

This series of articles focuses on Java cards that meet the GlobalPlatform version 2.1.1 and JavaCard 2.2.1 standards, such as NXP JCOP or Gemalto TOP GX. All or part of the information in this series of articles may not be applicable to Java cards that do not meet these standards (with the exception, of course, of later versions of these standards). Using cards that do not meet the mentioned standards for software protection may not be safe for the project.

Since the description of the GlobalPlatform standard for one specific version alone takes up about 350 printed A4 sheets, the author deliberately goes to some simplification of the terms and theories underlying the architecture of the described cards, which, in his opinion, does not contradict real data.

3. Basic information about Java cards​


What is a Java card? A Java card is a small computer encased in a SIM card case similar to the one you use in your cell phone. This microcomputer has its own microprocessor (such as the Philips P8WE5017, for example), a certain amount of "flash"memory for storing programs (usually from 32 to 128 kilobytes), and a cryptographic coprocessor.

The card communicates with the computer via a special reader, usually inserted into the USB port. But there are also contactless cards that are easy enough to bring to the reader to establish a connection.

Programs called applets can be stored in the card's memory. Applets are written in a slightly truncated version of the Java language (a text file with the extension .java), then compiled into bytecode by a regular Java compiler (a *.class file is obtained) and converted by a special converter program for direct loading into the card (usually a*. cap or *.ijc file). The Java language variant used for writing applets is simplified in such a way that applets are as fast and compact as possible (for example, support for such types as string is removed from the language, and most cards do not support int either. As a rule, there is no garbage collector — more on this in the following articles). Communication with the card is performed by sending a command called APDU (Application protocol data unit) to the card, consisting of a 5-byte header and command data. In response, the card can respond with a two-byte code: either an error code or a code indicating the successful execution of the operation (usually 90 00). Along with the operation success code, the card can send the application a byte stream corresponding to the result of the command execution (for example, decrypted data).

By default, the card usually already has at least one applet, called ISD or Card Manager, that provides basic functionality (such as installing and removing applets). Sometimes the manufacturer also installs other applets in the card (for example, the PKCS#11 support applet or the e-wallet applet).

Most Java cards carry a cryptographic coprocessor that speeds up the execution of encryption operations and checksum calculations by applets. The most commonly used ones are DES, AES, RSA, and SHA1. A complete list of supported algorithms can be found in the JavaCard SDK. A list of algorithms supported by a specific card can be found in the documentation for specific cards (yes, as a rule, the standard is not fully supported by the card, for example, due to export restrictions).

Technically, the applet code is an instance of a class inherited from some abstract JavaCard API class (Applet), whose methods provide basic functionality (installation processing, response to commands from the computer). All members of the applet class are persistent and stored in the card's EEPROM. Thus, if an instance of the applet class has the short x = 5 field and the applet has changed this value as a result of executing the APDU command, then the changed value will be available to the applet after removing the card from the computer and inserting it back into the reader.

The size of the card's RAM is usually small and depends on the implementation. Usually no more than 1Kb.

Access keys are used to protect the card. Usually there are three of them — the encryption key (ENC/AUTH), the signature key (MAC), and the key for encrypting important data (DEK/KEK), which is used when changing access keys to the card, as a rule). These are usually 3DES2 keys that are 16 bytes long each. Knowledge of these keys is only necessary for manipulating the applet (writing and deleting, reading the list of applets installed on the card). Sending a command to your applet and receiving a response from it does not require knowledge of these keys.

To communicate with the card from your Windows software, the SmartCard API is used, which allows you to transparently communicate with all cards that meet the standard, regardless of the card type and reader. Many programming languages (Java, .NET, Delphi, and others) have wrapper libraries for communicating with the card that provide the required functionality in a developer-friendly form of classes / components.

Some cards on the market (such as the Gemalto CyberFlex Egate 32k) have a built-in USB interface and can be used with a reader that can be "soldered" almost at home. However, such cards are much more expensive than regular ones. The cost of a card reader with a USB interface for large batches can be about $ 1. The cost of a standard reader, which usually has drivers built into Windows for production at Chinese facilities, is a few dollars.

The cards are delivered both in the form factor of a cell phone SIM card and in a "large" format.

The API for working with cards can respond to card insertion and extraction, which allows you to implement using cards, for example, employee time tracking systems (you need to leave — put the card in the reader or the reader itself with its own card in the PC. The software responded, asked the applet to sign random data, checked the signature, and registered it).

4. Why it is convenient to use Java cards for software protection​


The owner can load one or more applets into the Java card that implement almost any algorithms (the complexity, of course, is limited by the speed of the card processor and the amount of available memory). But these applets cannot be read from the card by anyone, including the cardholder (the applet can only be erased and a new one written in its place). You can only pass a certain command to the applet and get a response. The perfect "black box".

The GlobalPlatform standard allows remote, secure updates of applets, for example, over the Internet. At the same time, the use of cryptographic algorithms ensures that the source code of the applet cannot be intercepted by a third party (I had to write client-server solutions for such operations. I can't say that everything is simple, since the cards are still different, but, nevertheless, it is quite possible).

A Java card is usually protected from electronic data collection by special methods (i.e. it is impossible to make a copy of it). Remember that we are talking about specific cards that implement specific standards. Some Mifare cards, such as those used by our metro in the past, can be easily cloned (although this is not a Java card), while those produced using IBM JCOP technology are usually very difficult.

The applet can block the card itself (to unlock it, you will need to set up a secure session, which requires knowledge of the access keys to the card) or destroy the card (further work with it by any means will be impossible, the card will always respond with an error).

Many Java cards are certified according to EAL standards (some JCOPS are certified, for example, according to EAL4+, EAL5), which guarantees reliable protection. Some cards are used, for example, as electronic wallets by companies such as Visa.

The cost of some Java cards when purchasing in large batches is very low (some simple JCOP variants cost several euros for large batches). Compare this cost with the cost of some specialized security keys like HASP or Guardant, most of which, by the way, do not allow you to place arbitrary algorithms in the key's memory.

The Java language variant used for writing applets is extremely easy to learn and use
All the tools for working with most of the cards available on the market are open and free.

5. Can I hack software protected by a Java card?​


The difficulty of hacking software protected by the card depends on the complexity of the algorithm that you put in the card. For example, if you place an applet in the card that will sum two transmitted numbers and return the result, there is a good chance that the first hacker will make an emulator. He doesn't even have to break the software for this (it's enough to replace the dll in Windows that communicates with the card). However, it should be noted that in this case, you will be able to release version V2 of your applet, which will already sum up three numbers and will thus be “more resistant” to hacking.

But, for example, if you wrote software that uses a card to generate an electronic signature of documents using RSA keys that you put in the applet, such software will be impossible to crack, since it is absolutely impossible to extract the RSA key from the applet if the applet itself does not want to. However, as a rule, the protection mechanisms placed in the applet are a cross between the two examples given, and we'll talk about this later.

6. Selecting a Java Card​


When choosing cards to protect your software, be careful.
  • Study all the documents and characteristics of the cards that are offered to you.
  • Make sure that your cards are certified and protected from attacks.
  • Pay attention to the list of algorithms supported by the card. For example, on some cheap JCOPS, AES and RSA are disabled (the algorithms may not be completely disabled. For example, you will only be able to work with keys of limited length).

As for me, with a light heart, I can only recommend using NXP JCOP or Gemalto TOP (and their older versions).

7. Where to buy​


In general, it is better to buy cards abroad from trusted suppliers working with large companies. In Russia, the prices for them are simply wild (although, of course, everything depends on the quantity). But for tests or initial development, you can buy them in online stores. Unfortunately, few people will give you a good price for a small batch of cards. But it is quite possible to buy a couple of pieces for a trial.

8. Gratitude to patient readers​


Thank you to everyone who read this far. Thanks and indignation are accepted.

I will be glad to have any questions in the comments and try to update the article so that it includes answers.


Chapter 2. Java Smart Card from the Applet Developer's Point of View​


1. APDU command.​


The command passed to the applet is called an APDU command. An APDU command consists of five bytes of header + data. However, you don't need to send the data yourself. Five bytes of the header:
  • CLA — command class. Defines the class of the command to send. It usually takes the values 0x00, 0x80, and 0x84.
  • INS — command instruction. Defines directly the action that the applet should perform.
  • P1 is the first parameter. It can pass additional instructions to the applet.
  • P2 is the second parameter. It can pass additional instructions to the applet.
  • LC — length of the data following the header. 0 if no data is available.
  • Data. Additional team data.

For example:
Code:
00A4040008A000000003000000

Code:
[0x00] (CLA) [0xA4] (INS) [0x04] (P1) [0x00] (P2) [0x08] (LC) [0xA0 0x00 0x00 0x00 0x03 0x00 0x00 0x00] (DATA)

0x00, 0xA4 is the SELECT APPLICATION command that selects an applet for subsequent data exchange. To pass a command to your applet, you must first select it using this command. The parameter P1 = 0x04 means that the applet is selected by its name (AID, see below). The parameter P2 = 0x00 means that we want to select an applet that strictly matches the passed name. As data (8 bytes), we passed the applet name ("a000000003000000" is the standard name for the CardManager applet in some card variants). For more information about standard applet commands, see Global Platform Card Spec 2.1.1, page 105

As you can see, the maximum size of an APDU command is 255 + 5 = 260 bytes (there is, however, support for " long commands, but I have never used them). However, in practice, commands longer than a hundred bytes are rarely used. I try to make sure that the commands don't exceed 127 bytes in length. The reason for this precaution is simple: you may come across cards whose APDU buffer size is less than 260 bytes and the card simply won't accept a long command. We'll have to send it in parts.

For your applets, it is better to choose the CLA value in the range 0xD0-0xFE, and the INS value — any value that is not used by standard commands, except for the ranges 0x60-0x6F, 0x90-0x9F (this is a technical limitation of the T=0 protocol).

2. AID. Packages​


The applet name is called AID (Application Identifier). Several applets or just classes can be combined into a package (in fact, the concept of a package in relation to Java cards is the same as in Java itself). The package also has an identifier (Package AID). The first bytes of the applet's AID must be equal to the AID of its packet. For example, I have a package A0101010101010, and in it an applet with the AID A010101010101055. The minimum AID length is 5 bytes. The maximum is 16.

3. Applet firewall. Applet communication.​


By default, applets are completely independent of each other. They don't have any means of transmitting data to each other. However, one applet can implement the Shareable interface, giving others access to some of its methods. Only primitive data types and references to the APDU buffer (the place where the received command is usually placed in the card and the response to it is formed) can cross the border between applets, since it is actually shared by all card applets.

Using the JavaCard API, different applets can "talk" to each other (using the Shareable interface). This allows you, for example, to implement a permanent applet that returns the card's serial number and a second applet that implements the set of functions you need. In this case, the second applet can be safely updated, and the first one can be left in the card forever. Then it will be able to perform some operations that depend on the serial number (for example, encrypt data in a unique way for this serial number).

4. Return codes.​


After processing the command, the applet returns a two-byte result code. A successful result code can be accompanied by a set of response bytes. A list of possible return codes can be found here. Usually, successful completion of the operation has the code 90 00.

5. Working with memory.​


All members of the applet class are located in the EEPROM of the card memory, which is quite slow. But usually cards have some small (up to several kilobytes) amount of transient memory, which is somewhat similar to RAM. Access to it is several times faster. This memory is allocated on request by calling JCSystem. makeTransientByteArray(). Please note that the amount of this memory is limited (the few kilobytes I mentioned are allocated to all card applets).

6. Data transfer protocols.​


Two protocols are used to communicate with cards: T=0 and T=1. T=0 is considered character-oriented, and T=1 is considered information-oriented. However, these nuances don't matter to us. Simply put, these protocols differ only in that in the case of the T=1 protocol, data is transmitted in a stream, as we are used to (stream-question => stream-answer), and in the case of T=0, we have a hemorrhoid with the need to form a command differently depending on whether we transmit data or not, whether we are waiting for data or not (for details, see the description of SCardTransmit. I will not consider the subtleties of the protocols here (at one time they gave me a bit of hemorrhoids when the client suddenly had cards with T=1, and my software worked only with T=0), I will only note that it is preferable to choose components for working with cards that provide transparent support for both protocols. If you are interested in differences, please contact my Delphi component, which I use to communicate with cards. I tried to build in transparent support for both. Time will tell how well I did it.

7. ATR and other card information​


ATR = Answer To Reset is a set of bytes returned by the card to identify it. If you happen to be using different types of cards for a particular project, studying ATR is a good way to distinguish between them. You can get the ATR by calling SCardGetAttrib.

CPLC Data (Card Production Life Cycle Data) is a set of data about the card that the CardManager applet usually returns when sending the command 0x80 0xCA 0x9F 0x7F to it. This data contains some system information about the card, such as, for example, the EEPROM serial number. I would like to note that it is difficult to count on the uniqueness of, for example, the EEPROM serial number. If you expect to have a serial number on the card, write an applet that will implement reading/writing this number. Since I did not find the CPLC Data fields decryption in the official documentation, I give the structure of this data in Delphi here:

Code:
TFSCardAPICPLCData = packed record
  public
    CPLCTag: array[0..1] of Byte; // Expected: 9F 7F
    CPLCLength: Byte; // Expected: 2A
    IntegratedCircuitROMFabricator: array[0..1] of Byte;
    IntegratedCircuitROMType: array[0..1] of Byte;
    ROMOSidentifier: array[0..1] of Byte;
    OSReleaseDate: array[0..1] of Byte;
    OSReleaseLevel: array[0..1] of Byte;
    EEPROMFabricationDate: array[0..1] of Byte;
    EEPROMSerialNumber: array[0..3] of Byte;
    EEPROMBatchIdentifier: array[0..1] of Byte;
    EEPROMModuleFabricator: array[0..1] of Byte;
    EEPROMModulePackagingDate: array[0..1] of Byte;
    EEPROMIntegratedCircuitCardManufacturer: array[0..1] of Byte;
    EEPROMEmbeddingDate: array[0..1] of Byte;
    EEPROMPrePersonalizer: array[0..1] of Byte;
    EEPROMPrePersonalizationDate: array[0..1] of Byte;
    EEPROMPrePersonalizationEquipmentIdentifier: array[0..3] of Byte;
    EEPROMPersonalizer: array[0..1] of Byte;
    EEPROMPersonalizationDate: array[0..1] of Byte;
    EEPROMPersonalizationEquipmentIdentifier: array[0..3] of Byte;
  end;

By the way, I also came across cards that returned an error in response to a CPLC request. In fact, this means that the CPLC block was not registered in them during production.

8. Interception of data sent to / from the card​


Since any software communicates with the card via standard Windows libraries, always assume that any round-trip communication can be intercepted. There are even special utilities for this, like APDUView. Therefore, all data exchange with the card must be encrypted. Which automatically assumes that your program must be protected by a Themida-type protector.

9. A little bit about performance​


I did some tests with the cards I had on hand. The test results are very approximate (I did not create any special conditions, the applet was used primitive). The Gemalto TOP IM GX card can transfer 12Kb (kilobytes) of data in approximately 2.177 seconds. Encrypting and transmitting 12Kb of 3DES2 data takes about 8.823 seconds, and AES256 takes 4.420 seconds.

It may seem that it is sparse. However, in this case, I always advise my clients to remember programming for the ZX Spectrum.So let a miracle happen in a few kilobytes.

10. Gratitude to patient readers​


Thank you to everyone who read this far. Thanks and indignation are accepted.

I will be glad to have any questions in the comments and try to update the article so that it includes answers.


Chapter 3. Installing and Configuring the IDE​


1. Install the required software​


I didn't come across a normal IDE that fully supports the Javacard SDK 2.2.1. Well, unless JCOP Tools, which IBM sold to NXP, and NXP lost somewhere. But even if you find this kit — it is paid. To use it, according to rumors, you also need to sign an NDA. There are several paid SDKs, of which I only worked with the CyberFlex SDK. I didn't like it.

NetBeans 6.9+ includes the Javacard Tools plugin, which is really quite powerful. Unfortunately, this plugin only supports the development of cards that are compatible with the Javacard SDK 3.0 Connected. And there are few such cards on the market. However, no one bothers to develop an applet in this environment without using the Java Card API 3. x features, and then just compile / convert the applet's source code using the usual SDK 2.2.1.

For development, I used the usual Eclipse IDE for Java Developers for a long time, which I brought to mind a little by embedding the necessary utilities from the SDK. So, download the latest version of the Eclipse IDE for Java Developers from the Eclipse website.

Just unpack the downloaded archive somewhere (not in Program Files, preferably) to the hard disk. I usually put it in the root of the disk in the eclipse-java folder. Here and further, it is undesirable to use Russian letters and spaces in folder names.

Next, we will need the Java SDK of any version. It is usually called JavaSE (Java Standard Edition SDK), or JDK. Since Oracle bought Sun, the link may change, but Google will help you if it does. So far, you can download it from here. It comes with an installer, so just install it as usual.

And we'll also need the Java Card Development Kit 2.2.1. I usually put it in the root of the hard drive, too.

Now you need to configure the system a little. Press Windows + Break together on your keyboard or just open My Computer properties. Go to the Advanced tab and click Environment Variables. Add the following to the system variables::

JC_HOME=C: \ java_card_kit-2_2_1 — path where you unpacked the Java Card Development Kit
JAVA_HOME=c:\j2sdk1. 4. 1 — path where the Java SDK is installed. If it is installed in Program Files, it is better to use the short 8.3 path " C:\Progra~1\...».

Now you need to add the value ";%JC_HOME%\bin;%JAVA_HOME%\bin;"to the end of the PATH variable. Moreover, the variables are %..% is better to expand and specify the full paths in PATH.

You can check that the installation is correct by running the build_samples file.bat located in the Java Card SDK folder (samples subdirectory). However, if you use a Java Developer Kit other than 1.3 or 1.4, you will have to adjust it a little. Open the build_samples file.bat and add the "- target 1.2-source 1.2" parameters to the "set JCFLAGS" line (without quotation marks, of course). This is necessary because the card file converter expects files to be compiled by a compatible compiler).

After running build_samples and working correctly, the %JC_HOME%\samples\classes\com\sun\javacard\samples\HelloWorld\javacard\ folder should contain the files HelloWorld.cap, HelloWorld.exp, and HelloWorld.jca. The HelloWorld. cap file is ready for immediate insertion into the card.

2. Configuring Eclipse​


Launch Eclipse. At the first launch, you will be asked about the desired location of the workspace. I usually leave the default location.

Create a new Java project. File -> New -> Project -> Java -> Java Project. Name it something. You can place it outside the workspace, if that's convenient for you. All other settings can be left as is. Click Next. Go to the Libraries tab and delete everything that is there. Click Add External JAR and select the file %JC_HOME%\lib\api.jar (%JC_HOME% = inside the Java Card SDK that you unpacked). Click Finish.

The Package Explorer window appears on the left. Right - click on the src folder and select New - > Package. We need to create a package that will include our test applet. Call it whatever you like. For example, testpackage. Right - click on the package icon in Package Explorer. Select New - > Class. As a superclass (the class from which the class of our applet will be inherited), select "javacard.framework.Applet». Note the creation of all stubs that Eclipse offers, except main() (Constructors from superclass, Inherited abstract methods). Enter the name of the applet class. For example, TestApplet. Click Finish.

As you can see, Eclipse has generated an applet stub, which we will turn into a fully functional applet in the following chapters.

Now we need to make our lives a little easier by writing files to automate the process of compiling an applet and converting it to a*. cap file. To do this, we will need to create two files. One for compiling and converting both the applet and the other for uploading to the card. However, if you want, you can combine everything in one file. Note that we named the package mytestapplet, not the applet MyTestApplet.

So, build. bat:

Code:
@echo off
set APPLET_HOME=C:\Work\JavaCard\MyTestApplet
set PACKAGE_NAME=mytestapplet
set APPLET_NAME=MyTestApplet
del /q %APPLET_HOME%\bin\%PACKAGE_NAME%\*.class
del /q %APPLET_HOME%\bin\%PACKAGE_NAME%\javacard\*.*
%JAVA_HOME%\bin\javac -g -d %APPLET_HOME%\bin -classpath %JC_HOME%\samples\classes\;%JC_HOME%\lib\api.jar;%JC_HOME%\lib\installer.jar -source 1.2 -target 1.2 %APPLET_HOME%\src\
%JC_HOME%\bin\converter -config %APPLET_HOME%\%APPLET_NAME%.opt
pause

I think everything is clear here without comments. And a sample MyTestApplet. opt file from which the converter reads information (penultimate line *.bat):

Code:
-out CAP JCA
-exportpath E:\java_card_kit-2_2_1\api_export_files;D:\java_card_kit-2_2_1\lib\api.jar
-classdir C:\Work\JavaCard\MyTestApplet\bin\
-d C:\Work\JavaCard\MyTestApplet\bin\
-verbose
-applet  0xa0:0x46:0x52:0x41:0x43:0x54:0x41:0x4c:0x0:0x1 mytestapplet.MyTestApplet
mytestapplet
0xa0:0x46:0x52:0x41:0x43:0x54:0x41:0x4c:0x0 1.0

Note the-applet directive (it specifies the applet's AID) and the last line (AID and package version). *. cap file after our manipulations should be in the folder C:\Work\JavaCard\MyTestApplet\bin\.

You can add this file to the Eclipse menu via Run -> External Tools -> External Tools Configurations. I think everything there is quite trivial and does not require an explanation.

3. IntelliJ (JetBrains) IDEA​


I must say that I am a fan of IDEA. IDEA is for me the ideal of an ideal development environment (sorry for the repetitions, I got emotional). Therefore, some time later I left Eclipse, switched to IDEA, and transformed bat files into simple Ant tasks. I'm quite happy with the result.

I highly recommend that you do the same. Although, of course, the taste and color…

4. Gratitude to patient readers​


Thank you to everyone who read this far. Thanks and indignation are accepted.

I will be glad to have any questions in the comments and try to update the article so that it includes answers.


Chapter 4. Writing the first applet​


1. Sample applet​


In fact, we will not write anything. I'll just give you the terribly commented source code of the test applet for the card here. And then I'll tell you about some of the subtleties of implementation.

Code:
package test;

//Import the necessary libraries
import javacard.framework.APDU;
import javacard.framework.Applet;
import javacard.framework.ISO7816;
import javacard.framework.ISOException;
import javacard.framework.Util;
import javacard.security.*;
import javacardx.crypto.*;

//Define applet
public class Test extends Applet {

    // Command class (CLA) for our applet
    private static final byte CLA_TEST = (byte) 0x80;

    // Command number for speed testing
    private static final byte INS_TESTSPEED = (byte) 0x20;

    // Command number for testing encryption
    private static final byte INS_TEST3DES = (byte) 0x30;

    // Allocate ourselves a buffer for encryption operations
    private static byte[] enсryptBuffer = new byte[120];

    // We create an instance of the class that handles encryption. We say we use
    // DES in CBC mode
    private static Cipher cipher = Cipher.getInstance(Cipher.ALG_DES_CBC_NOPAD,
            false);

    // Create an instance of the class that will store the 3DES3 encryption key.
    private static DESKey key = (DESKey) KeyBuilder.buildKey(
            KeyBuilder.TYPE_DES, KeyBuilder.LENGTH_DES3_3KEY, false);

    // Allocate memory for the 3DES3 encryption key
    private static byte[] keyarr = new byte[24];

    // Applet constructor. Called once when the applet is installed in the card
    protected Test() {
        // Fill the encryption buffer with 0xAA bytes
        Util.arrayFillNonAtomic(enсryptBuffer, (short) 0,
                (short) enсryptBuffer.length, (byte) 0xAA);
       // and the key is 0xBB bytes
        Util.arrayFillNonAtomic(keyarr, (short) 0, (short) keyarr.length,
                (byte) 0xBB);

        // Set to use the data from the keyarr array as the key
        // encryption
        key.setKey(keyarr, (short) 0);
    }

    // Method that installs the applet.
    public static void install(byte bArray[], short bOffset, byte bLength)
            throws ISOException {
        new Test().register();
    }

    // Method that is called when sending a command to our applet
    public void process(APDU apdu) throws ISOException {
        // Получаем ссылку на буфер с данными команды
        byte buffer[] = apdu.getBuffer();

        // If the command passed to the applet is SELECT, return control
        // CardManager
        if ((buffer[ISO7816.OFFSET_CLA] == 0x00)
                && (buffer[ISO7816.OFFSET_INS] == (byte) (0xA4)))
            return;

        // If CLA is different than expected, return an error
        if (buffer[ISO7816.OFFSET_CLA] != CLA_TEST) {
            ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
        }

         // We look at what kind of command was sent to us and call the corresponding
         // processing method
        switch (buffer[ISO7816.OFFSET_INS]) {
        case INS_TEST3DES:
            processTest3DES(apdu);
        case INS_TESTSPEED:
            processTestSpeed(apdu);
        default: // For all other INS values, return an error code
            ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
        }
    }

    // Method that processes the send rate test command
    private void processTestSpeed(APDU apdu) {
        // Get a link to the buffer
        byte[] buffer = apdu.getBuffer();
        // Fill buffer with arbitrary bytes
        for (byte i = 0; i < 120; i++) {
            buffer[i] = i;
        }
         // Telling the Java machine to pass when exiting the process method
         // computer as
         // response buffer content starting from byte with index 0 and length 120
         // byte.
         // Don't forget that this method is called by process.
         // No immediate dispatch
        apdu.setOutgoingAndSend((short) 0, (short) 120);
    }

    private void processTest3DES(APDU apdu) {
        // Получаем ссылку на буфер
        byte[] buffer = apdu.getBuffer();

        // Encrypt the contents of the encryptBuffer, placing the result in buffer
        cipher.doFinal(this.enсryptBuffer, (short) 0,
                (short) this.enсryptBuffer.length, buffer, (short) 0);

        // Instruct to send data
        apdu.setOutgoingAndSend((short) 0, (short) this.enсryptBuffer.length);
    }
}

2. Some subtleties​


The applet class constructor is called only once - when loading the applet into the card and installing it.

The first thing you need to know when developing your applet is whether the Java Card API implementation on the card supports the garbage collector. If the garbage collector is not supported, then any object created with the new operator will remain stuck in the card memory forever. You will not be able to destroy it and free up the occupied memory (except by deleting the applet from the card).

One simple conclusion follows from this: if your card does not support garbage collection, all new statements must be located inside the constructor of the applet class (inside the method, with a name like the class itself). You will not be able to use new statements outside of this method. If you break this rule, after some time, when executing commands, the applet will start "spitting" errors and it will have to be overwritten.

But even if the garbage collector is supported by the card, it probably won't work automatically. You will need to call it manually in the applet. And this is quite a long process, which leads to fragmentation of the card memory.

The second point is the fragmentation of the card memory when managing applets. An applet in the card's memory is like a file on the hard disk. If you delete an applet that was written before any other applet, a "hole" of free space the size of the deleted applet will remain in the card's memory. Therefore, you need to follow simple rules:
  • If you don't want to delete some applets after writing to the card, write them first.
  • If some applets are supposed to be updated and others are written to the card after them, you will have to delete all of them and overwrite them before updating them.

The same goes for dynamic memory allocation on cards that support garbage collection. Although the collector destroys unused objects, it may not need to defragment the memory, because in the case of a card's EEPROM, this is a very long process.

The Java implementation for cards does not support at least:
  • types char, double, float, long, int, string;
  • the transient qualifier;
  • transfers
  • multidimensional arrays

Moreover, the lack of support for the int type leads to a rather ridiculous format for calling methods: apdu. setOutgoingAndSend((short) 0, (short) 120), since in Java numeric literals are int by default.

Errors in applet writing can occur at each of three levels: compilation ( * . java -> *. class), conversion (*.class -> *.cap), applet linking in the card (*.cap -> card). Be careful. You can write a huge applet, compile and convert it, and then find out that it is not being loaded into the card for some reason. Since debugging applets is difficult in this case, you can recommend commenting out parts of the applet and uploading it to the card until you come across the part that caused the error.

Some cards have a verifier (for example, CodeShield on the latest Schlumberger/Gemalto egate batches). This verifier additionally checks the applet code after it is loaded into the card at the installation stage (a characteristic sign of its presence — a long pause before receiving a response to the last download command-can reach up to a whole minute), creating additional hemorrhoids. For example, this verifier may require the mandatory presence of break in each case of the switch statement, preventing you from grouping two cases into one.

All members of the applet class are stored in the card's EEPROM. The number of rewriting cycles of this memory, although large (several hundred thousand cycles), is still limited. Cards have a certain amount of RAM, which can be allocated by calling Util. makeTransientArray (as the name suggests, memory is allocated as an array, and this allocation is also available on cards without a garbage collector. The memory allocated by makeTransientArray is released correctly in all cases (see the documentation)). Usually about 1Kb. Of course, working with this memory is faster than with EEPROM.

To get an idea of the features that are available to the applet, I suggest simply scrolling through the documentation included in the Javacard SDK.

3. Gratitude to patient readers​


Thank you to everyone who read this far. Thanks and indignation are accepted.

I will be glad to have any questions in the comments and try to update the article so that it includes answers.


Chapter 5. Security​


In 90% of cases, you will not be able to come up with an algorithm that has all the following properties:
  • if you removed this algorithm from the program, your software would become completely non-functional
  • a hacker would not be able to guess and emulate this algorithm

If you hit these 90%, then you should definitely:
  • Encrypt all communications with the card
  • Protect your software with a mounted Themida tread

1. Encryption of data exchange with the card​


If you want to build strong security, the traffic encryption keys must change. A new key should be generated at least every time your app is launched. Session keys should be generated based on data provided by both the card and your program. The mechanism of a secure session can look like this in a primitive version, for example:
  • There is a certain DES M master key. The card and software know it.
  • The card generates 4 bytes of random data (Ccard), soft generates 4 bytes of random data (Csoft). They exchange this information with each other.
  • The card and software combine both arrays (Ccard + Csoft), encrypt the resulting set of bytes with the master key M. This results in 8 bytes of the 1DES key, which will then encrypt the entire exchange in the current session.

Attention! In any case, do not do as described.

If the decrypted data appears incorrect to the card, it should be blocked. The easiest way to implement this option is to create a CardIsLocked boolean field in the applet class and check its contents in the process method before calling the method corresponding to the passed command code. If CardIsLocked — give the software an error instead of data.

2. Using Themida features​


Themida is considered to be one of the most difficult to remove treads. However, just hanging a projector on top is not enough. If you want to build really strong security, you should use the Themida API to its fullest extent:
  • Make sure to use the Themida instance mechanism for protection
  • Pay special attention to the Themida help section called "SecureEngine Macros". When developing your own secure session mechanism for communicating with the card, enclose all the code that provides communication with the card in macros such as VM_Start/End, Code_Replace_Start/End.
  • Usually, a secure data exchange session with the card is set up once when the app is launched. If this is also true in your case, put the code responsible for starting the protected session in the Clear_Start/End macros, so that after installing the protected session, the code that does this is removed from the process address space.
  • Use the CheckProtectionStart/End and CheckCodeIntegrityStart/End macros inside functions that work with the card.
  • Do not allow your program to run under virtual machines (unless your application requires it)

3. Cryptographic traps. A few of the millions waiting for you.​


When working with cryptography, it is important to understand what you are doing, what you can do, and what you can't do. Of course, if you use a smart card to protect your console Tetris, you can afford anything you want. But if this tetris game is unique and will bring you a million dollars tomorrow… Then, for example, once you use a specific initialization vector with a specific DES key, don't do it again.

Don't invent your own super-secret-unknown encryption and hashing algorithms. Remember the fate of the GSM A5 / 3 cipher and its poor authors, who decided that they were super-cryptographers.

Having designed a super-strong security system, do not leave stupid holes in it, like the one in a bank client based on BS-Client.

4. Gratitude to patient readers​


Thank you to everyone who read this far. Thanks and indignation are accepted.

I will be glad to have any questions in the comments and try to update the article so that it includes answers.
 
Last edited by a moderator:
Top