I. Présentation de Java Card▲
I-A. Introduction des cartes à puce▲
I-A-1. Exemples d'utilisations▲
On retrouve les cartes à puce dans plusieurs domaines. On cite quelques exemples de cartes :
- carte bancaire : Carte Bleue (France), MasterCard (USA) ;
- carte d'assurance maladie : Vitale (France) ;
- porte-monnaie électronique : Moneo (France) ;
- carte étudiant ;
- carte SIM.
I-A-2. Types de cartes▲
Il existe deux grandes familles de cartes à puce :
-
cartes synchrones : ce type de cartes est doté soit d'une mémoire EPROM soit d'une mémoire EEPROM
- carte à mémoire EPROMErasable Programming Only Memory : ce type de cartes peut être effacée et reprogrammée plusieurs fois. Le processus d'effacement et de reprogrammation nécessite le déplacement de la carte vers un support physique dédié à cette opération. Elle est utilisée comme une carte de prépaiement du téléphone ; dans ce cas, elle est considérée comme carte jetable. Elle peut aussi servir de carte d'identification utilisée pendant des années,
- carte à mémoire EEPROMElectrical Erasable Programming Only Memory : c'est une carte EPROM, mais elle possède l'avantage d'être effacée et reprogrammée sans qu'il soit nécessaire de la retirer du support ou de l'appareil qui l'utilise. Elle est souvent utilisée comme carte de fidélité ;
-
cartes asynchrones : appelées aussi cartes à microcontrôleur. Ce type de cartes est composé de :
- unité centrale de microprocesseur,
- mémoire morte : PROMProgrammable Read Only Memory,
- mémoire vive : RAMRandom Access Memory,
- mémoire EEPROM,
- interface d'entrée/sortie,
- un cryptoprocesseur.
Avec ce type de carte, toutes les applications sont possibles et imaginables comme les cartes bancaires, porte-monnaie électroniques, cartes de santé, etc.
Parmi les types de cartes asynchrones, on retrouve les Smart Cards.
On distingue deux manières de communication avec une carte à puce :
- carte à puce avec contact en utilisant la norme ISO 7816 ;
- carte à puce sans contact en utilisant la norme ISO 1443 ou la norme ISO 15693.
I-A-3. Architecture d'une Smart Card avec contact▲
La carte est composée de 8 connecteurs selon la norme ISO 7816 représentée comme suit :
- VCC : tension d'alimentation de la carte fournie par le lecteur ;
- RST (Reset) ;
- CLK : horloge ;
- GND (Ground) : masse ;
- VPP : tension de programmation fournie par le lecteur (inutilisé aujourd'hui) ;
- I/O : entrée/sortie des données ;
- RFU (Reserved for Future Use) : connecter d'autres composants.
I-B. C'est quoi Java Card ?▲
I-B-1. Hardware▲
Java Card est une carte asynchrone de type Smart Card. Donc elle possède une mémoire EEPROM. Les cartes standard ont une EEPROM de taille variant de 1 Ko à 128 Ko. Tandis que la carte Java Card est distinguée d'une EEPROM de taille égale à 256 Ko due à la présence de la machine virtuelle.
I-B-2. Software▲
Java Card est un langage de programmation spécifique à la réalisation des cartes à puce de type Java Card.
Le langage Java Card est une version allégée du langage de programmation Java. Comme l'espace mémoire alloué dans la carte est de taille réduite, il y a certaines caractéristiques qui ne sont pas supportées par Java Card telles :
- les types simples : int, float, double… à l'exception du byte, short et boolean ;
- les chaînes de caractères ;
- manipulation des tableaux multidimensionnels ;
- multithreading ;
- garbage collector (supporté uniquement à partir de la version 2.2 de Java Card).
- Le programme réalisé en Java Card est appelé une Applet ou bien Cardlet. Les applets sont chargées sur la carte dans l'EEPROM. L'espace mémoire utilisé par l'applet est appelé Sandbox.
Pour pouvoir exécuter une applet, il faut avoir un minimum de caractéristiques de la carte Java Card :
- μp : 30 KI/s ;
- ROM : 12 Ko ;
- RAM : 512 Ko ;
- EEPROM : un minimum de 4 ko .
Java Card comporte les versions 1.0, 2.0 et 3.0 sortie récemment.
On utilisera par la suite la version 2.0 de Java Card qui est la plus stable.
I-B-3. Architecture de Java Card▲
- La gestion du matériel se fait à travers les méthodes natives de bas niveau (écrire dans la RAM, lire à partir de la RAM, gestion de la mémoire, etc.). Ce sont des méthodes de base et existent toujours.
- L'interpréteur (JVM) permet d'exécuter les applets sélectionnées.
- Standard Class Librairies est un ensemble d'APIApplication Programming Interface provenant du Java Card Framework et contenant les classes nécessaires à la création d'une applet telle que (APDU, AID, Applet, etc.).
- Card Executive permet de charger l'applet sur la carte.
- Il peut coexister une ou plusieurs applets sur la même carte. Ce sont des cartes multiservices (exemple : carte étudiant + carte Moneo). Une seule applet à la fois est exécutée.
Native methods + JVM + API + Card executive => Java Card Runtime Environment.
I-B-4. Framework Java Card▲
Java Card comporte quatre packages :
- javacard.framework : comporte les classes les plus importantes telles que APDU, AID, PIN, ISO, etc. ;
- javacardx.framework : comporte des classes telles que DedicatedFile, elm EntryFile ;
- javacardx.crypto : c'est un package qui contient des classes de cryptographie ;
- javacardx.cryptoEnc : c'est un package qui contient d'autres classes de cryptographie.
I-B-5. Cycle de vie d'une applet▲
Hors Carte
Étape 1 :
Implémenter le code de l'applet sous un éditeur tel que Eclipse en important les API nécessaires existant dans le SE. Un fichier d'extension .java est obtenu.
Étape 2 :
Compiler le fichier .java à l'aide du compilateur javac existant sous le JDKJava Development Kit. On obtient un fichier .class qui contient du byte code Java et un fichier .link qui permet de faire la liaison avec les API appelées.
Étape 3 :
Le convertisseur existant sous JCDKJava Card Development Kit permet de convertir les deux fichiers .class et .link en un nouveau fichier d'extension .cap contenant du byte code Java Card.
Dans la Carte
Étape 4 :
Cette étape consiste à charger le fichier .cap obtenu précédemment dans notre carte à puce de type Java Card. La JCRE alloue un espace mémoire dans l'EEPROM appelé sandbox pour l'applet à charger.
Étape 5 :
La JCRE fait appel à la méthode install(). Cette méthode permet de :
- créer une instance de l'applet ;
- réaliser l'identification de l'applet grâce à l'AIDApplication ID ;
- enregistrer l'applet.
Communication carte-lecteur
Étape 6 :
Un APDU est un format de communication entre la carte à puce et le lecteur de cartes. Donc pour pouvoir communiquer avec l'applet souhaitée, le lecteur initie la communication en envoyant un APDU de sélection. Ce dernier contient l'AIDApplication ID de l'applet à sélectionner. Si tout est correct, la carte renvoie un APDU de réponse indiquant le succès de l'opération.
La JCREJava Card Runtime Environment sélectionne l'applet en utilisant la méthode select().
Étape 7 :
Ensuite le lecteur poursuit la communication en envoyant des APDU de commande pour interroger la carte. La méthode process() a pour rôle de gérer les différents APDU de commandes. À noter que cette dernière gère aussi la réception de l'APDU de sélection. Une réponse est retournée selon la commande demandée par le CAD Card Access Device(lecteur).
II. Préparation de l'environnement▲
II-A. Installation de l'éditeur▲
Il faut avoir un éditeur pour pouvoir implémenter et tester notre applet.
- On choisit l'éditeur Eclipse IDE for Java Developpers.
II-A-1. Téléchargement▲
Selon votre Système d'exploitation, choisissez le lien correspondant :
Windows 32 bits :
Windows 64 bits :
II-A-2. Manipulation▲
Décompresser le fichier .zip téléchargé sous C:\Eclipse.
- Vérifier l'existence du fichier Eclipse.exeet du dossier plugins.
- De préférence, on place le dossier workspace, qui contiendra tous les projets, sous C:\Eclipse.
II-B. Installation de JDK▲
II-B-1. Téléchargement▲
On installe la version 7 de JDK (à choisir le dernier update).
Windows 32 bits/64 bits :
http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html
II-B-2. Manipulation▲
Installer le fichier téléchargé.
- L'espace présent dans le mot Program Files du chemin de JDK présente une éventuelle source de problèmes lors de la compilation.
- Pour y remédier, on change l'emplacement de C:\Program Files\Java vers C:\Java.
Ensuite, on ajoute une variable d'environnement JAVA_HOME pour pouvoir compiler dans la console sans souci du chemin actuel.
Le processus d'ajout de la variable d'environnement se fait comme suit :
- Cliquer avec le bouton droit sur l'icône de Poste de travail, puis sur Propriétés > Paramètres système Avancés > Variables d'environnement.
- Dans la zone Variable Utilisateur, on crée une nouvelle variable d'environnement nommée JAVA_HOME contenant le chemin C:\Java\jdk1.7.0_67 (varie selon votre version d'update de JDK).
- Dans la zone Variable Système, on modifie la variable Path en ajoutant à la fin %JAVA_HOME%\bin;.
- %JAVA_HOME% représente le contenu de la variable JAVA_HOME.
Il faut faire attention lors de la manipulation de la variable Path pour ne pas effacer l'ancien contenu.
Pour vérifier le bon fonctionnement, on tape la commande javacdans la console DOS.
En cas de dysfonctionnement de l'ajout de la variable d'environnement JAVA_HOME, on procède par un forçage de fonctionnement en ajoutant directement dans la variable PATH le chemin d'accès C:\Java\ jdk1.7.0_67\bin; .
II-C. Installation de JCDK▲
II-C-1. Téléchargement▲
On installe la version 2.2.2 de JCDK Java Card Development Kit( la plus stable).
Windows 32 bits/64 bits :
II-C-2. Manipulation▲
Sous C:\JCDKdézipper le fichier téléchargé.
Sous C:\JCDK\java_card_kit-2_2_2 dézipper directement les 4 fichiers .zip.
Ensuite, ajouter la variable d'environnement JC_HOME.
Le processus d'ajout de la variable d'environnement se fait comme suit :
- Cliquer avec le bouton droit sur l'icône du Poste de travail, puis sur Propriétés > Paramètres> système Avancés > Variables d'environnement.
- Dans la zone Variable Utilisateur, on crée une nouvelle variable d'environnement nommée JC_HOME contenant le chemin C:\JCDK\java_card_kit-2_2_2.
- Dans la zone Variable Système, on modifie la variable Path en ajoutant %JC_HOME%\bin; .
Pour vérifier le bon fonctionnement, on tape par exemple la commande converter sous DOS.
En cas de dysfonctionnement de l'ajout de la variable d'environnement JC_HOME, on procède par un forçage de fonctionnement en ajoutant directement dans la variable PATH le chemin d'accès C:\JCDK\java_card_kit-2_2_2\bin;.
II-D. Ajout des plugins Eclipse-JCDE▲
II-D-1. Téléchargement▲
Windows 32 bits/64 bits :
http://sourceforge.net/projects/eclipse-jcde/files/latest/download?source=files
II-D-2. Manipulation▲
Dézipper le fichier téléchargé dans le dossier C:\Eclipse\plugins.
Deux dossiers sont ajoutés Plugins et _MACOSX.
Transférer le contenu de C:\Eclipse\plugins\plugins vers C:\Eclipse\plugins.
III. Application serveur▲
III-A. Langage Java Card▲
III-A-1. AID▲
L'AIDApplication ID permet d'identifier une applet installée sur la carte.
Une carte peut contenir une ou plusieurs applets. La sélection de l'applet souhaitée se fait à travers son AID.
Il existe aussi un AID pour les packages.
L'AID est composé de deux parties :
- RID (5 octets) : une compagnie obtient son propre et unique RID de la norme ISO;
- PIX (0 - 11 octets) : chaque compagnie affecte des PIX selon son choix à ses applets.
D'autre part, il existe des AID par défaut attribués par la norme ISO.
III-A-2. APDU▲
La communication reliant le lecteur avec la carte se fait à travers l'APDU.
C'est toujours le lecteur qui initie la communication avec la carte et non le contraire.
Il existe trois types d'APDU :
- APDU de commande: c'est à travers cet APDU que le lecteur demande l'action souhaitée. Par exemple incrémenter un compteur.
La forme de l'APDU est comme suit :
- C: classe de l'applet ;
- INS: instruction ;
- P1, P2 : paramètres ;
- Lc: taille du champ data ;
- Data field : la data envoyée dans l'APDU;
- Le: taille de DATA reçu dans la réponse de la carte .
Exemple d'un APDU :
C'est un tableau d'octets (byte[])
- Les champs sont en format hexadécimal.
- Les valeurs de CLA et INS sont déclarées dans notre applet où on définit leurs valeurs nous-même.
- P1 et P2 sont généralement envoyés à 0.
- La longueur de la data est égale à 2, défini par le champ Lc.
- Le champ data comporte donc deux valeurs qui sont envoyées dans l'APDU.
- Le champ Le définit la taille 7F (en hexadécimale) équivalent de 127 octets en valeur décimale.
- APDU de sélection : il permet de sélectionner l'applet souhaitée en fonction de son AID.
L'APDU de sélection est caractérisé par :
- CLA= 0x00 ;
- INS = 0xA4 ;
- P1= 0x04 & P2 = 0x00 ;
- Lc= 0x0B qui est égal à 11 octets au format décimal => taille de l'AID ;
- Data contient l'AID de l'applet à sélectionner. Ceci est l'AID par défaut attribué par la norme ISO ;
- Le= 0x7F ;
- APDU de réponse : c'est l'APDU envoyé par la carte pour répondre au lecteur. Il est composé de deux champs nommés SW1et SW2 qui retournent l'état du traitement de l'APDU envoyé par le lecteur.
SW1 = 0x90 & SW2 = 0x00 => Si le traitement est effectué avec succès. Sinon ils renvoient d'autres valeurs. Chaque valeur correspond à une erreur définie dans la norme ISO7816.
On retrouve dans le lien ci-dessous plusieurs valeurs de SW ainsi que l'erreur correspondante.
http://www.win.tue.nl/pinpasjc/docs/apis/jc222/javacard/framework/ISO7816.html
L'APDU de réponse peut contenir aussi un champ DATA. Mais uniquement lorsqu'on veut récupérer une valeur.
III-B. Application serveur▲
L'application serveur représente l'applet. On implémente une application qui effectue quatre opérations sur un compteur : incrémentation, décrémentation, interrogation et initialisation du compteur par une valeur donnée.
III-B-1. Création de l'applet▲
Pour créer un projet Java Card : File > New > Other > Java Card > Java Card Projet.
Créer un projet Java Card nommé TP JC App Serveur.
Manque d'une bibliothèque de Java Card.
Il faut ajouter le chemin du dossier lib contenu dans C:\JCDK\java_card_kit-2_2_2.
Pour créer une applet Java Card => File > new > Other > Java Card > Java Card Applet.
Nom du package : monpackage.
Nom de l'applet : MonApplet.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
package
monpackage;
import
javacard.framework.APDU;
import
javacard.framework.Applet;
import
javacard.framework.ISOException;
public
class
App extends
Applet {
private
App
(
) {
}
public
static
void
install
(
byte
bArray[], short
bOffset, byte
bLength)
throws
ISOException {
new
App
(
).register
(
);
}
@Override
public
void
process
(
APDU arg0) throws
ISOException {
// TODO Auto-generated method stub
}
}
Il faut supprimer le mot @Override pour éliminer l'erreur.
Dans la méthode process(APDU arg0) générée, on remplace arg0 par apdu.
Finalement, on attribue un AID par défaut à l'applet. Cliquer le bouton droit sur monpackage > Java Card Tools > Set Package AID.
III-B-2. Code▲
Explication détaillée du code :
2.
3.
4.
import
javacard.framework.APDU;
import
javacard.framework.Applet;
import
javacard.framework.ISOException;
import
javacard.framework.ISO7816;
Eclipse génère les quatre classes ci-dessus depuis javacard.framework.
- javacard.framework.APDU : APDU est une classe contenant plusieurs méthodes parmi lesquelles on utilisera quelques-unes.
- javacard.framework.Applet : la classe Applet contient la méthode install() dont notre applet hérite.
- javacard.framework.ISOException : cette classe traite les exceptions rencontrées lors de la communication avec les APDU.
- javacard.framework.ISO7816 : cette classe contient différentes constantes parmi elles les SW correspondant aux erreurs de traitement des APDU.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
Public class
MonApplet extends
Applet {
/******************** Constantes ************************/
public
static
final
byte
CLA_MONAPPLET=
(
byte
) 0xB0
;
public
static
final
byte
INS_INCREMENTER_COMPTEUR=
0x00
;
public
static
final
byte
INS_DECREMENTER_COMPTEUR=
0x01
;
public
static
final
byte
INS_INTERROGER_COMPTEUR=
0x02
;
public
static
final
byte
INS_INITIALISER_COMPTEUR=
0x03
;
/*********************** Variables ***************************/
private
byte
compteur;
L'applet doit hériter de la classe Applet.
On déclare le CLA de notre applet à une valeur de 0xB0.
On a quatre opérations à réaliser avec le compteur. Donc on doit déclarer quatre INS :
- INS_INCREMENTER_COMPTEUR ayant une valeur 0x00 ;
- INS_DECREMENTER_COMPTEUR ayant une valeur 0x01 ;
- INS_INTERROGER_COMPTEURayant une valeur 0x02 ;
- INS_INITIALISER_COMPTEUR ayant une valeur 0x03 .
Les valeurs et l'ordre des déclarations sont librement choisis.
Un warning apparaît lorsqu'on utilise un INS supérieur ou égal à 0x60 prévenant que cet INS peut ne pas être supporté par la carte.
On rappelle que :
1 byte = 1 octet = 8 bits
1 short = 2 byte = 16 bits
2.
3.
4.
5.
6.
7.
8.
9.
/************ Constructor **************/
private
MonApplet
(
) {
compteur=
0
;
}
public
static
void
install
(
byte
bArray[], short
bOffset, byte
bLength)
throws
ISOException {
new
MonApplet
(
).register
(
);
}
La méthode install() est évoquée pour pouvoir installer l'applet sur la carte.
Elle fait appel au constructeur MonApplet() et crée une nouvelle instance de l'applet puis fait appel à la méthode register() pour l'enregistrer dans la carte.
Les paramètres de install() :
- bArray[] : tableau de type byte ;
- bOffset: un short indiquant la position de lecture dans bArray[] ;
- bLength : un byte indiquant la longueur de Data à lire dans bArray[]. La méthode process(APDU apdu) est la méthode principale qui va gérer toutes les opérations. Elle reçoit en paramètre l'objet apdu de la classe APDU.
2.
3.
4.
public
void
process
(
APDU apdu) throws
ISOException {
byte
[] buffer=
apdu.getBuffer
(
);
if
(
buffer[ISO7816.OFFSET_CLA]!=
CLA_MONAPPLET)
ISOException.throwIt
(
ISO7816.SW_CLA_NOT_SUPPORTED);
La méthode apdu.getBuffer() permet d'extraire les cinq premiers champs de l'APDU envoyé : CLA, INS, P1, P2 et Lc.
La méthode process() reçoit l'APDU de commande et l'APDU de sélection.
Elle ne traite que l'APDU de commande, donc elle doit renvoyer l'APDU de sélection.
On utilise la méthode this.selectingApplet() qui retourne Truesi l'apdu entré est un APDU de sélection. Dans ce cas, on doit quitter.
Lorsque l'instruction return est exécutée, on sort de la méthode et comme le type de retour de la méthode process() est void donc on ne retourne rien return ; .
La première étape à réaliser est de vérifier si le CLA entré en APDU de commande correspond à notre applet. Le CLA se trouve dans le buffer (qui contient les cinq premiers champs de l'APDU). Pour y accéder, on utilise buffer[ISO7816.OFFSET_CLA].
Puis on le compare avec notre CLA_MONAPPLET (déclaré constante de valeur 0xB0).
S'il existe une différence alors une exception de ISO7816.SW_CLA_NOT_SUPPORTEDest propagée par le process().
À noter que le SW_CLA_NOT_SUPPORTED est une constante prédéfinie dans la classe ISO7816 ayant une valeur égale à 0x6E00. Cette valeur est retournée à travers l'APDU de réponse et précisément dans les champs : SW1 = 0x6E et SW2=0x00.
2.
3.
4.
5.
switch
(
buffer[ISO7816.OFFSET_INS]){
case
INS_INCREMENTER_COMPTEUR:
compteur++
;
break
;
On traite selon la valeur de l'INS envoyée en APDU de commande.
On accède à l'INS en utilisant buffer[ISO7816.OFFSET_INS].
Les valeurs possibles sont : 0x00 / 0x01 /0x02 / 0x03 ayant leur nom de constante équivalant.
Dans l'APDU de réponse, on obtient juste SW1 et SW2 qui indiqueront respectivement 0x90et 0x00 en cas de réussite.
2.
3.
Case INS_DECREMENTER_COMPTEUR:
compteur--
;
break
;
Dans l'APDU de réponse, on obtient juste SW1 et SW2 qui indiqueront respectivement 0x90 et 0x00 en cas de réussite.
2.
3.
4.
case
INS_INTERROGER_COMPTEUR:
buffer[0
]=
compteur;
apdu.setOutgoingAndSend
((
short
)0
, (
short
) 1
);
break
;
Si l'INS correspond à la valeur 0x02 donc interrogation du compteur.
L'interrogation du compteur nécessite une DATA retournée dans l'APDU de réponse.
Le buffer utilisé pour la récupération de l'APDU de commande est lui-même utilisé en APDU de réponse.
On utilise la première case du buffer en lui affectant la valeur du compteur (en écrasant la valeur du CLA contenue auparavant dans buffer[0] mais qui est sans intérêt dans cette étape).
On rappelle que l'APDU de réponse contient DATA + SW1 + SW2 et que le champ DATA est facultatif selon les besoins.
La méthode apdu.setOutgoingAndSend() permet d'envoyer l'APDU de réponse en utilisant le buffer.
Void setOutgoingAndSend( short bOff , short len )
Le premier paramètre bOff indique la position de lecture à partir du buffer. On a affecté la valeur du compteur à la case 0.
Le deuxième paramètre reflète la longueur du Data à envoyer. On a un seul byte à envoyer donc la valeur est 1.
2.
3.
4.
case
INS_INITIALISER_COMPTEUR:
apdu.setIncomingAndReceive
(
);
compteur=
buffer[ISO7816.OFFSET_CDATA];
break
;
Dans ce cas, on aura un APDU de commande contenant dans le champ DATA une valeur qu'on affectera au compteur.
La méthode apdu.setIncomingAndReceive() permet d'aspirer la DATA d'un seul coup si elle est de taille réduite.
Maintenant, le champ Data est ajouté au buffer et on peut y accéder à travers buffer[ISO7816.OFFSET_CDATA] et on affecte la valeur passée par l'APDU dans compteur.
III-C. Simulation▲
Avant de commencer la simulation, on génère le script en cliquant sur le bouton droit sur le nom du package > Java Card Tools > Generate script.
Erreur de compilation.
Il faut changer le compilateur de 1.7 vers 1.5 qui est supporté par Java Card.
- Project > Properties > Java Compiler .
- Cocher Enable project specific settings.
- Changer 1.7 par 1.5.
- Régénérer le script une autre fois.
On obtient plusieurs fichiers, dont create-MonApplet.script et select-MonApplet.script utilisés ultérieurement pour l'installation et la sélection de l'applet.
Il existe deux types de simulateurs.
III-C-1. JCWDE▲
Le simulateur JCWDE ne conserve pas l'état de la carte après la modification de la valeur du compteur.
- Lancer le simulateur JCWDE sur Eclipse en appuyant sur Start (barre de menu).
- Ouvrir l'invite de commande et taper la commande apdutool.
- Sélection de l'installeur d'applets : APDU existant dans le fichier create-MonApplet.script.
Il ne faut pas emporter powerdown ; .
=> APDU de sélection réussi : sw1 : 90 , sw2 :00
- Création de l'applet : APDU existant dans le fichier create-MonApplet.script.
=> APDU de commande réussi : sw1 : 90 , sw2 :00
- Sélection de l'applet : APDU existant dans le fichier select-MonApplet.script.
=> APDU de sélection réussi : sw1 : 90 , sw2 :00
Consulter la valeur du compteur : CLA=0xB0 et INS= 0x02
=> La valeur du compteur est contenue dans le champ DATA de l'APDU de réponse qui retourne 0.
Incrémenter la valeur du compteur : CLA=0xB0 et INS= 0x00.
Puis consulter la valeur du compteur : CLA=0xB0 et INS= 0x02.
=> Dans la DATA du l'APDU de réponse, on récupère la valeur 01.
Initialiser la valeur du compteur à 0x4A = 74: CLA=0xB0 et INS= 0x03.
Décrémenter la valeur du compteur : CLA=0xB0 et INS= 0x01.
Puis consulter la valeur du compteur : CLA=0xB0 et INS= 0x02
=> La réponse est 49 = 73 en décimal, donc opération de décrémentation réussie.
III-C-2. CREF▲
Le simulateur CREF est caractérisé par la conservation de l'état de la carte après la fin de simulation.
Le simulateur possède parmi ses options :
-o nomfichier.eeprom: enregistrer l'état de la carte dans un fichier eeprom ;
-i nomfichier.eeprom : initialiser la carte à partir du fichier eeprom précédemment crée.
Les étapes de simulation :
- ouvrir l'invite de commande et taper la commande « cref -o monapplet.eeprom ».
=> Initialement le fichier monapplet.eeprom est vide. Après le lancement de la commande ci-dessus, toute opération effectuée sur la carte sera enregistrée dans le fichier ;
- réaliser l'upload de l'applet directement sur Eclipse : monpackage > Java Card Tools > Deploy
Le fichier monapplet.eeprom contient à présent le chargement de l'applet ;
- il faut relancer l'invite de commande et taper la commande : cref -i monapplet.eeprom -o monapplet.eeprom .
=> On initialise la carte à partir du fichier monapplet.eeprom (qui contient le chargement de la carte) et on prépare l'enregistrement de la carte de(s) opération(s) suivante(s) ;
- sous Eclipse, on installe l'applet en cliquant avec le bouton droit sur create-MonApplet.script puis Java Card Tools > Run Script.
=> L'installation de l'applet est, par conséquent, enregistrée dans le fichier eeprom.
Dans la console, retaper la commande cref -i monapplet.eeprom -o monapplet.eeprom .
Ouvrir une deuxième console et taper la commande apdutool.
Sous notre projet, monpackage.javacard >select-MonApplet.script, sélectionner l'APDU de sélection et le taper à la suite de apdutool.
=> Sélection de l'APDU avec succès SW1 :90 , SW2 : 00
Incrémenter le compteur : CLA = 0xb0 et INS = 0x00
=> La valeur actuelle du compteur devient égale à 1.
=> Cette valeur est enregistrée dans le fichier eeprom.
Pour tester la conservation d'état, on ferme la simulation et on reprend juste l'étape de sélection de l'APDU, car le chargement et l'installation sont déjà enregistrés dans la le fichier eeprom. Il suffit d'initialiser la carte depuis le fichier eeprom.
Dans la console, retaper la commande cref -i monapplet.eeprom -o monapplet.eeprom.
Ouvrir une deuxième console et taper la commande apdutool .
Sous notre projet, monpackage.javacard > select-MonApplet.script, sélectionner l'APDU de sélection et le taper à la suite de apdutool.
Consulter la valeur du compteur : CLA = 0xb0 ; INS = 0x02.
Effectivement, on obtient la valeur 1 dans l'APDU de réponse.
IV. Application client▲
IV-A. Programmation▲
IV-A-1. Création du projet▲
IV-A-1-a. Création nouveau projet▲
Créer un nouveau projet java nommé TP JC App Client .
IV-A-1-b. Ajout bibliothèque apduio.jar▲
La bibliothèque apduio.jar contient les classes permettant la communication avec notre application serveur Java Card précédemment implémentée.
Cette bibliothèque existe sous C:\JCDK\java_card_kit-2_2_2\lib .
Cliquer sur le bouton droit de projet > Propriétés > Java Build Path.
Cliquer sur Add External JARs et sélectionner la bibliothèque apduio.jar.
IV-A-1-c. Ajout de classe▲
Créer d'abord un nouveau package nommé monpackageclient.
Ensuite, créer une nouvelle classe nommée MaClasse.
IV-A-2. Code▲
Explication détaillée du code :
2.
3.
4.
5.
6.
public
class
MaClasse {
private
static
final
byte
CLA_MONAPPLET =
(
byte
) 0xB0
;
public
static
final
byte
INS_INCREMENTER_COMPTEUR=
0x00
;
public
static
final
byte
INS_DECREMENTER_COMPTEUR=
0x01
;
public
static
final
byte
INS_INTERROGER_COMPTEUR=
0x02
;
public
static
final
byte
INS_INITIALISER_COMPTEUR=
0x03
;
Dans la classe MaClasse, on déclare le CLA de l'applet compteur ainsi que les différents INS dont on aura besoin à la suite selon le type d'opération souhaitée.
Ils possèdent les mêmes valeurs que celles déclarées dans l'application serveur et ce, afin de garantir la communication entre le client et le serveur.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
public
static
void
main
(
String[] args) throws
IOException, CadTransportException {
CadT1Client cad;
Socket sckClient;
/**************** Connexion à la carte ****************/
try
{
sckClient=
new
Socket
(
"localhost"
,9025
);
sckClient.setTcpNoDelay
(
true
);
BufferedInputStream input=
new
BufferedInputStream
(
sckClient.getInputStream
(
));
BufferedOutputStream output=
new
BufferedOutputStream
(
sckClient.getOutputStream
(
));
cad=
new
CadT1Client
(
input,output);
}
catch
(
Exception e){
System.out.println
(
"Impossible de se connecter à la carte"
);
return
;
}
- Instanciation d'un Socket pour la connexion au localhost sur le port 9025.
- Éliminer le temps d'attente et l'envoi du packet directement.
- Récupérer l'input stream (flux de données) du socket.
- Récupérer l'output stream du socket.
- Instance du lecteur de carte.
- En cas d'erreur de connexion, un message est affiché.
2.
3.
4.
5.
6.
7.
8.
/************* Mise sous tension de la carte ******************/
try
{
cad.powerUp
(
);
}
catch
(
Exception e){
System.out.println
(
"Erreur lors de l'envoi de la commande powerup à la carte"
);
return
;
}
Mise sous tension de la carte avec la méthode powerUp().
Un message d'erreur est affiché en cas d'erreur de mise sous tension.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
/********* Sélection de l'applet: Commande APDU de type SELECT *********/
Apdu apdu =
new
Apdu
(
);
apdu.command[Apdu.CLA] =
0x00
;
apdu.command[Apdu.INS] =
(
byte
) 0xA4
;
apdu.command[Apdu.P1] =
0x04
;
apdu.command[Apdu.P2] =
0x00
;
byte
[] appletAID =
{
0x01
, 0x02
, 0x03
, 0x04
, 0x05
, 0x06
,0x07
, 0x08
, 0x09
, 0x00
, 0x00
}
;
apdu.setDataIn
(
appletAID);
cad.exchangeApdu
(
apdu);
if
(
apdu.getStatus
(
) !=
0x9000
) {
System.out.println
(
"Erreur lors de la sélection de l'applet"
);
System.exit
(
1
);
}
L'étape suivante consiste dans la sélection de l'applet souhaitée. On rappelle que la sélection est réalisée grâce à un Apdu de sélection comportant l'AID de l'applet.
Avant d'envoyer un Apdu, on doit remplir ses différents champs.
Remplir le tableau apdu.command comme suit :
apdu.command[Apdu.CLA] = 0x00;
apdu.command[Apdu.INS] = (byte) 0xA4;
apdu.command[Apdu.P1] = 0x04;
apdu.command[Apdu.P2] = 0x00;
- Ce sont les valeurs propres à l'APDU de sélection
Déclarer un tableau de bytes et l'initialiser avec l'AID de l'applet dans l'application serveur. La valeur de l'AID correspondant à l'AID par défaut généré par la norme ISO7816.
Le rôle de la méthode apdu.setDataIn(appletAID) est de remplir le champ Data de la commande apdu ainsi que la taille correspondante c.-à-d. le champ Lc.
Finalement l'envoi de l'apdu vers la carte se fait à travers la méthode apdu.exchangeApdu(apdu).
La méthode apdu.getStatus() récupère les SW envoyés dans l'apdu de réponse par la carte. Si le getStatus() est différent de 0x9000 signifie qu'il existe une erreur.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
/************************* Menu principal ***************************/
boolean
fin=
false
;
while
(!
fin){
System.out.println
(
);
System.out.println
(
"Application client JavaCard"
);
System.out.println
(
"---------------------------"
);
System.out.println
(
);
System.out.println
(
"1- Interroger le compteur"
);
System.out.println
(
"2- Incrementer le compteur"
);
System.out.println
(
"3- Decrementer le compteur"
);
System.out.println
(
"4- Reinitialiser le compteur"
);
System.out.println
(
"5- Quitter"
);
System.out.println
(
"Votre choix :"
);
int
choix =
System.in.read
(
);
while
(!(
choix >=
'1'
&&
choix<=
'5'
)) {
choix =
System.in.read
(
);
}
2.
3.
4.
5.
apdu=
new
Apdu
(
);
apdu.command[Apdu.CLA]=
MaClasse.CLA_MONAPPLET;
apdu.command[Apdu.P1]=
0x00
;
apdu.command[Apdu.P2]=
0x00
;
apdu.setLe
(
0x7F
);
Selon l'opération choisie, on envoie l'apdu correspondant à l'applet. Mais pour toutes les opérations citées, il existe des champs en commun. Donc on remplit les champs CLA , P1 , P2 et Le à part.
2.
3.
4.
5.
6.
7.
8.
9.
switch
(
choix) {
case
'1'
:
apdu.command[Apdu.INS] =
MaClasse.INS_INTERROGER_COMPTEUR;
cad.exchangeApdu
(
apdu);
if
(
apdu.getStatus
(
) !=
0x9000
)
System.out.println
(
"Erreur : status word different de 0x9000"
);
else
System.out.println
(
"Valeur du compteur : "
+
apdu.dataOut[0
]);
break
;
Ensuite, selon le choix dans le menu, on affecte l'INS correspondant dans l'apdu de commande.
Le premier choix correspondant à l'interrogation du compteur.
Il n'existe pas de Data dans ce cas, mais on recevra une Data dans l'apdu de réponse.
En cas de bon déroulement , on affiche sur la console la valeur du compteur.
2.
3.
4.
5.
6.
7.
8.
case
'2'
:
apdu.command[Apdu.INS] =
MaClasse.INS_INCREMENTER_COMPTEUR;
cad.exchangeApdu
(
apdu);
if
(
apdu.getStatus
(
) !=
0x9000
)
System.out.println
(
"Erreur : status word different de 0x9000"
);
else
System.out.println
(
"OK"
);
break
;
Le deuxième choix consiste à incrémenter le compteur.
De même cette opération ne nécessite pas de Data. Donc il suffit d'affecter l'INS correspondant et d'envoyer l'apdu.
2.
3.
4.
5.
6.
7.
8.
case
'3'
:
apdu.command[Apdu.INS] =
MaClasse.INS_DECREMENTER_COMPTEUR;
cad.exchangeApdu
(
apdu);
if
(
apdu.getStatus
(
) !=
0x9000
)
System.out.println
(
"Erreur : status word different de 0x9000"
);
else
System.out.println
(
"OK"
);
break
;
Le troisième choix consiste à décrémenter le compteur. Identique à la précédente sauf l'INS correspondant est affecté.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
case
'4'
:
apdu.command[Apdu.INS] =
MaClasse.INS_INITIALISER_COMPTEUR;
byte
[] donnees =
new
byte
[1
];
donnees[0
] =
5
;
apdu.setDataIn
(
donnees);
cad.exchangeApdu
(
apdu);
if
(
apdu.getStatus
(
) !=
0x9000
)
System.out.println
(
"Erreur : status word different de 0x9000"
);
else
System.out.println
(
"OK"
);
break
;
Le quatrième choix consiste à initialiser le compteur. Une valeur est envoyée dans l'apdu qui sera attribuée au compteur par l'application serveur.
Toute data est envoyée à travers un tableau de bytes. Dans ce cas, on a besoin d'un tableau de bytes d'une seule case. On affecte par exemple la valeur 5 au tableau qui sera par la suite intégré dans l'apdu de commande par la méthode apdu.setDataIn(données).
2.
3.
case
'5'
:
fin=
true
;
break
;
2.
3.
4.
5.
6.
7.
/******************* Mise hors tension de la carte ******************/
try
{
cad.powerDown
(
);
}
catch
(
Exception e){
System.out.println
(
"Erreur lors de l'envoi de la commande Powerdown à la carte"
);
return
; }
IV-A-3. Simulation▲
IV-A-3-a. JCWDE▲
Créer un fichier de configuration qui contiendra la liste des applets JavaCard à installer pour la simulation et spécifier leurs AID.
Dans notre cas, on possède une seule applet.
Le fichier est créé sous C:\Eclipse\workspace\TP JC App Serveur\bin et nommé monapplet.app.
monpackage.MonApplet 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x00 0x00
Lancer le simulateur et se placer dans le répertoire C:\Eclipse\workspace\TP JC App Serveur\bin et taper la commande jcwde monapplet.app.
Lancer l'application client sous Eclipse.
-
Interrogation du compteur : - Incrémentation du compteur : choix 2 ;
- Réinitialisation du compteur : choix 4 ;
- Décrémentation et interrogation du compteur :
IV-A-3-b. CREF▲
Le CREF est caractérisé par la conservation d'état de la carte.
Dans l'application serveur, on a lancé la simulation CREF de l'applet pendant laquelle on a enregistré dans le fichier monapplet.eeprom le chargement et l'installation de l'applet.
Sous Eclipse, on se positionne dans le fichier de l'applet puis ouvrir la console.
Exécuter la commande cref -i monapplet.eeprom -o monapplet.eeprom.
Ensuite, exécuter le code de l'application client .On obtient le menu principal.
Initialiser le compteur à 5 puis interroger pour vérifier la valeur.
Par la suite, on quitte en choisissant l'option 5 du menu. Puis on exécute de nouveau la commande cref -i monapplet.eeprom -o monapplet.eeprom après s'être positionné dans l'applet sous Eclipse.
Et finalement, on interroge de nouveau la carte et on récupère une valeur du compteur égale à 5.
V. Conclusion et remerciements▲
Au cours de ce tutoriel, on a travaillé une simple application de compteur. Elle vise à faciliter la compréhension de l'application serveur, qui joue le rôle d'un lecteur de carte. L'application serveur est codée en langage Java Card.
Une deuxième partie concernant le développement d'une application client, qui joue le rôle de la carte. L'application client est codée en langage Java dont le rôle est de communiquer avec l'application serveur.
Afin de tester notre application, on procède par une simulation réalisée sur l'ordinateur. Et ceci est notre point d'arrêt. On ne va pas aborder le chargement de l'application sur une carte à puce réelle.
Je tiens à remercier Logan Mauzaize pour ses conseils, Claude LELOUP pour sa relecture orthographique attentive de cet article et Mickaël Baron pour la mise au gabarit.
Un remerciement est également présenté à l'auteur juju_41 pour son article Introduction à la programmation de Javacard sous Windows.