[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-core-devel
Subject:    KMD5
From:       Dirk Mueller <mueller () kde ! org>
Date:       2001-11-16 23:46:41
[Download RAW message or body]

From: Dirk Mueller <mueller@kde.org>
To: kde-core-devel@kde.org
Cc: 
Bcc: 
Subject: KMD5 rewrite
Reply-To: 

Hi, 


after a 5 minute experience with kmail I noticed that some of the leaks of 
kmail come from KMD5, where every calculation leaked at least 16 bytes 
because of incorrect class usage. I had a look at the class and I noticed a 
lot of flaws in the API, so I decided to fix those. 

The things in particular: 

- KMD5 was not able to md5 a set of binary data. Thats because it assumed
  that it can call strlen() on it to get the length. Thats broken. 

- KMD5 provided methods that took QString, but did not calculate the MD5
  sum of the unicode values but converted it to latin1() first. thats 
  broken. 

- it provided QByteArray and QCString variants. as QCString inherits 
  QByteArray, the QCString variants are useless. 

- I didn't quite like the FILE* variant and the way it reports errors in 
  a state variable. thats uncomfortable to use. I changed it in a QIODevice
  (which QFile inherits) and a bool return value. more intuitive and
  more consistent, and also allows you to pass it anything else that
  inherits a QIODevice. 

- the error tracking of the class usage is awkward. I didn't find a single
  usage of KMD5 that checks for these error states. IMHO if there are ways
  to misuse the API, its a flaw in the API and not in the application. 
  Granted, the state nature of MD5 makes it difficult to design the API. 

  I removed the finalize() method - its automatically finalized when
  you request the digest() value. after that you cannot update the 
  digest anymore without calling reset() first. 

  This makes the class much easier to use in my opinion and is less
  error-prone. 

- it forced the user to USE QUINT_8. This isn't widely used imho. I made
  it accept char* and unsigned char*

- it added two typedefs HASH and HEXHASH. These are not namespace clean 
  and do not belong in kde libs therefore. I removed HEXHASH completely
  (its a QCString now for other reasons see below) and replaced HASH
  with KMD5::Digest. This is more intuitive what it is and is namespace 
  clean. 

- KMD5 had a state variable that identified a "HASH" as being BIN or HEX. 
  given that hex is just a representation of the Digest, I don't think
  this belongs in the class. it has a hexDigest() method which returns
  the hexDigest as a QCString now and a rawDigest() method that returns
  KMD5::Digest. 

- it had several variants of verify() that were not static but needed
  the message and the digest to compare it with and returned bool. 
  I changed it to compare the given digest with its _own_ computed
  digest, which I find more useful in a OO design. 

- the comparison if a digest matches was badly broken - it assumed
  that a digest can not contain NUL characters which is not true. 

- the documentation of the class was very incomplete, as some sentences
  simply stopped in the middle without an ending or any contents. I
  shortened the documentation and rewrote in large parts to match it the
  actual behaviour and usage of the class.   

- the documentation was wrong in many places. i.e. it said that
  the user does not have to care about free'ing the rawDigest() return 
  value - which was not true and hence causes the leaks everywhere. 

- to fix the leaks in an elegant way I changed the unprotected char* 
  return values of the digest() variants to QCString. IMHO we shouldn't
  use unprotected char* returns in an API - let C coders do that, we
  have better means in our language. 

- the class has a private class pointer, but didn't have copy or assignment
  operators. This wouldn't allow a BC extension. as I don't think its
  useful to copy a KMD5 instance, I've disabled copying for now. 
  We could properly impelement copy and assignment operator though for
  being able to keep binary compatibility. 

- the method had a init() method that was _protected_. I fixed the API flaw
  by making the method private. 

- the class leaked a file descriptor if there was an error reading the
  file. 

- probably a few other errors I forgot about already..

Unsolved problems: 

- The class is not completely endianess-safe it seems. 

- the removal of the HASH and HEXHASH makes the patch source-incompatible. 
  however, I think its still worth the trouble as KMD5 isn't exactly
  commonly used and it was a bad namespace breakage. We should fix it
  before 3.0 (IMHO). these two typedefs didn't even match our 
  naming sheme. Opinions?

- rawDigest() returns a const reference to its own state reference. its
  not much of a problem as the digest won't ever change after rawDigest()
  was called (the state is "finalized") then, however, when the class
  is destructed the return value is dangling when you don't make a copy
  of it. I'm not sure if that is a problem. it is not in the code I found,
  they never store the digest() values over the lifetime of KMD5. 
  

Please have a look and comment if we can have a greatly fixed API in KDE 3 
or if the source incompatible changes are too much. Note I didn't even test 
if the class still works - however I didn't change anything in the "core 
calculation" routine - so it should still work fine. however I don't know a
MD5 POP3 or webserver to test with :-/


Dirk

["kmd5fix.patch" (text/plain)]

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 <stdio.h> // for FILE
 #include <qglobal.h>
 #include <qstring.h>
-
-typedef char HASH[16];
-typedef char HASHHEX[33];
+#include <qiodevice.h>
 
 /**
  * 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:
  *
  * <PRE>
- *  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() );
  * </PRE>
  *
  * 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:
  *
  * <PRE>
  *  context.reset();
- *  context.update( QCString("TWO") );
- *  context.update( QCString("THREE") );
- *  printf ( "Raw Digest output: %s", static_cast<char*>(context.rawDigest()) );
- *  printf ( "Hex Digest output: %s", context.hexDigest() );
- * </PRE>
- *
- * 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:
- *
- * <PRE>
- *  KMD5 context;
- *  context.update(QCString("ONE"));
- *  context.update(QCString("TWO"));
- *  context.update(QCString("THREE"));
- *  context.finalize();
- *  printf ( "Raw Digest output: %s", static_cast<char*>(context.rawDigest()) );
- *  printf ( "Hex Digest output: %s", context.hexDigest() );
+ *  context.update( "TWO" );
+ *  context.update( "THREE" );
+ *  printf ( "Hex Digest output: %s", context.hexDigest().data() );
  * </PRE>
  *
  * @short An adapted C++ implementation of RSA Data Securities MD5 algorithm.
- * @author Dawit Alemayehu <adawit@kde.org>
+ * @author Dirk Mueller <mueller@kde.org>, Dawit Alemayehu <adawit@kde.org>
  */
+
 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!
-   *
-   * <u>IMPORTANT:</u> 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 <b>not</b> 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.
-   *
-   * <u>IMPORTANT:</u> 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<const unsigned char*>(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<char *>(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<Q_UINT8 *>(in.data()) );
-}
+    if (len < 0)
+        len = qstrlen(reinterpret_cast<const char*>(in));
 
-void KMD5::update( const QByteArray& in )
-{
-    update( reinterpret_cast<Q_UINT8 *>(in.data()), in.size() );
-}
+    if (!len)
+        return;
 
-void KMD5::update( Q_UINT8 *in, int len )
-{
-    if ( len == -1 )
-        len = qstrlen( reinterpret_cast<char *>(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<Q_UINT32>( len );
 
-    if (m_finalized)
-    {
-        m_error = ERR_ALREADY_FINALIZED;
-        return;
-    }
-
     buffer_index = static_cast<Q_UINT32>((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<const unsigned char*>(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<char*>(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<Q_UINT32>((m_count[0] >> 3) & 0x3f);
     padLen = (index < 56) ? (56 - index) : (120 - index);
-    update (PADDING, padLen);
+    update (reinterpret_cast<const char*>(PADDING), padLen);
 
     // Append length (before padding)
-    update (bits, 8);
+    update (reinterpret_cast<const char*>(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<char *>(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<void *>(m_buffer), 0, sizeof(*m_buffer));
-    memset ( static_cast<void *>(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<char *>(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


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic