/* $Id: HBCIPassportDDVPCSC.java,v 1.1 2011/11/24 21:59:37 willuhn Exp $
This file is part of HBCI4Java
Copyright (C) 2001-2008 Stefan Palme
HBCI4Java is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
HBCI4Java is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.kapott.hbci.passport;
import java.io.File;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.io.StreamCorruptedException;
import java.util.List;
import java.util.Properties;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.spec.PBEParameterSpec;
import javax.smartcardio.Card;
import javax.smartcardio.CardTerminal;
import javax.smartcardio.CardTerminals;
import javax.smartcardio.TerminalFactory;
import org.kapott.hbci.callback.HBCICallback;
import org.kapott.hbci.datatypes.SyntaxCtr;
import org.kapott.hbci.exceptions.HBCI_Exception;
import org.kapott.hbci.exceptions.InvalidPassphraseException;
import org.kapott.hbci.manager.HBCIKey;
import org.kapott.hbci.manager.HBCIUtils;
import org.kapott.hbci.manager.HBCIUtilsInternal;
import org.kapott.hbci.smartcardio.DDVBankData;
import org.kapott.hbci.smartcardio.DDVCardService;
import org.kapott.hbci.smartcardio.DDVKeyData;
/**
* Implementierung eines DDV-Passports, welcher intern die neue Chipkarten-API
* "javax.smartcardio" von Java 6 verwendet. Die Implementierung basiert auf
* dem OCF-Code von HBCI4Java 2.5.8.
*/
public class HBCIPassportDDVPCSC extends HBCIPassportDDV
{
private Card smartCard;
private DDVCardService cardService;
/**
* ct.
* @param init
* @param dummy
*/
public HBCIPassportDDVPCSC(Object init, int dummy)
{
super(init,dummy);
}
/**
* ct.
* @param init
*/
public HBCIPassportDDVPCSC(Object init)
{
this(init,0);
ObjectInputStream is = null;
try
{
////////////////////////////////////////////////////////////////////////
// set parameters for initializing card
this.setUseBio(Integer.parseInt(HBCIUtils.getParam(getParamHeader()+".usebio","-1")));
this.setUseSoftPin(Integer.parseInt(HBCIUtils.getParam(getParamHeader()+".softpin","-1")));
this.setSoftPin(new byte[0]);
this.setPINEntered(false);
this.setEntryIdx(Integer.parseInt(HBCIUtils.getParam(getParamHeader()+".entryidx","1")));
//
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// init card
HBCIUtils.log("initializing javax.smartcardio",HBCIUtils.LOG_DEBUG);
HBCIUtilsInternal.getCallback().callback(this,HBCICallback.NEED_CHIPCARD,HBCIUtilsInternal.getLocMsg("CALLB_NEED_CHIPCARD"),HBCICallback.TYPE_NONE,null);
this.initCT();
HBCIUtilsInternal.getCallback().callback(this,HBCICallback.HAVE_CHIPCARD,"",HBCICallback.TYPE_NONE,null);
//
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// init basic bank data
try {
this.setPort(new Integer(3000));
this.setFilterType("None");
this.ctReadBankData();
if (this.askForMissingData(true,true,true,false,false,true,false))
this.saveBankData();
this.ctReadKeyData();
}
catch (HBCI_Exception e1)
{
throw e1;
}
catch (Exception e)
{
throw new HBCI_Exception(HBCIUtilsInternal.getLocMsg("EXCMSG_PASSPORT_INSTDATAERR"),e);
}
//
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// read passport file
String path = HBCIUtils.getParam(getParamHeader()+".path","./");
this.setFileName(HBCIUtilsInternal.withCounter(path+"pcsc"+getCardId(),getEntryIdx()-1));
HBCIUtils.log("loading passport data from file "+getFileName(),HBCIUtils.LOG_DEBUG);
File file = new File(this.getFileName());
if (file.exists() && file.isFile() && file.canRead())
{
int retries = Integer.parseInt(HBCIUtils.getParam("client.retries.passphrase","3"));
while (true) // loop for entering the correct passphrase
{
if (this.getPassportKey() == null)
this.setPassportKey(calculatePassportKey(FOR_LOAD));
PBEParameterSpec paramspec = new PBEParameterSpec(CIPHER_SALT,CIPHER_ITERATIONS);
Cipher cipher = Cipher.getInstance("PBEWithMD5AndDES");
cipher.init(Cipher.DECRYPT_MODE,getPassportKey(),paramspec);
try
{
is = new ObjectInputStream(new CipherInputStream(new FileInputStream(file),cipher));
}
catch (StreamCorruptedException e1)
{
setPassportKey(null); // Passwort resetten
retries--;
if (retries<=0)
throw new InvalidPassphraseException();
}
catch (Exception e2)
{
throw new HBCI_Exception(HBCIUtilsInternal.getLocMsg("EXCMSG_PASSPORT_READERR"),e2);
}
// wir habens
if (is != null)
{
setBPD((Properties)(is.readObject()));
setUPD((Properties)(is.readObject()));
setHBCIVersion((String)is.readObject());
break;
}
}
}
//
////////////////////////////////////////////////////////////////////////
}
catch (Exception e)
{
// Im Fehlerfall wieder schliessen
try {
closeCT();
}
catch (Exception ex) {
HBCIUtils.log(ex);
}
if (e instanceof HBCI_Exception)
throw (HBCI_Exception) e;
throw new HBCI_Exception(HBCIUtilsInternal.getLocMsg("EXCMSG_CTERR"),e);
}
finally
{
// Close Passport-File
if (is != null) {
try {
is.close();
}
catch (Exception e) {
HBCIUtils.log(e);
}
}
}
}
/**
* @see org.kapott.hbci.passport.HBCIPassportDDV#initCT()
*/
protected void initCT()
{
try
{
TerminalFactory terminalFactory = TerminalFactory.getDefault();
CardTerminals terminals = terminalFactory.terminals();
if (terminals == null)
throw new HBCI_Exception("Kein Kartenleser gefunden");
List<CardTerminal> list = terminals.list();
if (list == null || list.size() == 0)
throw new HBCI_Exception("Kein Kartenleser gefunden");
HBCIUtils.log("found card terminals:",HBCIUtils.LOG_INFO);
for (CardTerminal t:list) {
HBCIUtils.log(" "+t.getName(),HBCIUtils.LOG_INFO);
}
CardTerminal terminal = null;
// Checken, ob der User einen konkreten Kartenleser vorgegeben hat
String name = HBCIUtils.getParam(getParamHeader()+".pcsc.name",null);
if (name != null)
{
HBCIUtils.log("explicit terminal name given, trying to open terminal: " + name,HBCIUtils.LOG_DEBUG);
terminal = terminals.getTerminal(name);
if (terminal == null)
throw new HBCI_Exception("Kartenleser \"" + name + "\" nicht gefunden");
}
else
{
HBCIUtils.log("open first available card terminal",HBCIUtils.LOG_DEBUG);
terminal = list.get(0);
}
HBCIUtils.log("using card terminal " + terminal.getName(),HBCIUtils.LOG_DEBUG);
// wait for card
if (!terminal.waitForCardPresent(60 * 1000L))
throw new HBCI_Exception("Keine Chipkarte in Kartenleser " + terminal.getName() + " gefunden");
// Hier kann man gemaess
// http://download.oracle.com/javase/6/docs/jre/api/security/smartcardio/spec/javax/smartcardio/CardTerminal.html#connect%28java.lang.String%29
// auch "T=0" oder "T=1" angeben. Wir wissen allerdings noch nicht, von welchem
// Typ die Karte ist. Daher nehmen wir "*" fuer jedes verfuegbare. Wenn wir die
// Karte geoeffnet haben, kriegen wir dann auch das Protokoll raus.
this.smartCard = terminal.connect("*");
String type = this.smartCard.getProtocol();
HBCIUtils.log(" card type: " + type,HBCIUtils.LOG_INFO);
// Card-Service basierend auf dem Kartentyp erzeugen
if (type == null || type.indexOf("=") == -1)
throw new HBCI_Exception("Unbekannter Kartentyp");
String id = type.substring(type.indexOf("=")+1);
String serviceName = "org.kapott.hbci.smartcardio.DDVCardService" + id;
HBCIUtils.log(" trying to load: " + serviceName,HBCIUtils.LOG_DEBUG);
this.cardService = (DDVCardService) Class.forName(serviceName).newInstance();
HBCIUtils.log(" using: " + this.cardService.getClass().getName(),HBCIUtils.LOG_INFO);
this.cardService.init(this.smartCard);
// getCID
byte[] cid=this.cardService.getCID();
this.setCID(new String(cid,"ISO-8859-1"));
// extract card id
StringBuffer cardId=new StringBuffer();
for (int i=0;i<8;i++)
{
cardId.append((char)(((cid[i+1]>>4)&0x0F) + 0x30));
cardId.append((char)((cid[i+1]&0x0F) + 0x30));
}
this.setCardId(cardId.toString());
}
catch (HBCI_Exception he)
{
throw he;
}
catch (Exception e)
{
throw new HBCI_Exception(e);
}
}
/**
* @see org.kapott.hbci.passport.HBCIPassportDDV#ctReadBankData()
*/
protected void ctReadBankData()
{
int idx = this.getEntryIdx()-1;
DDVBankData bankData = this.cardService.readBankData(idx);
this.setCountry(SyntaxCtr.getName(bankData.country));
this.setBLZ(bankData.blz);
this.setHost(bankData.commaddr);
this.setUserId(bankData.userid);
}
/**
* @see org.kapott.hbci.passport.HBCIPassportDDV#ctReadKeyData()
*/
protected void ctReadKeyData()
{
this.setSigId(new Long(cardService.readSigId()));
// readKeyData
DDVKeyData[] keyData=cardService.readKeyData();
this.setInstSigKey(new HBCIKey(
getCountry(), getBLZ(), getUserId(),
Integer.toString(keyData[0].num), Integer.toString(keyData[0].version),
null));
this.setInstEncKey(new HBCIKey(
getCountry(), getBLZ(), getUserId(),
Integer.toString(keyData[1].num), Integer.toString(keyData[1].version),
null));
}
/**
* @see org.kapott.hbci.passport.HBCIPassportDDV#ctEnterPIN()
*/
protected void ctEnterPIN()
{
if (getUseSoftPin()==1)
this.cardService.verifySoftPIN(1, this.getSoftPin());
else
this.cardService.verifyHardPIN(1);
}
/**
* @see org.kapott.hbci.passport.HBCIPassportDDV#ctSaveBankData()
*/
protected void ctSaveBankData()
{
int idx = this.getEntryIdx()-1;
DDVBankData bankData;
bankData=cardService.readBankData(idx);
bankData.country=SyntaxCtr.getCode(this.getCountry());
bankData.blz=this.getBLZ();
bankData.commaddr=this.getHost();
bankData.userid=this.getUserId();
cardService.writeBankData(idx,bankData);
}
/**
* @see org.kapott.hbci.passport.HBCIPassportDDV#ctSaveSigId()
*/
protected void ctSaveSigId()
{
cardService.writeSigId(getSigId().intValue());
}
/**
* @see org.kapott.hbci.passport.HBCIPassportDDV#ctSign(byte[])
*/
protected byte[] ctSign(byte[] data)
{
return cardService.sign(data);
}
/**
* @see org.kapott.hbci.passport.HBCIPassportDDV#ctEncrypt()
*/
protected byte[][] ctEncrypt()
{
return cardService.getEncryptionKeys(Integer.parseInt(getInstEncKeyNum()));
}
/**
* @see org.kapott.hbci.passport.HBCIPassportDDV#ctDecrypt(byte[])
*/
protected byte[] ctDecrypt(byte[] cryptedKey)
{
return cardService.decrypt(Integer.parseInt(getInstEncKeyNum()),cryptedKey);
}
/**
* @see org.kapott.hbci.passport.HBCIPassportDDV#closeCT()
*/
protected void closeCT()
{
try
{
if (smartCard!=null)
smartCard.disconnect(false);
}
catch (HBCI_Exception e1)
{
throw e1;
}
catch (Exception e2)
{
throw new HBCI_Exception(e2);
}
}
}