Hello, I am having major problems creating a file system for a MPCOS-EMV card. I have attached the code that I am using to create the file system, my opencard.properties file and the Set Environment batch file as text.
Below is the output I receive with the opencard.properties file as it is
above:
Starting TestMPCOS...
Waiting for card...
Card detected
java.lang.ClassNotFoundException: CardService implementing interface
opencard.op
t.iso.fs.FileSystemCardService
at
opencard.core.service.CardServiceRegistry.getCardServiceInstance(Card
ServiceRegistry.java:269)
at
opencard.core.service.SmartCard.getCardService(SmartCard.java:331)
at TestMPCOS.<init>(TestMPCOS.java:53)
at TestMPCOS.main(TestMPCOS.java:105)
Press any key to continue . . .
And below is the output I receive if I uncomment:
\
com.gemplus.opencard.service.gpk.file.GPKFileSystemService
in the opencard.properties file:
Starting TestMPCOS...
java.lang.ClassCastException:
com.gemplus.opencard.service.gpk.file.GPKFileSyste
mService
at
opencard.core.service.SmartCard.configureServiceRegistry(SmartCard.ja
va:218)
at opencard.core.service.SmartCard.start(SmartCard.java:535)
at TestMPCOS.main(TestMPCOS.java:96)
Press any key to continue . . .
I'm really stuck on this, Can anyone help me?
Best Regards
John Crook
// Gemplus Imports
import com.gemplus.opencard.service.gpk.admin.AdministrativeCardService;
import com.gemplus.opencard.service.gpk.admin.GPKAdministrativeService;
import com.gemplus.opencard.service.gpk.file.FileUtilityCardService;
import com.gemplus.opencard.service.gpk.file.GPKFileSystemService;
import com.gemplus.opencard.service.gpk.file.GPKFileUtilityService;
import com.gemplus.opencard.service.gpk.security.GPKAdministrativeCredential;
import com.gemplus.opencard.service.gpk.security.GPKCredentialStore;
// Java Imports
import java.security.InvalidKeyException;
// Opencard Imports
import opencard.core.service.*;
import opencard.core.terminal.*;
import opencard.opt.iso.fs.*;
import opencard.opt.iso.fs.FileSystemCardService;
import opencard.opt.security.CredentialBag;
// Cryptix imports
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.DESKeySpec;
// Class TestMPCOS
public class TestMPCOS{
private SmartCard sc = null;
private GPKFileSystemService fss;
private GPKFileUtilityService fus;
private static final CardFilePath root = new CardFilePath(":3F00");
private static final CardFilePath ef_3F01 = new CardFilePath(":3F00:3F01");
private static final CardFilePath df_0200 = new CardFilePath(":3F00:0200");
private static final CardFilePath ef_0201 = new CardFilePath(":3F00:0200:0201");
// Constructor
public TestMPCOS(SmartCard sc)
throws CardServiceException, ClassNotFoundException, CardServiceException,
CardTerminalException, InvalidKeyException {
this.sc = sc;
boolean extAuth = false;
// Instanciate file CardServices
fss = (GPKFileSystemService) sc.getCardService(FileSystemCardService.class, true);
fus = (GPKFileUtilityService) sc.getCardService(FileUtilityCardService.class, true);
// Provide credentials for Administrative key :3F00:3F01
CredentialBag bag = new CredentialBag();
GPKCredentialStore store = new GPKCredentialStore();
GPKAdministrativeCredential credential = new GPKAdministrativeCredential();
store.storeCredential(0, credential);
bag.addCredentialStore(store);
fss.provideCredentials(ef_3F01, bag);
// Erase Card
System.out.println("Erasing Card...");
fus.eraseCard();
// create DF(0x0200)
System.out.println("\nCreate DF " + df_0200);
fus.createDF(df_0200, extAuth, null);
// create EF(0x0201)
System.out.println("\nCreate EF " + ef_0201);
fus.createTransparentFile(ef_0201, 100, null);
// update binary
System.out.println("\nUpdate to " + ef_0201);
byte[] updateData = new byte[100];
for(int i = 0; i < 100; i++) {
updateData[i] = (byte)i;
}
Util.printBytes("updateData = \n", updateData);
fss.update(ef_0201, 0, updateData, 0, 100);
// read binary
System.out.println("\nRead from " + ef_0201);
byte[] readData = fss.read(ef_0201, 0, 100);
Util.printBytes("readData = \n", readData);
}
// Main()
public static void main(String[] args) {
try {
SmartCard.start();
// wait for a smartcard with file access support
System.out.println("\nWaiting for card...\n");
CardRequest cr = new CardRequest();
SmartCard card = SmartCard.waitForCard(cr);
System.out.println("Card detected\n");
// Instantiate the TestMPCOS class
TestMPCOS test1 = new TestMPCOS(card);
} catch(Exception e) {
e.printStackTrace();
}
finally {
try {
SmartCard.shutdown();
System.exit(0);
} catch(Exception e) {
e.printStackTrace();
}
}
}
}
abstract class Util {
// Computes teh checksum needed for PK_Send & Load Private Key
public static byte computePKChecksum(byte[] bArray, int len) {
// NOTE checksum = COM(XOR(tag||value))
// COM(X) = X^0xFF
byte chksum = (byte)0xFF;
for(int i =0; i<len; i++)
chksum = (byte)(chksum^bArray[i]);
return chksum;
}
// Swaps the bytes(order) used in PK_Send function
public static void swapForPKSend(byte[] source, int offSource, byte[] dest, int offDest, int len) {
int j = len-1;
for (int i=0; i<len; i++,j--)
dest[offDest+i] = source[offSource+j];
}
// Copies len number of bytes from the array<source>(at offset = offSource) to the array<dest>(offset = offDest).
public static void arrayCopy(byte[] source, int offSource, byte[] dest, int offDest, int len) {
for(int i=0; i<len; i++)
dest[offDest+i] = source[offSource+i];
}
// An utility for debugging...
public static void debug(boolean deb, String prompt, byte[] byteArray) {
if(deb)
Util.printBytes(prompt, byteArray);
}
// An utility to print byte array
public static void printBytes(String prompt, byte[] byteArray) {
String strByteArray = Util.toString(byteArray);
System.out.println(prompt + strByteArray);
}
// Does the 3DES encryption.
public static byte[] doEncrypt(byte[] inpText, byte[] key) throws Exception {
byte [] tmp = new byte[8];
try {
SecretKeySpec skSpecL = new SecretKeySpec(key, 0, 8, new String("DES"));
SecretKey kL = (SecretKey)skSpecL;
SecretKeySpec skSpecR = new SecretKeySpec(key, 8, 8, new String("DES"));
SecretKey kR = (SecretKey)skSpecR;
Cipher des = Cipher.getInstance("DES"+"/ECB/None");
// DES Encrypt
des.init(Cipher.ENCRYPT_MODE, kL);
tmp = des.doFinal(inpText);
// DES Decrypt
des.init(Cipher.DECRYPT_MODE, kR);
tmp = des.doFinal(tmp);
// DES Encrypt
des.init(Cipher.ENCRYPT_MODE, kL);
tmp = des.doFinal(tmp);
}catch(Exception e) {
e.printStackTrace();
}
return tmp;
}
// Computes the 16 bytes 3DES session key
public static byte[] computeSessionKey(byte[] inpText, byte[] key) throws Exception{
byte [] tmp = new byte[16];
try {
SecretKeySpec skSpecL = new SecretKeySpec(key, 0, 8, new String("DES"));
SecretKey kL = (SecretKey)skSpecL;
SecretKeySpec skSpecR = new SecretKeySpec(key, 8, 8, new String("DES"));
SecretKey kR = (SecretKey)skSpecR;
Cipher des = Cipher.getInstance("DES"+"/ECB/None");
// DES Encrypt
des.init(Cipher.ENCRYPT_MODE, kL);
byte[] tmp1 = des.doFinal(inpText);
// DES Decrypt
des.init(Cipher.DECRYPT_MODE, kR);
tmp1 = des.doFinal(tmp1);
// DES Encrypt
des.init(Cipher.ENCRYPT_MODE, kL);
tmp1 = des.doFinal(tmp1);
// DES Encrypt
des.init(Cipher.ENCRYPT_MODE, kR);
byte[] tmp2 = des.doFinal(inpText);
// DES Decrypt
des.init(Cipher.DECRYPT_MODE, kL);
tmp2 = des.doFinal(tmp2);
// DES Encrypt
des.init(Cipher.ENCRYPT_MODE, kR);
tmp2 = des.doFinal(tmp2);
// Concatenate
for(int i=0; i<8; i++)
tmp[i] = tmp1[i];
for(int i=0; i<8; i++)
tmp[i+8] = tmp2[i];
}catch(Exception e) {
e.printStackTrace();
}
return tmp;
}
// Returns a byte array from a string of hexadecimal digits.
public static byte[] hexFromString(String hex) {
int len = hex.length();
byte[] buf = new byte[((len + 1) / 2)];
int i = 0, j = 0;
if ((len % 2) == 1)
buf[j++] = (byte) fromDigit(hex.charAt(i++));
while (i < len) {
buf[j++] = (byte) ((fromDigit(hex.charAt(i++)) << 4) |
fromDigit(hex.charAt(i++)));
}
return buf;
}
// Returns the number from 0 to 15 corresponding to the hex digit <i>ch</i>.
public static int fromDigit(char ch) {
if (ch >= '0' && ch <= '9')
return ch - '0';
if (ch >= 'A' && ch <= 'F')
return ch - 'A' + 10;
if (ch >= 'a' && ch <= 'f')
return ch - 'a' + 10;
throw new IllegalArgumentException("invalid hex digit '" + ch + "'");
}
//Compares two byte arrays for equality.
public static boolean areEqual (byte[] a, byte[] b) {
int aLength = a.length;
if (aLength != b.length)
return false;
for (int i = 0; i < aLength; i++)
if (a[i] != b[i])
return false;
return true;
}
//Returns a string of hexadecimal digits from a byte array. Each
//byte is converted to 2 hex symbols.
public static String toString( byte[] ba ) {
int length = ba.length;
char[] buf = new char[length * 2];
for (int i = 0, j = 0, k; i < length; ) {
k = ba[i++];
buf[j++] = HEX_DIGITS[(k >>> 4) & 0x0F];
buf[j++] = HEX_DIGITS[ k & 0x0F];
}
return new String(buf);
}
public static final char[] HEX_DIGITS = {
'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
};
}
opencard.properties
Description: Binary data
@echo off rem ************************************************************* rem * Local OCF Configuration * rem ************************************************************* rem * Modifying these settings should be sufficient to * rem * run the demo applications. * rem * * rem * Where the OpenCard Framework is installed * set OCF_INSTALLDIR=C:\OpenCard\OCF1.2\ rem * * rem * The next two Variables are only needed when using a * rem * Pure Java CardTerminal. * rem * * rem * Path to the Comm API classes (comm.jar) * set OCF_COMMAPI= rem * * rem * Path to the OCF CardTerminal classes provided by * rem * the reader hardware vendor * set OCF_PUREJAVA_CARDTERMINAL= rem * * rem * Set Classpath for JDK1.1 * set OCF_CLASSPATH=%CLASSPATH% rem * * rem ************************************************************* rem * No changes should be neccessary below this point. * rem ************************************************************* rem ************************************************************* rem * OCF base classes * rem ************************************************************* set OCF_CLASSPATH=%OCF_CLASSPATH%;%OCF_INSTALLDIR%lib\base-core.jar set OCF_CLASSPATH=%OCF_CLASSPATH%;%OCF_INSTALLDIR%lib\base-opt.jar set OCF_CLASSPATH=%OCF_CLASSPATH%;%OCF_INSTALLDIR%lib\reference-services.jar set OCF_CLASSPATH=%OCF_CLASSPATH%;%OCF_INSTALLDIR%lib\gemplus-gpk-0.1.jar set OCF_CLASSPATH=%OCF_CLASSPATH%;%OCF_INSTALLDIR%lib\gemplus-service-0.3.jar rem ************************************************************* rem * Classes needed for OCF demos * rem ************************************************************* set OCF_CLASSPATH=%OCF_CLASSPATH%;%OCF_INSTALLDIR%lib\sb-demo.jar set OCF_CLASSPATH=%OCF_CLASSPATH%;%OCF_INSTALLDIR%lib\sb-demo-ext.jar rem ************************************************************* rem * CardTerminal configuration * rem ************************************************************* rem PC/SC CardTerminal classes set OCF_CLASSPATH=%OCF_CLASSPATH%;%OCF_INSTALLDIR%lib\reference-terminals-windows.jar rem Add OCF PC/SC dll's to search path set PATH=%PATH%;%OCF_INSTALLDIR%lib rem Pure Java CardTermial classes (Java Communications API needed) set OCF_CLASSPATH=%OCF_CLASSPATH%;%OCF_COMMAPI% set OCF_CLASSPATH=%OCF_CLASSPATH%;%OCF_PUREJAVA_CARDTERMINAL% rem ************************************************************* rem * END of configuration * rem ************************************************************* echo Setting up environment... echo (Edit %OCF_INSTALLDIR%\demos\setenv.bat echo to change these settings.) echo ------------------------------------------------------------ echo OCF_INSTALLDIR=%OCF_INSTALLDIR% echo OCF_CLASSPATH=%OCF_CLASSPATH% echo PATH=%PATH% echo ------------------------------------------------------------
