Index: kmdcodec.h =================================================================== RCS file: /home/kde/kdelibs/kdecore/kmdcodec.h,v retrieving revision 1.31 diff -u -5 -d -p -r1.31 kmdcodec.h --- kmdcodec.h 2001/11/16 05:46:22 1.31 +++ kmdcodec.h 2001/11/16 23:46:35 @@ -36,13 +36,11 @@ #define KBase64 KCodecs #include // for FILE #include #include - -typedef char HASH[16]; -typedef char HASHHEX[33]; +#include /** * A wrapper class for the most commonly used encoding and * decoding algorithms. Currently there is support for encoding * and decoding input using base64, uu and the quoted-printable @@ -336,349 +334,163 @@ private: * * The default constructor is designed to provide much the same * functionality as the most commonly used C-implementation while * the other three constructors are meant to further simplify the * message digest calculations by calculating the result in one - * single step. Additionally, you have the ability to obtain the - * result in either raw (16-bytes) or hexidecimal formats (33-bytes) - * using @ref rawDigest and @ref hexDigest respectivelly, you can also - * reuse a single instance to make multiple message digest calculations - * by simply invoking @reset(). + * single step. + * KMD5 is state-based, that means you can add new contents with + * update() as long as you didn't request the digest value yet. + * After the digest value was requested, the object is "finalized" + * and you have to call reset() to be able to do another calculation + * with it. + * The reason for this behaviour is that upon requesting the message + * digest KMD5 has to pad the received contents up to a 64 byte + * boundary to calculate its value. After this operation it is + * not possible to resume consuming data. * - * @sect Useage: + * @sect Usage: * - * A common useage of this class: + * A common usage of this class: * *
- *  HASH rawResult;
- *  HASHHEX hexResult;
- *  QCString test1 = "This is a simple test.";
+ *  KMD5::Digest rawResult;
+ *  const char* test1 = "This is a simple test.";
  *
  *  KMD5 context( test1 );
- *  context.rawDigest( rawResult );
- *  context.hexDigest( hexResult );
- *  printf ( "Raw Digest output: %s", rawResult );
- *  printf ( "Hex Digest output: %s", hexResult );
+ *  printf ( "Hex Digest output: %s", context.hexDigest().data() );
  * 
* * To cut down on the unnecessary overhead of creating multiple KMD5 objects, * you can simply invoke @ref reset() to resue the same object in making another * calculation: * *
  *  context.reset();
- *  context.update( QCString("TWO") );
- *  context.update( QCString("THREE") );
- *  printf ( "Raw Digest output: %s", static_cast(context.rawDigest()) );
- *  printf ( "Hex Digest output: %s", context.hexDigest() );
- * 
- * - * NOTE: Invoke @ref reset() deletes the previously calculated message - * digest value. Thus, be sure to copy the previous result before you - * reuse the same object! Also, if you use one of the convienence - * constructors you must first invoke reset(), before calling any of the - * update functions. Otherwise, the call to @ref update will fail. - * - * Here is an of KMD5 useage much along the same lines of how one would - * use the commonly available C-implementations of the MD5 algorithm: - * - *
- *  KMD5 context;
- *  context.update(QCString("ONE"));
- *  context.update(QCString("TWO"));
- *  context.update(QCString("THREE"));
- *  context.finalize();
- *  printf ( "Raw Digest output: %s", static_cast(context.rawDigest()) );
- *  printf ( "Hex Digest output: %s", context.hexDigest() );
+ *  context.update( "TWO" );
+ *  context.update( "THREE" );
+ *  printf ( "Hex Digest output: %s", context.hexDigest().data() );
  * 
* * @short An adapted C++ implementation of RSA Data Securities MD5 algorithm. - * @author Dawit Alemayehu + * @author Dirk Mueller , Dawit Alemayehu */ + class KMD5 { - public: - - /** - * HEX hexidecimal representation of the message digest - * BIN binary representation of the message digest - */ - enum DigestType { BIN, HEX }; - /** - * ERR_NONE no error occured. [default] - * ERR_ALREADY_FINALIZED @ref finalize() has already been invoked. - * ERR_NOT_YET_FINALIZED @ref hexDigest() or @ref rawDigest() invoked before @ref finalize(). - * ERR_CANNOT_READ_FILE indicates a problem while trying to read the given file. - * ERR_CANNOT_CLOSE_FILE indicates a problem while trying to close the given file. - */ - enum ErrorType { ERR_NONE, ERR_ALREADY_FINALIZED, ERR_NOT_YET_FINALIZED, - ERR_CANNOT_READ_FILE, ERR_CANNOT_CLOSE_FILE }; + typedef unsigned char Digest[16]; - /** - * Default constructor that only performs initialization. - * Unlike the other constructors - */ KMD5(); /** - * Constructor that initializes, computes, and finalizes - * the message digest for the given string. + * Constructor that updates the digest for the given string. * - * NOTE: This is a convience constructor. It is provided to - * allow compatiability with the C implementation of this digest. + * @param in C string or binary data + * @param len if negative, calculates the length by using + * strlen on the first parameter, otherwise + * it trusts the given length (does not stop on NUL byte). */ - KMD5(Q_UINT8 * in); + KMD5(const char* in, int len = -1); /** - * Constructor that initializes, computes, and finalizes - * the message digest for the given file. + * @overload * - * NOTE: This is a convience constructor. As such it does - * not allow the update of the message after it has been - * invoked. If you need to update the message after creating - * the constructor, - */ - KMD5(FILE *file); - - /** * Same as above except it accepts a QByteArray as its argument. */ KMD5(const QByteArray& a ); - - /** - * Same as above except it accepts a QCString as its argument. - */ - KMD5(const QCString& in); - - /** - * @deprcated. Use @ref KMD5(const QCString& in) instead! - * - * IMPORTANT: This constructor has been depricated and - * will be removed in future release. This is done to avoid - * loss of data from misuse of the function since it first - * converts the given data into Latin-1. Additionally, this - * conversion is very slow! - */ - KMD5(const QString& in); - - /** - * Updates the message to be digested. - * - * @param input message to be added to the digest (QByteArray). - */ - void update (const QByteArray& in ); - - /** - * Same as above except it accepts a pointer to FILE. - * - * NOTE that the file must have been already opened. If you - * want the file to be automatically closed, set @p closeFile - * to TRUE. - * - * @param file a pointer to FILE as returned by calls like f{d,re}open - * @param closeFile if true closes the file using fclose. - */ - void update (FILE *file, bool closeFile = false ); - /** - * Updates the message to be digested. + * Updates the message to be digested. Be sure to add all data + * before you read the digest. After reading the digest, you + * can not add more data! * - * @param input message to be added to digest (unsigned char*) + * @param input message to be added to digest * @param len the length of the given message. - */ - void update (Q_UINT8 * in, int len = -1 ); - - /** - * Same as above except it accepts a QCString as its argument. */ - void update ( const QCString& in ); - - /** - * Same as above except it accepts a QString as its argument. - * - * IMPORTANT: This function is ONLY provided for convenience - * and backward compatability! Using it can result in an incorrect - * digest caclculation since the conversion of the QString input to - * latin-1 can and will result in data loss if the input data contains - * non-latin1 characters. As such it is highly recommended that you - * avoid this function unless you are absolutely certain that your - * input does not contain any non-latin1 character!! - */ - void update ( const QString& in ); - - /** - * Finalizes the message digest calculation. - * - * If you used the default constructor, you must invoke this function - * before you can obtain the calculated digest value. - */ - void finalize(); - - /** - * Compares the message digest supplied messaged digest @p msg_digest - * with the one calculated for the input QCString @p input. - * - * @em NOTE: Calling this function will reset any previously calcualted - * digests. If you want to verify your token with the current digest - * value, use @ref verify( const char*, DigestType ) instead. - * - * @param input the message to be added to the digest value - * @param msg_digest the digest to compare the result against - * @param type the format of the result for comparison (binary or hexidecimal). - * - * @return true if the digests match, otherwise false. - */ - bool verify( const QCString& in, const char * msg_digest, - DigestType type = HEX ); - - /** - * Same as above except it takes a QString argument as its input. - * - * @em IMPORTANT: This function is ONLY provided for convenience - * and backward compatability! Using it can result in an incorrect - * verification since the conversion of the QString input to latin-1 - * can and will result in data loss if the input data contains non- - * latin1 characters. As such it is highly recommended that you - * avoid this function unless you are absolutely certain that your - * input does not contain any non-latin1 character!! - */ - bool verify( const QString& in, const char * msg_digest, - DigestType type = HEX ); + void update(const char* in, int len = -1) { update(reinterpret_cast(in), len); } + void update(const unsigned char* in, int len = -1); /** - * Same as above except it takes a pointer to a FILE as its input. + * @overload * - * @em NOTE: Calling this function will reset any previously - * calcualted digests. If you want to verify your token with the - * current digest value, use @ref verify(const char*, DigestType) - * instead. + * @param input message to be added to the digest (QByteArray). */ - bool verify( FILE* f, const char * msg_digest, DigestType type = HEX ); + void update(const QByteArray& in ); /** - * Compares the given string with with the current message digest. + * @overload * - * Unlike the other verification functions this one does not reset - * the calculated message digest if one is already present. Rather - * it simply compares the given digest value against the calculated - * one. + * reads the data from an I/O device, i.e. from a file (QFile). * - * @em NOTE: This function will return false if there was an error - * calculating the message digest as well as when the verification - * fails. You can use @ref hasErrored() to determine which is the case. + * NOTE that the file must be open for reading. * - * @param msg_digest the digest to compare the result against - * @param type the format of the result for comparison (binary - * or hexidecimal). + * @param file a pointer to FILE as returned by calls like f{d,re}open * - * @return true if the digests match, otherwise false. + * @returns false if an error occured during reading. */ - bool verify( const char* msg_digest, DigestType type = HEX ); + bool update(QIODevice& file); /** - * Re-initializes internal paramters. - * - * Note that calling this function will reset all internal variables - * and hence any calculated message digest. Invoke this function only - * when you reuse the same object to perform another message digest - * calculation. + * Calling this function will reset the calculated message digest. + * Use this method to perform another message digest calculation + * without recreating the KMD5 object. */ void reset(); /** - * Returns the raw 16-byte binary value of the message - * digest. - * - * NOTE: you are responsible for making a copy of this - * string. - * - * @return the raw represenation of the digest or NULL - * if there was error calculating the digest. + * @return the raw represenation of the digest */ - Q_UINT8* rawDigest (); + const Digest& rawDigest (); /** * Fills the given array with the binary representation of the * message digest. * * Use this method if you do not want to worry about making * copy of the digest once you obtain it. * * @param bin an array of 16 characters ( char[16] ) */ - void rawDigest( HASH bin ); + void rawDigest( KMD5::Digest& bin ); /** * Returns the value of the calculated message digest in * a hexcidecimal representation. - * - * The 32-byte hexidecimal value is terminated by a NULL - * character to form a properly terminated string. Also - * note that that if - * - * NOTE: You are responsible for making a copy of - * this string! - * - * @return the hex represenation of the digest or NULL if - * there was error calculating the digest. */ - char * hexDigest (); - - /** - * Fills the given array with the hexcidecimal representation of - * the message digest. - * - * Use this method if you do not want to worry about making - * copy of the digest once you obtain it. Also note that this - * method appends a NULL charater to the end of the array to - * form a properly terminated string. This is the reason why - * the hexDigest is 33 characters long. - * - * @param bin an array of 33 characters ( char[33] ) - */ - void hexDigest( HASHHEX hex ); + QCString hexDigest (); /** - * Indicates whether the message digest calculation failed or - * succeeded. Use @ref error() to determine the error type. - * - * @return false if errors are present, otherwise true + * @overload */ - bool hasErrored() const { return (m_error != ERR_NONE); } + void hexDigest(QCString&); /** - * Returns the type of error that occurred. - * - * @return the error type. See @ref ErrorType for details. + * returns true if the calculated digest for the given + * message matches the given one. */ - int error() const { return m_error; } + bool verify( const KMD5::Digest& digest); protected: - /** - * Initializer called by all constructors - */ - void init(); - - /** * Performs the real update work. Note * that length is implied to be 64. */ - void transform( Q_UINT8 * buffer ); + void transform( const unsigned char* buffer ); /** - * Returns true if the current message digest matches @p msg_digest. + * finalizes the digest */ - bool isDigestMatch( const char * msg_digest, DigestType type ); + void finalize(); private: + KMD5(const KMD5& u); + KMD5& operator=(const KMD5& md); - void encode( Q_UINT8 *output, Q_UINT32 *in, Q_UINT32 len ); - void decode( Q_UINT32 *output, Q_UINT8 *in, Q_UINT32 len ); + void init(); + void encode( unsigned char* output, Q_UINT32 *in, Q_UINT32 len ); + void decode( Q_UINT32 *output, const unsigned char* in, Q_UINT32 len ); Q_UINT32 rotate_left( Q_UINT32 x, Q_UINT32 n ); Q_UINT32 F( Q_UINT32 x, Q_UINT32 y, Q_UINT32 z ); Q_UINT32 G( Q_UINT32 x, Q_UINT32 y, Q_UINT32 z ); Q_UINT32 H( Q_UINT32 x, Q_UINT32 y, Q_UINT32 z ); @@ -694,12 +506,11 @@ private: private: Q_UINT32 m_state[4]; Q_UINT32 m_count[2]; Q_UINT8 m_buffer[64]; - Q_UINT8 m_digest[16]; - ErrorType m_error; + Digest m_digest; bool m_finalized; struct KMD5Private; KMD5Private* d; }; Index: kmdcodec.cpp =================================================================== RCS file: /home/kde/kdelibs/kdecore/kmdcodec.cpp,v retrieving revision 1.45 diff -u -5 -d -p -r1.45 kmdcodec.cpp --- kmdcodec.cpp 2001/11/16 05:46:22 1.45 +++ kmdcodec.cpp 2001/11/16 23:46:35 @@ -745,79 +745,45 @@ QString KCodecs::decodeString( const QSt KMD5::KMD5() { init(); } -KMD5::KMD5( Q_UINT8 *in ) -{ - init(); - update( in, qstrlen(reinterpret_cast(in)) ); - finalize(); -} - -KMD5::KMD5( const QCString& in ) -{ - init(); - update( in ); - finalize(); -} - -KMD5::KMD5( const QString& in ) +KMD5::KMD5(const char *in, int len) { init(); - update( in ); - finalize(); + update(in, len); } -KMD5::KMD5( const QByteArray& in ) +KMD5::KMD5(const QByteArray& in) { init(); update( in ); - finalize(); } -KMD5::KMD5(FILE *f) -{ - init(); - update( f, true ); - finalize (); -} - -void KMD5::update ( const QString& str ) +void KMD5::update(const QByteArray& in) { - QByteArray in; - in.setRawData( str.latin1(), str.length() ); - update( in ); - in.resetRawData( str.latin1(), str.length() ); + update(in.data(), int(in.size())); } -void KMD5::update ( const QCString& in ) +void KMD5::update(const unsigned char* in, int len) { - update( reinterpret_cast(in.data()) ); -} + if (len < 0) + len = qstrlen(reinterpret_cast(in)); -void KMD5::update( const QByteArray& in ) -{ - update( reinterpret_cast(in.data()), in.size() ); -} + if (!len) + return; -void KMD5::update( Q_UINT8 *in, int len ) -{ - if ( len == -1 ) - len = qstrlen( reinterpret_cast(in) ); + if (m_finalized) { + kdWarning() << "KMD5::update called after state was finalized!" << endl; + return; + } Q_UINT32 in_index; Q_UINT32 buffer_index; Q_UINT32 buffer_space; Q_UINT32 in_length = static_cast( len ); - if (m_finalized) - { - m_error = ERR_ALREADY_FINALIZED; - return; - } - buffer_index = static_cast((m_count[0] >> 3) & 0x3F); if ( (m_count[0] += (in_length << 3))<(in_length << 3) ) m_count[1]++; @@ -829,69 +795,55 @@ void KMD5::update( Q_UINT8 *in, int len memcpy (m_buffer + buffer_index, in, buffer_space); transform (m_buffer); for (in_index = buffer_space; in_index + 63 < in_length; in_index += 64) - transform (in+in_index); + transform (reinterpret_cast(in+in_index)); buffer_index = 0; } else in_index=0; memcpy(m_buffer+buffer_index, in+in_index, in_length-in_index); } -void KMD5::update( FILE *file, bool closeFile ) +bool KMD5::update(QIODevice& file) { - Q_UINT8 buffer[1024]; + char buffer[1024]; int len; - while ((len=fread(buffer, 1, 1024, file))) + while ((len=file.readBlock(reinterpret_cast(buffer), sizeof(buffer))) > 0) update(buffer, len); - // Check if we got to this point because - // we reached EOF or an error. - if ( !feof( file ) ) - { - m_error = ERR_CANNOT_READ_FILE; - return; - } - - // Close the file iff the flag is set. - if ( closeFile && fclose (file) ) - m_error = ERR_CANNOT_CLOSE_FILE; + return file.atEnd(); } void KMD5::finalize () { + if (m_finalized) return; + Q_UINT8 bits[8]; Q_UINT32 index, padLen; - static Q_UINT8 PADDING[64]= + static unsigned char PADDING[64]= { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - if (m_finalized) - { - m_error = ERR_ALREADY_FINALIZED; - return; - } - //encode (bits, m_count, 8); memcpy( bits, m_count, 8 ); // Pad out to 56 mod 64. index = static_cast((m_count[0] >> 3) & 0x3f); padLen = (index < 56) ? (56 - index) : (120 - index); - update (PADDING, padLen); + update (reinterpret_cast(PADDING), padLen); // Append length (before padding) - update (bits, 8); + update (reinterpret_cast(bits), 8); // Store state in digest //encode (m_digest, m_state, 16); memcpy( m_digest, m_state, 16 ); @@ -899,129 +851,75 @@ void KMD5::finalize () memset ( (void *)m_buffer, 0, sizeof(*m_buffer)); m_finalized = true; } -void KMD5::reset() -{ - init(); -} - -bool KMD5::verify( const char * msg_digest, DigestType type ) -{ - if ( !m_finalized || !m_digest || m_error != ERR_NONE ) - return false; - return isDigestMatch( msg_digest, type ); -} -bool KMD5::verify( FILE* f, const char * msg_digest, DigestType type ) +bool KMD5::verify( const KMD5::Digest& digest) { - init(); - update( f ); finalize(); - return isDigestMatch( msg_digest, type ); + return (0 == memcmp(rawDigest(), digest, sizeof(KMD5::Digest))); } -bool KMD5::verify( const QCString& in, const char * msg_digest, - DigestType type ) +const KMD5::Digest& KMD5::rawDigest() { - init(); - update( in ); finalize(); - return isDigestMatch( msg_digest, type ); + return m_digest; } -bool KMD5::verify( const QString& in, const char * msg_digest, - DigestType type ) +void KMD5::rawDigest( KMD5::Digest& bin ) { - init(); - update( in ); finalize(); - return isDigestMatch( msg_digest, type ); + memcpy( bin, m_digest, 16 ); } -Q_UINT8* KMD5::rawDigest() -{ - Q_UINT8* s = new Q_UINT8[16]; - rawDigest( reinterpret_cast(s) ); - if ( m_error == ERR_NONE ) - return s; - else - return '\0'; -} -void KMD5::rawDigest( HASH bin ) +QCString KMD5::hexDigest() { - if (!m_finalized) - { - m_error = ERR_NOT_YET_FINALIZED; - return; - } - memcpy( bin, m_digest, 16 ); + QCString s(33); + + finalize(); + sprintf(s.data(), "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + m_digest[0], m_digest[1], m_digest[2], m_digest[3], m_digest[4], m_digest[5], + m_digest[6], m_digest[7], m_digest[8], m_digest[9], m_digest[10], m_digest[11], + m_digest[12], m_digest[13], m_digest[14], m_digest[15]); + + return s; } -char * KMD5::hexDigest() +void KMD5::hexDigest(QCString& s) { - char *s = new char[33]; - hexDigest( s ); - if ( m_error == ERR_NONE ) - return s; - else - return 0; + s.resize(33); + sprintf(s.data(), "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + m_digest[0], m_digest[1], m_digest[2], m_digest[3], m_digest[4], m_digest[5], + m_digest[6], m_digest[7], m_digest[8], m_digest[9], m_digest[10], m_digest[11], + m_digest[12], m_digest[13], m_digest[14], m_digest[15]); } -void KMD5::hexDigest( HASHHEX hex ) +void KMD5::init() { - if (!m_finalized) - { - m_error = ERR_NOT_YET_FINALIZED; - return; - } - - for (int i=0; i<16; i++) - sprintf(hex+i*2, "%02x", m_digest[i]); - hex[32]='\0'; + d = 0; + reset(); } -void KMD5::init() +void KMD5::reset() { m_finalized = false; - m_error = ERR_NONE; m_count[0] = 0; m_count[1] = 0; m_state[0] = 0x67452301; m_state[1] = 0xefcdab89; m_state[2] = 0x98badcfe; m_state[3] = 0x10325476; - - memset ( static_cast(m_buffer), 0, sizeof(*m_buffer)); - memset ( static_cast(m_digest), 0, sizeof(*m_digest)); -} -bool KMD5::isDigestMatch( const char * msg_digest, DigestType type ) -{ - bool result = false; - - switch (type) - { - case HEX: - if ( ::qstrcmp( hexDigest(), msg_digest ) == 0 ) - result = true; - break; - case BIN: - if ( ::qstrcmp( reinterpret_cast(rawDigest()), msg_digest ) == 0 ) - result = true; - break; - default: - break; - } - return result; + memset ( m_buffer, 0, sizeof(*m_buffer)); + memset ( m_digest, 0, sizeof(*m_digest)); } -void KMD5::transform( Q_UINT8 block[64] ) +void KMD5::transform( const unsigned char block[64] ) { Q_UINT32 a = m_state[0], b = m_state[1], c = m_state[2], d = m_state[3], x[16]; decode (x, block, 64); @@ -1160,11 +1058,11 @@ void KMD5::II ( Q_UINT32& a, Q_UINT32 b, a += I(b, c, d) + x + ac; a = rotate_left (a, s) +b; } -void KMD5::encode ( Q_UINT8 *output, Q_UINT32 *in, Q_UINT32 len ) +void KMD5::encode ( unsigned char* output, Q_UINT32 *in, Q_UINT32 len ) { #if !defined(WORDS_BIGENDIAN) memcpy(output, in, len); #else @@ -1179,11 +1077,11 @@ void KMD5::encode ( Q_UINT8 *output, Q_U #endif } // Decodes in (Q_UINT8) into output (Q_UINT32). Assumes len is a // multiple of 4. -void KMD5::decode (Q_UINT32 *output, Q_UINT8 *in, Q_UINT32 len) +void KMD5::decode (Q_UINT32 *output, const unsigned char* in, Q_UINT32 len) { #if !defined(WORDS_BIGENDIAN) memcpy(output, in, len); #else