/***************************************************************************
 $RCSfile: hbcicard.h,v $
                             -------------------
    cvs         : $Id: hbcicard.h,v 1.8 2003/05/06 15:05:41 aquamaniac Exp $
    begin       : Tue Aug 28 2001
    copyright   : (C) 2001 by Martin Preuss
    email       : martin@libchipcard.de

 ***************************************************************************
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Lesser General Public            *
 *   License as published by the Free Software Foundation; either          *
 *   version 2.1 of the License, or (at your option) any later version.    *
 *                                                                         *
 *   This library 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     *
 *   Lesser General Public License for more details.                       *
 *                                                                         *
 *   You should have received a copy of the GNU Lesser General Public      *
 *   License along with this library; if not, write to the Free Software   *
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston,                 *
 *   MA  02111-1307  USA                                                   *
 *                                                                         *
 ***************************************************************************/


#ifndef HBCICARD_H
#define HBCICARD_H

struct s_card_id;
class HBCICard;


#define k_HBCICARD_TYPE_UNKNOWN 0
#define k_HBCICARD_TYPE_0       1
#define k_HBCICARD_TYPE_1       2


#include <string>
#include <chipcard/cterror.h>



/**
 * This class provides easy access to HBCI cards.
 * You may read and write from/to those cards.
 * DDV cards of type 0 and of type 1 are supported. This class does not
 * support RSA cards (like G&D cards).
 * @author Martin Preuss <martin@libchipcard.de>
 * @ingroup scards
 * @short Special class for HBCI (German Home Banking Computer Interface) cards
 */
class CHIPCARD_API HBCICard : public CTProcessorCard {
private:

  int _type;
  string _cid;
  string _cmdPutInstData;
  string _cmdVerifyPin;
  string _cmdSecureVerifyPin;

  s_card_id *_make_card_id(string &data);

  /**
   * Selects DF_BANKING/DF_BANKING_20 and checks whether it is a type 0
   * or type 1 card.
   */
  CTError _checkType();

  /** For type 0 cards */
  bool _hash2mac0(string &hash, string &mac);

  /** For type 1 cards */
  bool _hash2mac1(string &hash, string &mac);

  bool _getKeyVersion0(int key,int &kv);
  bool _getKeyVersion1(int key,int &kv);

  CTError _getCID(string &cid);

public:
  /**
   * This class describes a HBCI card.
   * @author Martin Preuss<martin@libchipcard.de>
   */
  class CHIPCARD_API CardData {
  private:
    unsigned char _cardtype;
    unsigned char _industrialkey;
    unsigned int _shortinstcode;
    string _cardnumber;
    unsigned char _bestuntil_year;
    unsigned char _bestuntil_month;
    unsigned char _active_year;
    unsigned char _active_month;
    unsigned char _active_day;
    unsigned short _countrycode;
    string _currency;

  public:
    CardData();
    CardData(const string &s, int cardtype);
    ~CardData();

    /**
     * The type of the card: k_HBCICARD_TYPE_0, k_HBCICARD_TYPE_1
     * or k_HBCICARD_TYPE_UNKNOWN.
     */
    int cardType() const { return _cardtype;};
    /**
     * "Branchenhauptschluessel", dont know what that means but it has
     * always value 67.
     */
    int industrialKey() const { return _industrialkey;};
    /**
     * Short institute code of card delivering institute.
     */
    unsigned int shortInstituteCode() const { return _shortinstcode;};
    /**
     * ASCII-String cardnumber.
     */
    const string &cardNumber() const { return _cardnumber;};
    /**
     * Card is valid until THIS year.
     */
    int bestuntil_year() const { return _bestuntil_year;};
    /**
     * Card is valid until THIS month.
     */
    int bestuntil_month() const { return _bestuntil_month;};
    /**
     * Year of the card's activation.
     */
    int active_year() const { return _active_year;};
    /**
     * Month of the card's activation.
     */
    int active_month() const { return _active_month;};
    /**
     * Day of the card's activation.
     */
    int active_day() const { return _active_day;};
    /**
     * Country code (280 stands for Germany).
     */
    int countryCode() const { return _countrycode;};
    /**
     * Currency string ("DEM", "EUR").
     */
    const string &currency() const { return _currency;};
  };

