/* $Id: Crypt.java,v 1.1 2011/05/04 22:38:03 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.security; import java.lang.reflect.Field; import java.util.Date; import java.util.List; import org.kapott.hbci.comm.Comm; import org.kapott.hbci.exceptions.HBCI_Exception; import org.kapott.hbci.manager.HBCIUtils; import org.kapott.hbci.manager.HBCIUtilsInternal; import org.kapott.hbci.manager.IHandlerData; import org.kapott.hbci.manager.MsgGen; import org.kapott.hbci.passport.HBCIPassportInternal; import org.kapott.hbci.protocol.MSG; import org.kapott.hbci.protocol.MultipleSEGs; import org.kapott.hbci.protocol.MultipleSyntaxElements; import org.kapott.hbci.protocol.SEG; import org.kapott.hbci.protocol.SyntaxElement; import org.w3c.dom.Element; import org.w3c.dom.Node; public final class Crypt { public final static String SECFUNC_ENC_3DES="4"; public final static String SECFUNC_ENC_PLAIN="998"; public final static String ENCALG_2K3DES="13"; public final static String ENCMODE_CBC="2"; public final static String ENCMODE_PKCS1="18"; public final static String ENC_KEYTYPE_RSA="6"; public final static String ENC_KEYTYPE_DDV="5"; private IHandlerData handlerdata; private MSG msg; private String u_secfunc; // 4=normal; 998=klartext private String u_keytype; // 5=ddv, 6=rdh private String u_blz; // schluesseldaten private String u_country; private String u_keyuserid; private String u_keynum; private String u_keyversion; private String u_cid; private String u_sysId; private String u_role; private String u_alg; // crypthead.cryptalg.alg private String u_mode; // crypthead.cryptalg.mode private String u_compfunc; public void setParam(String name, String value) { try { Field field=this.getClass().getDeclaredField("u_"+name); HBCIUtils.log("setting "+name+" to "+value,HBCIUtils.LOG_DEBUG); field.set(this,value); } catch (Exception ex) { throw new HBCI_Exception("*** error while setting parameter",ex); } } private void initData(IHandlerData handlerdata, MSG msg) { this.msg = msg; this.handlerdata = handlerdata; } public Crypt(IHandlerData handlerdata, MSG msg) { initData(handlerdata,msg); } public void init(IHandlerData handlerdata, MSG msg) { initData(handlerdata,msg); } private byte[] getPlainString() { try { // remove msghead and msgtail first StringBuffer ret=new StringBuffer(1024); List<MultipleSyntaxElements> childs=msg.getChildContainers(); int len=childs.size(); /* skip one segment at start and one segment at end of message (msghead and msgtail), the rest will be encrypted */ for (int i=1;i<len-1;i++) { ret.append(childs.get(i).toString(0)); } // pad message int padLength=8-(ret.length()%8); for (int i=0;i<padLength-1;i++) { ret.append((char)(0)); } ret.append((char)(padLength)); return ret.toString().getBytes(Comm.ENCODING); } catch (Exception ex) { throw new HBCI_Exception("*** error while extracting plain message string",ex); } } public MSG cryptIt(String newName) { MSG newmsg=msg; HBCIPassportInternal passport=(HBCIPassportInternal)handlerdata.getPassport(); if (passport.hasInstEncKey()) { String msgName = msg.getName(); MsgGen gen=handlerdata.getMsgGen(); Node msgNode = msg.getSyntaxDef(msgName, gen.getSyntax()); String dontcryptAttr = ((Element)msgNode).getAttribute("dontcrypt"); if (dontcryptAttr.length() == 0) { try { setParam("secfunc",passport.getCryptFunction()); setParam("keytype",passport.getCryptKeyType()); setParam("blz",passport.getBLZ()); setParam("country",passport.getCountry()); setParam("keyuserid",passport.getInstEncKeyName()); setParam("keynum",passport.getInstEncKeyNum()); setParam("keyversion",passport.getInstEncKeyVersion()); setParam("cid",passport.getCID()); setParam("sysId",passport.getSysId()); setParam("role","1"); setParam("alg",passport.getCryptAlg()); setParam("mode",passport.getCryptMode()); setParam("compfunc","0"); // TODO: spaeter kompression implementieren byte[][] crypteds=passport.encrypt(getPlainString()); String msgPath=msg.getPath(); String dialogid=msg.getValueOfDE(msgPath+".MsgHead.dialogid"); String msgnum=msg.getValueOfDE(msgPath+".MsgHead.msgnum"); String segnum=msg.getValueOfDE(msgPath+".MsgTail.SegHead.seq"); Date d=new Date(); gen.set(newName+".CryptData.data","B"+new String(crypteds[1],Comm.ENCODING)); gen.set(newName+".CryptHead.CryptAlg.alg",u_alg); gen.set(newName+".CryptHead.CryptAlg.mode",u_mode); gen.set(newName+".CryptHead.CryptAlg.enckey","B"+new String(crypteds[0],Comm.ENCODING)); gen.set(newName+".CryptHead.CryptAlg.keytype",u_keytype); gen.set(newName+".CryptHead.SecIdnDetails.func",(newmsg.getName().endsWith("Res")?"2":"1")); gen.set(newName+".CryptHead.KeyName.KIK.blz",u_blz); gen.set(newName+".CryptHead.KeyName.KIK.country",u_country); gen.set(newName+".CryptHead.KeyName.userid",u_keyuserid); gen.set(newName+".CryptHead.KeyName.keynum",u_keynum); gen.set(newName+".CryptHead.KeyName.keyversion",u_keyversion); gen.set(newName+".CryptHead.SecProfile.method",passport.getProfileMethod()); gen.set(newName+".CryptHead.SecProfile.version",passport.getProfileVersion()); if (passport.getSysStatus().equals("0")) { gen.set(newName+".CryptHead.SecIdnDetails.cid","B"+u_cid); } else { gen.set(newName+".CryptHead.SecIdnDetails.sysid",u_sysId); } gen.set(newName+".CryptHead.SecTimestamp.date",HBCIUtils.date2StringISO(d)); gen.set(newName+".CryptHead.SecTimestamp.time",HBCIUtils.time2StringISO(d)); gen.set(newName+".CryptHead.role",u_role); gen.set(newName+".CryptHead.secfunc",u_secfunc); gen.set(newName+".CryptHead.compfunc",u_compfunc); gen.set(newName+".MsgHead.dialogid",dialogid); gen.set(newName+".MsgHead.msgnum",msgnum); gen.set(newName+".MsgTail.msgnum",msgnum); if (newName.endsWith("Res")) { gen.set(newName+".MsgHead.MsgRef.dialogid",dialogid); gen.set(newName+".MsgHead.MsgRef.msgnum",msgnum); } newmsg=gen.generate(newName); // renumerate crypto-segments for (int i=1;i<=2;i++) { SEG seg=(SEG)(((MultipleSEGs)((newmsg.getChildContainers()).get(i))).getElements().get(0)); seg.setSeq(997+i,SyntaxElement.ALLOW_OVERWRITE); } newmsg.propagateValue(newmsg.getPath()+".MsgTail.SegHead.seq",segnum, SyntaxElement.DONT_TRY_TO_CREATE, SyntaxElement.ALLOW_OVERWRITE); newmsg.autoSetMsgSize(gen); } catch (Exception ex) { throw new HBCI_Exception("*** error while encrypting",ex); } } else HBCIUtils.log("did not encrypt - message does not want to be encrypted",HBCIUtils.LOG_DEBUG); } else HBCIUtils.log("can not encrypt - no encryption key available",HBCIUtils.LOG_WARN); return newmsg; } private boolean isCrypted() { boolean ret = true; MultipleSyntaxElements seglist = (msg.getChildContainers().get(1)); if (seglist instanceof MultipleSEGs) { SEG crypthead = null; try { crypthead = (SEG)(seglist.getElements().get(0)); } catch (Exception e) { ret = false; } if (ret) { String sigheadCode = "HNVSK"; MsgGen gen=handlerdata.getMsgGen(); if (!crypthead.getCode(gen).equals(sigheadCode)) ret = false; } } else ret = false; return ret; } public String decryptIt() { StringBuffer ret=new StringBuffer(msg.toString(0)); HBCIPassportInternal passport=(HBCIPassportInternal)handlerdata.getPassport(); if (passport.hasMyEncKey()) { if (isCrypted()) { try { String msgName=msg.getName(); List<MultipleSyntaxElements> childs=msg.getChildContainers(); SEG msghead=(SEG)(((MultipleSEGs)(childs.get(0))).getElements().get(0)); SEG msgtail=(SEG)(((MultipleSEGs)(childs.get(childs.size()-1))).getElements().get(0)); // verschluesselte daten extrahieren SEG cryptdata=(SEG)(((MultipleSEGs)(childs.get(2))).getElements().get(0)); byte[] cryptedstring=cryptdata.getValueOfDE(msgName+".CryptData.data").getBytes(Comm.ENCODING); // key extrahieren SEG crypthead=(SEG)(((MultipleSEGs)(childs.get(1))).getElements().get(0)); byte[] cryptedkey=crypthead.getValueOfDE(msgName+ ".CryptHead.CryptAlg.enckey").getBytes(Comm.ENCODING); // neues secfunc (klartext/encrypted) String secfunc=crypthead.getValueOfDE(msgName+".CryptHead.secfunc"); if (!secfunc.equals(passport.getCryptFunction())) { String errmsg=HBCIUtilsInternal.getLocMsg("EXCMSG_CRYPTSFFAIL",new Object[] {secfunc, passport.getCryptFunction()}); if (!HBCIUtilsInternal.ignoreError(null,"client.errors.ignoreCryptErrors",errmsg)) throw new HBCI_Exception(errmsg); } // TODO: diese checks werden vorerst abgeschaltet, damit pin-tan reibungslos geht /* // constraint checking String keytype=crypthead.getValueOfDE(msgName+".CryptHead.CryptAlg.keytype"); if (!keytype.equals(passport.getSecMethod56()) && !(passport instanceof HBCIPassportPinTan)) throw new HBCI_Exception(HBCIUtils.getLocMsg("EXCMSG_CRYPTMETHODFAIL",new Object[] {keytype,passport.getSecMethod56()})); String mode=crypthead.getValueOfDE(msgName+".CryptHead.CryptAlg.mode"); if (!mode.equals(passport.getCryptMode())) throw new HBCI_Exception(HBCIUtils.getLocMsg("EXCMSG_CRYPTMODEFAIL",new Object[] {keytype,passport.getCryptMode()})); */ /* TODO: removed code because no real checks are done here if (passport.getSysStatus().equals("1")) { String sysid=null; try { // falls noch keine system-id ausgehandelt wurde, so sendet der // hbci-server auch keine... deshalb der try-catch-block sysid=crypthead.getValueOfDE(msgName+".CryptHead.SecIdnDetails.sysid"); } catch (Exception e) { sysid="0"; } // TODO: sysid checken (kann eigentlich auch entfallen, weil // das jeweils auf h�herer ebene geschehen sollte!) } else { String cid=crypthead.getValueOfDE(msgName+".CryptHead.SecIdnDetails.cid"); if (!cid.equals(passport.getCID())) { String errmsg=HBCIUtilsInternal.getLocMsg("EXCMSG_CRYPTCIDFAIL"); if (!HBCIUtilsInternal.ignoreError(null,"client.errors.ignoreCryptErrors",errmsg)) throw new HBCI_Exception(errmsg); } // TODO: cid checken } */ // TODO spaeter kompression implementieren String compfunc=crypthead.getValueOfDE(msgName+".CryptHead.compfunc"); if (!compfunc.equals("0")) { String errmsg=HBCIUtilsInternal.getLocMsg("EXCMSG_CRYPTCOMPFUNCFAIL",compfunc); if (!HBCIUtilsInternal.ignoreError(null,"client.errors.ignoreCryptErrors",errmsg)) throw new HBCI_Exception(errmsg); } // TODO: hier auch die DEG SecProfile lesen und �berpr�fen byte[] plainMsg=passport.decrypt(cryptedkey,cryptedstring); int padLength=plainMsg[plainMsg.length-1]; // FileOutputStream fo=new FileOutputStream("decrypt.dat"); // fo.write(plainMsg); // fo.close(); // neuen nachrichtenstring zusammenbauen ret=new StringBuffer(1024); ret.append(msghead.toString(0)). append(new String(plainMsg,0,plainMsg.length-padLength,Comm.ENCODING)). append(msgtail.toString(0)); HBCIUtils.log("decrypted message: "+ret,HBCIUtils.LOG_DEBUG2); } catch (Exception ex) { throw new HBCI_Exception("*** error while decrypting",ex); } } else HBCIUtils.log("did not decrypt - message is already cleartext",HBCIUtils.LOG_DEBUG); } else HBCIUtils.log("can not decrypt - no decryption key available",HBCIUtils.LOG_WARN); return ret.toString(); } public void destroy() { handlerdata=null; msg=null; u_alg=null; u_blz=null; u_cid=null; u_compfunc=null; u_country=null; u_keynum=null; u_keyuserid=null; u_keyversion=null; u_mode=null; u_role=null; u_secfunc=null; u_keytype=null; u_sysId=null; } }