This is an implementation of a JavaCard ePurse. It is based on the template shared created by FractalizeR!
The project makes use of the Javacard Development Kit 2.2.1. Building is done using an Ant build script.
- Java Runtime Environment (JRE) and the Java Development Kit (JDK).
- GlobalPlatformPro (version
v0.3.4-29-g15d7427
), for accessing the applets on the JavaCard.
-
Install latest Java SDK.
-
Open project using IDEA’s
File -> Open project
-
Go to
File -> Project Structure -> SDKs
and add the SDK you installed in step 1. If there is already something, you can delete it before adding the newly installed SDK. -
Go to
File -> Project Structure -> Libraries
. Remove current Classes entry. Then add\lib\jc221\lib\api.jar
. -
Open
Common.properties
file and setup everything you need there according to the comments. This includes the path to SDK installation folder. Openbuild.xml
(this is an Ant build package so you need Ant plugin to be installed in IDEA) and correct the entries that follow${APPLETAIDPREFIX}
to suit your AID. -
To build the applet, go to use
View -> Tool Windows -> Ant Build
. A window will pop up on the right side of your screen. If you don't see any build targets, click on the green plus and select thebuild.xml
file. Usebinarize.all.standard
to build the applet for Gemalto TOPs and similiar. -
Target files will be placed in
\out\ePurse\javacard
-
If you have more than one applet in the project, edit
build.xml
and add a second entry under each tag with the info you need.
Now you can build your applet using IDEA's menu: Build -> Build Project
Q: IntelliJ does not autocomplete on the .jar
I imported
A: This is probaby because your sources are not specified as sources in the project itself. Go to File -> Project Properties
, click on Modules
.
Now click on the folder that contains your sources (src
in our case), and mark the folder as Resources.
Q: When I try to build and run the Terminal
module, I get one of the following errors: Cannot start compilation: the outpath path is not specified for module "Terminal". Specify the outpat path in Configure Project or Error: Could not find or load main class Terminal
A: This has something to do with the output path of the module. File -> Project Structure
(or CTRL + ALT + SHFT + S
for short), select the Terminal
module. In the tab Paths
, under Compiler ouput
select Inherit project compile output path
. On the left side, under Project Settings, click on Project
. On the bottom, you see Project compiler output
. This is the location where .class
files of the module will be put.
In your project, create an addition folder called classes
, and put the absolute location in this field (e.g. C:\Users\%USERNAME%\Documents\ePurse\out\classes
, where %USERNAME%
is your username).
Once done, click Apply
on the bottom and you should be good to go.
To access the applets on the card, put the card in the cardreader and connect the cardreader with the computer.
The following commands can now be used (where applet.cap
is the applet you want to install):
- List applet
java -jar gp.jar -list
- Install applet
java -jar gp.jar -install applet.cap
- Delete applet. An applet can be deleted by specifying the AID (Application Identifier) of the applet:
java -jar gp.jar --deletedeps --delete 3B2963616C6300
Here is a list of the errors the card can throw:
- SW_VERIFICATION_FAILED (0x6300)
- SW_PIN_VERIFICATION_REQUIRED (0x6301)
- SW_TERMINAL_VERIFICATION_FAILED (0x6302)
- SW_CARD_BLOCKED (0x6303)
- SW_WRONG_NONCE (0x6304)
- SW_NO_MORE_PIN_ATTEMPTS (0x6305)
Command APDU:
CLA | INS | P1 | P2 | Lc | Data field | Le |
---|---|---|---|---|---|---|
0x0 | 0xA4 | 0x04 | 0x0 | 0x08 | 0xA0, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x10, 0x01 | N/A |
Response APDU:
Optional | Status word | Meaning |
---|---|---|
No data | 0x9000 | Successful processing |
0x6999 | Applet selection failed |
In this part the terminal communicates the public key of the newly created card and requests a key
This consists of the following:
Payload: publickey card || expiration date (in seconds) || implicit request for Id
Response: card id
In this protocol we verify whether the card and the terminal are still valid
Command APDU:
CLA | INS | P1 | P2 | Lc | Data field | Le |
---|---|---|---|---|---|---|
0xB0 | 0x41 | 0x0 | 0x0 | 0x0 | 0x0 | N/A |
Plaintext: nonce Payload is: Plaintext
This is not signed because we don't have the public key of the terminal.
Response APDU:
Optional | Status word | Meaning |
---|---|---|
No data | 0xx9000 | Successful processing |
0x6300 | Verification failed |
Command APDU:
CLA | INS | P1 | P2 | Lc | Data field | Le |
---|---|---|---|---|---|---|
0xB0 | 0x41 | 0x0 | 0x0 | 0x0 | 0x0 | N/A |
Plaintext: nonce Payload is: Plaintext
This is not signed because we don't have the public key of the terminal.
Response APDU:
Optional | Status word | Meaning |
---|---|---|
No data | 0xx9000 | Successful processing |
0x6300 | Verification failed |
We send the received APDU of the card and the one crafted by the terminal to the backend for a verification.
PlaintextA: Nonce || CardId PlaintextB: Nonce+1 || TerminalId Payload: PlaintextA || [PlaintextA]_Signed || PlaintextB || [PlaintextB]_Signed
The backend does some checks and returns the public key of the card and the public key of the terminal, also signed by the backend:
PlaintextResponse = Nonce+2 || public key card (exponent + modulus) || public key terminal (exponent + modulus) PayloadResponse = [PlaintextResponse]_Signed
The terminal forwards the decom request signed by the card
Plaintext: Nonce+1 || CardId Payload: [Plaintext]_Signed
Response: [nonce incremented || Implicit OK] signed by the backend, this is forwarded to the smartcard
The terminal forwards the request of a card to view his balance
Plaintext: Nonce+1 || CardId Payload: [Plaintext]_signed
Response: [Nonce incremented || correct balance ] signed by the backend
See in reloading, response is similar
In this step the backened receives a commitment of card that it will pay a certain amount.
Plaintext: Nonce || CardId || Amount Payload: [Plaintext]_Signed
Response: [Nonce incremented || Implicit OK] signed by the backend
Command APDU:
CLA | INS | P1 | P2 | Lc | Data field | Le |
---|---|---|---|---|---|---|
0xB0 | 0x30 | 0x0 | 0x0 | 1 | Credit amount | N/A |
Response APDU:
Optional | Status word | Meaning |
---|---|---|
No data | 0xx9000 | Successful processing |
0x6301 | PIN verification required | |
0x6A83 | Invalid credit amount | |
0x6A84 | Exceed the maximum amount |
Command APDU:
CLA | INS | P1 | P2 | Lc | Data field | Le |
---|---|---|---|---|---|---|
0xB0 | 0x40 | 0x0 | 0x0 | 1 | Debit amount | N/A |
Response APDU:
Optional | Status word | Meaning |
---|---|---|
No data | 0xx9000 | Successful processing |
0x6301 | PIN verification required | |
0x6A83 | Invalid debit amount | |
0x6A85 | Negative balance |
Command APDU:
CLA | INS | P1 | P2 | Lc | Data field | Le |
---|---|---|---|---|---|---|
0xB0 | 0x20 | 0x0 | 0x0 | Length of the PIN data | PIN data | N/A |
Response APDU:
Optional | Status word | Meaning |
---|---|---|
No data | 0xx9000 | Successful processing |
0x6300 | Verification failed |