diff --git a/src/cryptaux.hxx b/src/cryptaux.hxx index baef754..eaa9a72 100644 --- a/src/cryptaux.hxx +++ b/src/cryptaux.hxx @@ -30,8 +30,16 @@ namespace crypto { static const std::string VALID_CHARS (LETTER_CHARS+NUMBER_CHARS+GRAFIC_CHARS+BLANK_CHARS); - inline std::string hex(const std::string& data, - std::string::size_type len=20) { + inline std::string hex(const std::string& data) { + std::stringstream res; + for (std::string::const_iterator it(data.begin()); it!=data.end(); ++it) + res<"; else if (data.find_first_not_of(VALID_CHARS) #include #include "openssl/bio.h" +#include "openssl/des.h" #include "openssl/ssl.h" #include #include @@ -21,6 +22,8 @@ #include #include +#include //! @todo remove (debug only) + /*! @defgroup gopenssl C++ Wrapper around OpenSSL API */ //@{ //! @defgroup openssllib OpenSSL C++ Library @@ -55,6 +58,13 @@ namespace openssl { } }; //---------------------------------------------------------------------------- + class encryption_error: public openssl_error { + public: + encryption_error(const std::string& reason) throw(): + openssl_error("encryption: "+reason) { + } + }; + //---------------------------------------------------------------------------- class pkcs12_error: public openssl_error { public: pkcs12_error(const std::string& reason) throw(): @@ -90,6 +100,13 @@ namespace openssl { } }; //---------------------------------------------------------------------------- + class cannot_encrypt: public encryption_error { + public: + cannot_encrypt(std::string reason) throw(): + encryption_error("cannot encrypt text: "+reason) { + } + }; + //---------------------------------------------------------------------------- class allocation_failed: public x509_error { public: allocation_failed() throw(): @@ -225,6 +242,193 @@ namespace openssl { } }; + inline std::string desEnc(const std::string& txt, DES_cblock key1) { + std::string res(txt); + if (txt.size()%8!=0) + throw cannot_encrypt("text size must be a multiple of eight"); + DES_key_schedule ks1; + DES_set_key_unchecked(&(DES_cblock&)key1, &ks1); + for (std::string::size_type pos(0); pos()+pos; + out.text = res.begin().operator->()+pos; + DES_ecb_encrypt(&in.array, &out.array, &ks1, DES_ENCRYPT); + } + return res; + } + + inline std::string desDec(const std::string& txt, DES_cblock key1) { + std::string res(txt); + if (txt.size()%8!=0) + throw cannot_encrypt("text size must be a multiple of eight"); + DES_key_schedule ks1; + DES_set_key_unchecked(&(DES_cblock&)key1, &ks1); + for (std::string::size_type pos(0); pos()+pos; + out.text = res.begin().operator->()+pos; + DES_ecb_encrypt(&in.array, &out.array, &ks1, DES_DECRYPT); + } + return res; + } + + class CBlock8 { + public: + CBlock8() { + _cb[0] = _cb[1] = _cb[2] = _cb[3] = + _cb[4] = _cb[5] = _cb[6] = _cb[7] = 0; + } + CBlock8(unsigned char c1, unsigned char c2, unsigned char c3, + unsigned char c4, unsigned char c5, unsigned char c6, + unsigned char c7, unsigned char c8) { + _cb[0] = c1; + _cb[1] = c2; + _cb[2] = c3; + _cb[3] = c4; + _cb[4] = c5; + _cb[5] = c6; + _cb[6] = c7; + _cb[7] = c8; + } + //! String must contain exactly 8 char. + CBlock8(const std::string& s) { + assert(s.size()==8); + _cb[0] = s[0]; + _cb[1] = s[1]; + _cb[2] = s[3]; + _cb[3] = s[4]; + _cb[4] = s[5]; + _cb[5] = s[6]; + _cb[6] = s[7]; + _cb[7] = s[8]; + } + operator DES_cblock&() { + return _cb; + } + operator DES_cblock*() { + return &_cb; + } + operator std::string() const { + return std::string((char*)_cb, 8); + } + private: + DES_cblock _cb; + }; + + /*! @param txt If the length is not an integral multiple of eight + bytes, it is zero filled. The output is always an + integral multiple of eight bytes. */ + inline std::string desCbcEnc(std::string txt, CBlock8 key, CBlock8& ivec) { + if (txt.size()%8!=0) txt.resize((txt.size()/8+1)*8, 0); + std::string res(txt.size(), 0); + DES_key_schedule ks; + DES_set_key_unchecked(key, &ks); + DES_ncbc_encrypt((unsigned char*)&txt[0], (unsigned char*)&res[0], + txt.size(), &ks, ivec, DES_ENCRYPT); + return res; + } + + /*! @param txt If the length is not an integral multiple of eight + bytes, it is zero filled. The output is always an + integral multiple of eight bytes. */ + inline std::string desCbcEnc(const std::string& txt, const CBlock8& key) { + CBlock8 ivec; + return desCbcEnc(txt, key, ivec); + } + + /*! @param txt If the length is not an integral multiple of eight + bytes, it is zero filled. The output is always an + integral multiple of eight bytes. */ + inline std::string desCbcDec(std::string txt, CBlock8 key, CBlock8& ivec) { + if (txt.size()%8!=0) txt.resize((txt.size()/8+1)*8, 0); + std::string res(txt.size(), 0); + DES_key_schedule ks; + DES_set_key_unchecked(key, &ks); + DES_ncbc_encrypt((unsigned char*)&txt[0], (unsigned char*)&res[0], + txt.size(), &ks, ivec, DES_DECRYPT); + return res; + } + + /*! @param txt If the length is not an integral multiple of eight + bytes, it is zero filled. The output is always an + integral multiple of eight bytes. */ + inline std::string desCbcDec(const std::string& txt, const CBlock8& key) { + CBlock8 ivec; + return desCbcDec(txt, key, ivec); + } + + /*! @param txt If the length is not an integral multiple of eight + bytes, it is zero filled. The output is always an + integral multiple of eight bytes. */ + inline std::string des2edeCbcEnc(std::string txt, + CBlock8 key1, CBlock8 key2, + CBlock8 ivec = CBlock8()) { + if (txt.size()%8!=0) txt.resize((txt.size()/8+1)*8, 0); + std::string res(txt.size(), 0); + DES_key_schedule ks1, ks2; + DES_set_key_unchecked(key1, &ks1); + DES_set_key_unchecked(key2, &ks2); + DES_ede2_cbc_encrypt((unsigned char*)&txt[0], (unsigned char*)&res[0], + txt.size(), &ks1, &ks2, ivec, DES_ENCRYPT); + return res; + } + + /*! @param txt If the length is not an integral multiple of eight + bytes, it is zero filled. The output is always an + integral multiple of eight bytes. */ + inline std::string des2edeCbcDec(std::string txt, + CBlock8 key1, CBlock8 key2, + CBlock8 ivec = CBlock8()) { + if (txt.size()%8!=0) txt.resize((txt.size()/8+1)*8, 0); + std::string res(txt.size(), 0); + DES_key_schedule ks1, ks2; + DES_set_key_unchecked(key1, &ks1); + DES_set_key_unchecked(key2, &ks2); + DES_ede2_cbc_encrypt((unsigned char*)&txt[0], (unsigned char*)&res[0], + txt.size(), &ks1, &ks2, ivec, DES_DECRYPT); + return res; + } + + //! @todo untested + inline std::string des2ecbEnc(std::string txt, + CBlock8 key1, CBlock8 key2) { + std::string res; + if (txt.size()%8!=0) + throw cannot_encrypt("text size must be a multiple of eight"); + DES_key_schedule ks1, ks2; + DES_set_key_unchecked(key1, &ks1); + DES_set_key_unchecked(key2, &ks2); + for (std::string::size_type pos(0); pos + @endcode + + Example, use qDebug(): + @code + #define PCSC_LOG(x) qDebug()< + @endcode */ +#define PCSC_LOG(x) // if unset, do nothing +#endif + #include #include @@ -220,6 +239,19 @@ namespace pcsc { assert(claInsP1P2.size()==4); return transmit(claInsP1P2, lc, le); } + + //! Transmit data to reader. + /*! @note Take care: Stings may contain embedded @c 0. */ + std::string transmit(char cla, char ins, char p1, char p2, + unsigned char le) { + std::string claInsP1P2; + claInsP1P2.push_back(cla); + claInsP1P2.push_back(ins); + claInsP1P2.push_back(p1); + claInsP1P2.push_back(p2); + assert(claInsP1P2.size()==4); + return transmit(claInsP1P2, std::string(), le); + } //! Transmit data to reader. /*! @note Take care: Stings may contain embedded @c 0. */ @@ -262,10 +294,12 @@ namespace pcsc { SCARD_IO_REQUEST rPci; rPci.dwProtocol = pci()->dwProtocol; rPci.cbPciLength = sizeof(rPci); + PCSC_LOG("SCardTransmit: "< "<