  /**
   * This class describes a user at a credit institute.
   * @author Martin Preuss<martin@libchipcard.de>
   */
  class CHIPCARD_API instituteData {
  private:
    string _name;
    string _code;
    char _service;
    string _addr;
    string _addr_suffix;
    int _country;
    string _user;

  public:
    /**
     * Name of the credit institute.
     */
    const string &name() const { return _name;};
    /**
     * ASCII institute code ("Bankleitzahl").
     */
    const string &code() const { return _code;};
    void setCode(const string &c) { _code=c;};

    /**
     * Service type (2=TCP, 1=CEPT).
     */
    char service() const { return _service;};
    void setService(char s) { _service=s;};

    /**
     * ASCII comunication address (for tcp: server address).
     */
    const string &address() const { return _addr;};
    void setAddress(const string &a) { _addr=a;};

    /**
     * Address suffix (unused with tcp).
     */
    const string &addressSuffix() const { return _addr_suffix;};
    void setAddrSuffix(const string &s) { _addr_suffix=s;};

    /**
     * country code ("280" for Germany).
     */
    int country() const { return _country;};
    void setCountry(int i) { _country=i;};

    /**
     * Your user id for that credit institute.
     */
    const string &user() const { return _user;};
    void setUser(const string &u) { _user=u;};

    instituteData(const string &data);
    instituteData();
    ~instituteData();

    CTError  fromString(const string &data);
    string toString() const;

    string dump();
  };


  /** @name Constructors/Destructor
   *
   * Methods to retrieve the private members of this class.
   */
  //@{
  HBCICard(const CTCard &c);

  ~HBCICard();
  //@}

  /** @name Opening and closing operations
   *
   * Methods to connect and disconnect the card. Most other methods
   * only work if the card is open.
   */
  //@{
  /**
   * When this method is called normally the card is already opened by
   * means of @ref openCard(). However, it is likely that openCard() has
   * been called assuming this card is only a CTCard() object, nothing
   * special. You may then call THIS method here on all known card classes
   * to check for the type of this card.
   * This method must assume that any file on the card is already selected,
   * so it is in most cases a good idea to select the MF as the first action
   * of this method.
   * If the executing class finds that the card inserted is not of a type
   * it can handle then it MUST return an error.
   */
  virtual CTError reopenCard();

  /**
   * Opens the card for usage.
   * This way the card is powered on.
   * This method does some basic checks and retrieves basic information
   * about the card (whether it is a memory card or a processor card,
   * the size of the memory etc).
   * When this method successfully returns the card may be used.
   * @author Martin Preuss<martin@libchipcard.de>
   * @return CTError object that holds the result (call isOk() to see if
   * there was an error)
   */
  virtual CTError openCard();

  /**
   * Call this if you have finished working with the card. After this
   * method is called you may safely remove the card from the reader.
   * @author Martin Preuss<martin@libchipcard.de>
   * @return CTError object that holds the result (call isOk() to see if
   * there was an error)
   */
  virtual CTError closeCard(bool force=false);
  //@}

  /** @name Informational methods
   *
   * These methods tell you about the type and the status of the card.
   */
  //@{
  /**
   * This method returns a short name of the class which handles this card.
   * A HBCI card for example returns "HBCICard". So you can use this method
   * to check for the type of the card.
   */
  virtual string cardType();

  /**
   * This method returns a comma separated list of all card types this card
   * inherits including the type of this card, e.g. a HBCI card would
   * return "CTProcessorCard, HBCICard". If you overload this method in your
   * own class (you SHOULD) you simply have to call this method of the
   * class it directly inherits. That class will then do the same, so that
   * there is a list upon return.
   */
  virtual string cardTypes();

  /**
   * This method returns the cardnumber. This number is quite unique.
   * @author Martin Preuss <martin@libchipcard.de>
   * @return on error en empty string will be returned
   */
  string cardNumber();
  //@}

  /** @name Card Data Methods
   *
   * These methods return information about the HBCI card.
   */
  //@{
  /**
   * Gets the card's id struct and selects the appropriate
   * DF_BANKING or DF_BANKING_20 DF. May throw an CTError.
   * @author Martin Preuss <martin@libchipcard.de>
   * @return new CardData object
   * null on error
   */
  CardData getCardId();

  /**
   * Reads the full EF_ID file from the MF of the chip card.
   * Is needed by HBCI.
   * @author Martin Preuss <martin@libchipcard.de>
   * @return CTError object that holds the result (call isOk() to see if
   * there was an error)
   */
  CTError getCID(string &cid);
  //@}

  /** @name Institute Data Methods
   *
   * These methods return information about institutes stored on the card.
   */
  //@{
  /**
   * Gets you the institute data struct for the given entry. The HBCI card
   * stores up to 5 entries with number 1 being the first.
   * You have to VERIFY your pin prior to calling this method !
   * @author Martin Preuss <martin@libchipcard.de>
   * @return object containing the institute data. If an error occurs
   * it will be thrown.
   */
  instituteData getInstituteData(int num);

  /**
   * This is a non-exception version, it is temporarily used be OpenHBCI.
   */
  CTError getInstituteData(int num, instituteData &idata);

  /**
   * This writes the given institute data to the card. Of course it has to
   * be open for this and you have to have verified your pin with the
   * card.
   * @author Martin Preuss <martin@libchipcard.de>
   * @return error object
   */
  CTError putInstituteData(int num, const instituteData &d);
  //@}

  /** @name Pin Verification Methods
   *
   * These methods let you verify the pin with the card.
   */
  //@{
  /**
   * Verifies your pin with the ec card.
   * @author Martin Preuss <martin@libchipcard.de>
   * @return CTError object that holds the result (call isOk() to see if
   * there was an error)
   * @param pin the PIN to verify
   */
  CTError verifyPin(const string &pin);

  /**
   * This method lets the user enter the pin via the pin pad.
   * @author Martin Preuss <martin@libchipcard.de>
   */
  CTError verifyPin();
  //@}

  /** @name Key Information Methods
   *
   * These methods return information about the keys stored on the card.
   */
  //@{
  /**
   * Returns the version of a the local EF_KEY (that is that EF_KEY
   * which resides in the currently selected DF).
   * @author Martin Preuss <martin@libchipcard.de>
   * @return true if version could be retrieved, false on error
   * @param key key number (starting with 1)
   * @param kv reference to a variable which receives the key version
   */
  bool getKeyVersion(int key, int &kv);

  /**
   * Returns the key number of the crypt key (with 1 being the first)
   * @author Martin Preuss <martin@libchipcard.de>
   * @return false on error
   */
  bool getCryptKeyNumber(int &kn);

  /**
   * Returns the key number of the sign key (with 1 being the first)
   * @author Martin Preuss <martin@libchipcard.de>
   * @return false on error
   */
  bool getSignKeyNumber(int &kn);
  //@}

  /** @name Cryptographic Methods
   *
   * These methods are involved in en-/decryption.
   */
  //@{
  /**
   * Creates a MAC from a 20 byte hash.
   * According to HBCI standard this has to be a RIPEMD-160 hash.
   * @author Martin Preuss <martin@libchipcard.de>
   * @return true if mac contains valid MAC, false on error
   * @param hash reference to a string containing the 20 bytes RIPEMD-160
   * hash
   * @param mac reference to a string that receives the 8 byte MAC.
   */
  bool hash2MAC(string &hash, string &mac);

  /**
   * Creates random data (8 bytes).
   * @author Martin Preuss <martin@libchipcard.de>
   * @return false on error
   */
  bool getRandom(string &d);

  /**
   * Crypts a block of 8 bytes.
   * It uses the encrypting function of the chip card. That means if
   * you crypt a block twice with this method here you do NOT get the
   * clear text again !
   * @author Martin Preuss<martin@libchipcard.de>
   * @param src reference to a string containing the 8 bytes source
   * @param dst reference to a string to receive the decoded 8 bytes
   */
  bool cryptBlock(string &src, string &dst);
  //@}

  /** @name Sequence Counter Methods
   *
   * These methods allow reading and writing of the cards sequence counter.
   * This counter is to be incremented after signing a HBCI message.
   */
  //@{
  /**
   * Reads the sequence counter from the chipcard.
   * This counter should be incremented before signing a HBCI message.
   * This method is only available to call after inserting the card.
   * @author Martin Preuss <martin@libchipcard.de>
   * @return true if value is read, false on error
   */
  bool readSEQ(unsigned int &d);

  /**
   * Stores the value of the sequence counter which is stored in this
   * class at this moment. Call this after incrementing this value !
   * @author Martin Preuss <martin@libchipcard.de>
   * @return false on error
   */
  bool writeSEQ(unsigned int d);
  //@}

};


#endif






