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

List:       kde-core-devel
Subject:    [PATCH] SHA1 in kdelibs/kdecore/kmdcodec
From:       Szombathelyi "György" <gyurco () freemail ! hu>
Date:       2004-11-06 23:20:29
Message-ID: 200411070020.29671.gyurco () freemail ! hu
[Download RAW message or body]

Hello!

What about adding an SHA1 implementation to kmdcodec? There are at least four 
independent SHA1 code in the various KDE modules, it would be good to have 
only one.  I took the implementation from Kopete.
The patch also contains the modifications in kwallet to use the new code.
Should I commit?

Bye,
György

____________________________________________________________________
Miert fizetsz az internetert? Korlatlan, ingyenes internet hozzaferes a FreeStarttol.
Probald ki most! http://www.freestart.hu

["sha1.diff" (text/x-diff)]

Index: kdecore/kmdcodec.cpp
===================================================================
RCS file: /home/kde/kdelibs/kdecore/kmdcodec.cpp,v
retrieving revision 1.62
diff -u -p -u -r1.62 kmdcodec.cpp
@@ -1500,3 +1495,273 @@ void KMD4::transform( Q_UINT32 buf[4], Q
   buf[2] += c;
   buf[3] += d;
 }
+
+/****************************************************************************
+  SHA1 - from a public domain implementation by Steve Reid (steve@edmweb.com)
+****************************************************************************/
+
+KSHA1::KSHA1()
+{
+    init();
+}
+
+KSHA1::KSHA1(const char *in, int len)
+{
+    init();
+    update(in, len);
+}
+
+KSHA1::KSHA1(const QByteArray& in)
+{
+    init();
+    update( in );
+}
+
+KSHA1::KSHA1(const QCString& in)
+{
+    init();
+    update( in );
+}
+
+void KSHA1::update(const QByteArray& in)
+{
+    update(in.data(), int(in.size()));
+}
+
+void KSHA1::update(const QCString& in)
+{
+    update(in.data(), int(in.length()));
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void KSHA1::update(const unsigned char *in, int len)
+{
+  if (len < 0)
+      len = qstrlen(reinterpret_cast<const char*>(in));
+
+  if (!len)
+      return;
+
+  if (m_finalized) {
+      kdWarning() << "KSHA1::update called after state was finalized!" << endl;
+      return;
+  }
+  Q_UINT32 i, j;
+
+  j = (m_count[0] >> 3) & 63;
+  if((m_count[0] += len << 3) < ((Q_UINT32)len << 3))
+    m_count[1]++;
+
+  m_count[1] += (len >> 29);
+
+  if((j + len) > 63) {
+    memcpy(&m_buffer[j], in, (i = 64-j));
+    transform(m_state, m_buffer);
+    for ( ; i + 63 < (Q_UINT32)len; i += 64) {
+      transform(m_state, &in[i]);
+    }
+    j = 0;
+  }
+  else i = 0;
+    memcpy(&m_buffer[j], &in[i], len - i);
+
+}
+
+bool KSHA1::update(QIODevice& file)
+{
+    char buffer[1024];
+    int len;
+
+    while ((len=file.readBlock(reinterpret_cast<char*>(buffer), sizeof(buffer))) > \
0) +        update(buffer, len);
+
+    return file.atEnd();
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern 
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void KSHA1::finalize()
+{
+  Q_UINT32 i, j;
+  unsigned char finalcount[8];
+
+  for (i = 0; i < 8; i++) {
+    finalcount[i] = (unsigned char)((m_count[(i >= 4 ? 0 : 1)]
+    >> ((3-(i & 3)) * 8) ) & 255);  // Endian independent
+  }
+  update((unsigned char *)"\200", 1);
+  while ((m_count[0] & 504) != 448) {
+    update((unsigned char *)"\0", 1);
+  }
+  update(finalcount, 8);  // Should cause a transform()
+  for (i = 0; i < 20; i++) {
+    m_digest[i] = (unsigned char) ((m_state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+  }
+
+  // Wipe variables
+  i = j = 0;
+  memset(m_buffer, 0, 64);
+  memset(m_state, 0, 20);
+  memset(m_count, 0, 8);
+  memset(&finalcount, 0, 8);
+
+  m_finalized = true;
+}
+
+bool KSHA1::verify( const KSHA1::Digest& digest)
+{
+    finalize();
+    return (0 == memcmp(rawDigest(), digest, sizeof(KSHA1::Digest)));
+}
+
+bool KSHA1::verify( const QCString& hexdigest)
+{
+    finalize();
+    return (0 == strcmp(hexDigest().data(), hexdigest));
+}
+
+const KSHA1::Digest& KSHA1::rawDigest()
+{
+    finalize();
+    return m_digest;
+}
+
+void KSHA1::rawDigest( KSHA1::Digest& bin )
+{
+    finalize();
+    memcpy( bin, m_digest, sizeof(m_digest) );
+}
+
+QCString KSHA1::hexDigest()
+{
+    QCString s(41);
+
+    finalize();
+    sprintf(s.data(), \
"%02x%02x%02x%02x%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], m_digest[16],  +            \
m_digest[17], m_digest[18], m_digest[19]); +    return s;
+}
+
+void KSHA1::hexDigest(QCString& s)
+{
+    finalize();
+    s.resize(41);
+    sprintf(s.data(), \
"%02x%02x%02x%02x%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], m_digest[16],  +            \
m_digest[17], m_digest[18], m_digest[19]); +}
+
+QCString KSHA1::base64Digest()
+{
+    QByteArray ba(sizeof(m_digest));
+
+    finalize();
+    memcpy(ba.data(), m_digest, sizeof(m_digest));
+    return KCodecs::base64Encode(ba);
+}
+
+
+void KSHA1::init()
+{
+    d = 0;
+    reset();
+}
+
+/*
+ * Start SHA1 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void KSHA1::reset()
+{
+  m_finalized = false;
+
+	m_state[0] = 0x67452301;
+	m_state[1] = 0xEFCDAB89;
+	m_state[2] = 0x98BADCFE;
+	m_state[3] = 0x10325476;
+	m_state[4] = 0xC3D2E1F0;
+	m_count[0] = m_count[1] = 0;
+
+  memset ( m_buffer, 0, sizeof(*m_buffer));
+  memset ( m_digest, 0, sizeof(*m_digest));
+}
+
+inline Q_UINT32 KSHA1::rotate_left (Q_UINT32 x, Q_UINT32 n)
+{
+    return (x << n) | (x >> (32-n))  ;
+}
+
+#define blk(i) (block[i&15] = \
rotate_left(block[(i+13)&15]^block[(i+8)&15]^block[(i+2)&15]^block[i&15],1)) +
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) \
z+=((w&(x^y))^y)+block[i]+0x5A827999+rotate_left(v,5);w=rotate_left(w,30); +#define \
R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rotate_left(v,5);w=rotate_left(w,30);
 +#define R2(v,w,x,y,z,i) \
z+=(w^x^y)+blk(i)+0x6ED9EBA1+rotate_left(v,5);w=rotate_left(w,30); +#define \
R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rotate_left(v,5);w=rotate_left(w,30);
 +#define R4(v,w,x,y,z,i) \
z+=(w^x^y)+blk(i)+0xCA62C1D6+rotate_left(v,5);w=rotate_left(w,30); +
+/*
+ * The core of the MD4 algorithm
+ */
+void KSHA1::transform( Q_UINT32 state[5], const unsigned char buffer[64] )
+{
+	Q_UINT32 a, b, c, d, e;
+  Q_UINT32 block[16];
+
+  KFromToBigEndian( block, (Q_UINT32*) buffer, 16 );
+	// Copy context->state[] to working vars
+	a = state[0];
+	b = state[1];
+	c = state[2];
+	d = state[3];
+	e = state[4];
+	// 4 rounds of 20 operations each. Loop unrolled.
+	R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+	R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+	R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+	R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+	R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+	R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+	R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+	R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+	R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+	R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+	R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+	R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+	R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+	R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+	R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+	R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+	R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+	R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+	R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+	R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+
+	// Add the working vars back into context.state[]
+	state[0] += a;
+	state[1] += b;
+	state[2] += c;
+	state[3] += d;
+	state[4] += e;
+
+	// Wipe variables
+	a = b = c = d = e = 0;
+  memset( block, 0, sizeof(block) );
+}
+
+#undef R0
+#undef R1
+#undef R2
+#undef R3
+#undef R4
+#undef blk
Index: kdecore/kmdcodec.h
===================================================================
RCS file: /home/kde/kdelibs/kdecore/kmdcodec.h,v
retrieving revision 1.56
diff -u -p -u -r1.56 kmdcodec.h
--- kdecore/kmdcodec.h	5 Nov 2004 22:10:54 -0000	1.56
+++ kdecore/kmdcodec.h	6 Nov 2004 23:17:31 -0000
@@ -744,5 +742,166 @@ private:
   KMD4Private* d;
 };
 
+/**
+ * @short An adapted C++ implementation of the SHA1 Secure Hash algorithm.
+ * @since 3.4
+ *
+ * The class usage is the same as KMD5.
+ */
+class KDECORE_EXPORT KSHA1
+{
+public:
+
+  typedef unsigned char Digest[20];
+
+  KSHA1();
+
+  /**
+   * Constructor that updates the digest for the given string.
+   *
+   * @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).
+   */
+  KSHA1(const char* in, int len = -1);
+
+  /**
+   * @overload
+   *
+   * Same as above except it accepts a QByteArray as its argument.
+   */
+  KSHA1(const QByteArray& a );
+
+  /**
+   * @overload
+   *
+   * Same as above except it accepts a QByteArray as its argument.
+   */
+  KSHA1(const QCString& a );
+
+  /**
+   * 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 in     message to be added to digest
+   * @param len    the length of the given message.
+   */
+  void update(const char* in, int len = -1) { update(reinterpret_cast<const unsigned \
char*>(in), len); } +
+  /**
+   * @overload
+   */
+  void update(const unsigned char* in, int len = -1);
+
+  /**
+   * @overload
+   *
+   * @param in     message to be added to the digest (QByteArray).
+   */
+  void update(const QByteArray& in );
+
+  /**
+   * @overload
+   *
+   * @param in     message to be added to the digest (QByteArray).
+   */
+  void update(const QCString& in );
+
+  /**
+   * @overload
+   *
+   * reads the data from an I/O device, i.e. from a file (QFile).
+   *
+   * NOTE that the file must be open for reading.
+   *
+   * @param file       a pointer to FILE as returned by calls like f{d,re}open
+   *
+   * @returns false if an error occurred during reading.
+   */
+  bool update(QIODevice& file);
+
+  /**
+   * Calling this function will reset the calculated message digest.
+   * Use this method to perform another message digest calculation
+   * without recreating the KMD4 object.
+   */
+  void reset();
+
+  /**
+   * @return the raw representation of the digest
+   */
+  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( KSHA1::Digest& bin );
+
+  /**
+   * Returns the value of the calculated message digest in
+   * a hexadecimal representation.
+   */
+  QCString hexDigest ();
+
+  /**
+   * @overload
+   */
+  void hexDigest(QCString&);
+
+  /**
+   * Returns the value of the calculated message digest in
+   * a base64-encoded representation.
+   */
+  QCString base64Digest ();
+
+  /**
+   * returns true if the calculated digest for the given
+   * message matches the given one.
+   */
+  bool verify( const KSHA1::Digest& digest);
+
+  /**
+   * @overload
+   */
+  bool verify(const QCString&);
+
+protected:
+  /**
+   *  Performs the real update work.
+   */
+  void transform(Q_UINT32 state[5], const unsigned char buffer[64]);
+
+  /**
+   * finalizes the digest
+   */
+  void finalize();
+
+private:
+  KSHA1(const KSHA1& u);
+  KSHA1& operator=(const KSHA1& md);
+
+  void init();
+
+  Q_UINT32 rotate_left( Q_UINT32 x, Q_UINT32 n );
+
+private:
+  Q_UINT32 m_state[5];
+  Q_UINT32 m_count[2];
+  unsigned char m_buffer[64];
+  
+  Digest m_digest;
+  bool m_finalized;
+
+  class KSHA1Private;
+  KSHA1Private* d;
+};
 
 #endif
Index: kwallet/backend/Makefile.am
===================================================================
RCS file: /home/kde/kdelibs/kwallet/backend/Makefile.am,v
retrieving revision 1.18
diff -u -p -u -r1.18 Makefile.am
--- kwallet/backend/Makefile.am	5 Sep 2003 21:43:05 -0000	1.18
+++ kwallet/backend/Makefile.am	6 Nov 2004 23:17:32 -0000
@@ -8,7 +8,6 @@ libkwalletbackend_la_LIBADD = $(LIB_QT) 
 libkwalletbackend_la_SOURCES = blockcipher.cc		\
 			       blowfish.cc		\
 			       cbc.cc			\
-			       sha1.cc			\
 			       kwalletentry.cc		\
 			       kwalletbackend.cc
 
@@ -17,7 +16,6 @@ libkwalletbackend_la_METASOURCES = AUTO
 
 noinst_HEADERS = blowfishtables.h	\
 		 cbc.h			\
-		 sha1.h			\
 		 blockcipher.h		\
 		 kwalletentry.h		\
 		 kwalletbackend.h	\
Index: kwallet/backend/kwalletbackend.cc
===================================================================
RCS file: /home/kde/kdelibs/kwallet/backend/kwalletbackend.cc,v
retrieving revision 1.55
diff -u -p -u -r1.55 kwalletbackend.cc
--- kwallet/backend/kwalletbackend.cc	6 Nov 2004 11:47:46 -0000	1.55
+++ kwallet/backend/kwalletbackend.cc	6 Nov 2004 23:17:32 -0000
@@ -34,7 +34,6 @@
 #include <qregexp.h>
 
 #include "blowfish.h"
-#include "sha1.h"
 #include "cbc.h"
 
 #include <assert.h>
@@ -149,58 +148,58 @@ static int getRandomBlock(QByteArray& ra
 
 // this should be SHA-512 for release probably
 static int password2hash(const QByteArray& password, QByteArray& hash) {
-	SHA1 sha;
-	int shasz = sha.size() / 8;
+	KSHA1 sha;
+	int shasz = sizeof(KSHA1::Digest);
 
 	assert(shasz >= 20);
 
 	QByteArray block1(shasz);
 
-	sha.process(password.data(), QMIN(password.size(), 16));
+	sha.update(password.data(), QMIN(password.size(), 16));
 
 	// To make brute force take longer
 	for (int i = 0; i < 2000; i++) {
-		memcpy(block1.data(), sha.hash(), shasz);
+		memcpy(block1.data(), sha.rawDigest(), shasz);
 		sha.reset();
-		sha.process(block1.data(), shasz);
+		sha.update(block1);
 	}
 
 	sha.reset();
 
 	if (password.size() > 16) {
-		sha.process(password.data() + 16, QMIN(password.size() - 16, 16));
+		sha.update(password.data() + 16, QMIN(password.size() - 16, 16));
 		QByteArray block2(shasz);
 		// To make brute force take longer
 		for (int i = 0; i < 2000; i++) {
-			memcpy(block2.data(), sha.hash(), shasz);
+			memcpy(block2.data(), sha.rawDigest(), shasz);
 			sha.reset();
-			sha.process(block2.data(), shasz);
+			sha.update(block2);
 		}
 
 		sha.reset();
 
 		if (password.size() > 32) {
-			sha.process(password.data() + 32, QMIN(password.size() - 32, 16));
+			sha.update(password.data() + 32, QMIN(password.size() - 32, 16));
 
 			QByteArray block3(shasz);
 			// To make brute force take longer
 			for (int i = 0; i < 2000; i++) {
-				memcpy(block3.data(), sha.hash(), shasz);
+				memcpy(block3.data(), sha.rawDigest(), shasz);
 				sha.reset();
-				sha.process(block3.data(), shasz);
+				sha.update(block3);
 			}
 
 			sha.reset();
 
 			if (password.size() > 48) {
-				sha.process(password.data() + 48, password.size() - 48);
+				sha.update(password.data() + 48, password.size() - 48);
 
 				QByteArray block4(shasz);
 				// To make brute force take longer
 				for (int i = 0; i < 2000; i++) {
-					memcpy(block4.data(), sha.hash(), shasz);
+					memcpy(block4.data(), sha.rawDigest(), shasz);
 					sha.reset();
-					sha.process(block4.data(), shasz);
+					sha.update(block4);
 				}
 
 				sha.reset();
@@ -408,9 +407,8 @@ int Backend::open(const QByteArray& pass
 	}
 
 	// compute the hash ourself
-	SHA1 sha;
-	sha.process(t, fsize);
-	const char *testhash = (const char *)sha.hash();
+	KSHA1 sha(t, fsize);
+	const char *testhash = (const char *)sha.rawDigest();
 
 	// compare hashes
 	int sz = encrypted.size();
@@ -538,12 +536,10 @@ int Backend::sync(const QByteArray& pass
 	qf->writeBlock(hashes, hashes.size());
 
 	// calculate the hash of the file
-	SHA1 sha;
+	KSHA1 sha(decrypted);
 	BlowFish _bf;
 	CipherBlockChain bf(&_bf);
 
-	sha.process(decrypted.data(), decrypted.size());
-
 	// prepend and append the random data
 	QByteArray wholeFile;
 	long blksz = bf.blockSize();
@@ -581,7 +577,7 @@ int Backend::sync(const QByteArray& pass
 		wholeFile[(int)(i+blksz+4+decrypted.size())] = randBlock[(int)(i+blksz)];
 	}
 
-	const char *hash = (const char *)sha.hash();
+	const char *hash = (const char *)sha.rawDigest();
 	for (int i = 0; i < 20; i++) {
 		wholeFile[(int)(newsize - 20 + i)] = hash[i];
 	}



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

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