summaryrefslogtreecommitdiffstats
path: root/kopete/protocols/msn/msnchallengehandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kopete/protocols/msn/msnchallengehandler.cpp')
-rw-r--r--kopete/protocols/msn/msnchallengehandler.cpp151
1 files changed, 151 insertions, 0 deletions
diff --git a/kopete/protocols/msn/msnchallengehandler.cpp b/kopete/protocols/msn/msnchallengehandler.cpp
new file mode 100644
index 00000000..e0bcc987
--- /dev/null
+++ b/kopete/protocols/msn/msnchallengehandler.cpp
@@ -0,0 +1,151 @@
+/*
+ msnchallengehandler.h - Computes a msn challenge response hash key.
+
+ Copyright (c) 2005 by Gregg Edghill <gregg.edghill@gmail.com>
+ Kopete (c) 2003-2005 by The Kopete developers <kopete-devel@kde.org>
+
+ Portions taken from
+ http://msnpiki.msnfanatic.com/index.php/MSNP11:Challenges
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include "msnchallengehandler.h"
+
+#include <qdatastream.h>
+
+#include <kdebug.h>
+#include <kmdcodec.h>
+
+MSNChallengeHandler::MSNChallengeHandler(const QString& productKey, const QString& productId)
+{
+ m_productKey = productKey;
+ m_productId = productId;
+}
+
+
+MSNChallengeHandler::~MSNChallengeHandler()
+{
+ kdDebug(14140) << k_funcinfo << endl;
+}
+
+QString MSNChallengeHandler::computeHash(const QString& challengeString)
+{
+ // Step One: THe MD5 Hash.
+
+ // Combine the received challenge string with the product key.
+ KMD5 md5((challengeString + m_productKey).utf8());
+ QCString digest = md5.hexDigest();
+
+ kdDebug(14140) << k_funcinfo << "md5: " << digest << endl;
+
+ QValueVector<Q_INT32> md5Integers(4);
+ for(Q_UINT32 i=0; i < md5Integers.count(); i++)
+ {
+ md5Integers[i] = hexSwap(digest.mid(i*8, 8)).toUInt(0, 16) & 0x7FFFFFFF;
+ kdDebug(14140) << k_funcinfo << ("0x" + hexSwap(digest.mid(i*8, 8))) << " " << md5Integers[i] << endl;
+ }
+
+ // Step Two: Create the challenge string key
+
+ QString challengeKey = challengeString + m_productId;
+ // Pad to multiple of 8.
+ challengeKey = challengeKey.leftJustify(challengeKey.length() + (8 - challengeKey.length() % 8), '0');
+
+ kdDebug(14140) << k_funcinfo << "challenge key: " << challengeKey << endl;
+
+ QValueVector<Q_INT32> challengeIntegers(challengeKey.length() / 4);
+ for(Q_UINT32 i=0; i < challengeIntegers.count(); i++)
+ {
+ QString sNum = challengeKey.mid(i*4, 4), sNumHex;
+
+ // Go through the number string, determining the hex equivalent of each value
+ // and add that to our new hex string for this number.
+ for(uint j=0; j < sNum.length(); j++) {
+ sNumHex += QString::number((int)sNum[j].latin1(), 16);
+ }
+
+ // swap because of the byte ordering issue.
+ sNumHex = hexSwap(sNumHex);
+ // Assign the converted number.
+ challengeIntegers[i] = sNumHex.toInt(0, 16);
+ kdDebug(14140) << k_funcinfo << sNum << (": 0x"+sNumHex) << " " << challengeIntegers[i] << endl;
+ }
+
+ // Step Three: Create the 64-bit hash key.
+
+ // Get the hash key using the specified arrays.
+ Q_INT64 key = createHashKey(md5Integers, challengeIntegers);
+ kdDebug(14140) << k_funcinfo << "key: " << key << endl;
+
+ // Step Four: Create the final hash key.
+
+ QString upper = QString::number(QString(digest.mid(0, 16)).toULongLong(0, 16)^key, 16);
+ if(upper.length() % 16 != 0)
+ upper = upper.rightJustify(upper.length() + (16 - upper.length() % 16), '0');
+
+ QString lower = QString::number(QString(digest.mid(16, 16)).toULongLong(0, 16)^key, 16);
+ if(lower.length() % 16 != 0)
+ lower = lower.rightJustify(lower.length() + (16 - lower.length() % 16), '0');
+
+ return (upper + lower);
+}
+
+Q_INT64 MSNChallengeHandler::createHashKey(const QValueVector<Q_INT32>& md5Integers,
+ const QValueVector<Q_INT32>& challengeIntegers)
+{
+ kdDebug(14140) << k_funcinfo << "Creating 64-bit key." << endl;
+
+ Q_INT64 magicNumber = 0x0E79A9C1L, high = 0L, low = 0L;
+
+ for(uint i=0; i < challengeIntegers.count(); i += 2)
+ {
+ Q_INT64 temp = ((challengeIntegers[i] * magicNumber) % 0x7FFFFFFF) + high;
+ temp = ((temp * md5Integers[0]) + md5Integers[1]) % 0x7FFFFFFF;
+
+ high = (challengeIntegers[i + 1] + temp) % 0x7FFFFFFF;
+ high = ((high * md5Integers[2]) + md5Integers[3]) % 0x7FFFFFFF;
+
+ low += high + temp;
+ }
+
+ high = (high + md5Integers[1]) % 0x7FFFFFFF;
+ low = (low + md5Integers[3]) % 0x7FFFFFFF;
+
+ QDataStream buffer(QByteArray(8), IO_ReadWrite);
+ buffer.setByteOrder(QDataStream::LittleEndian);
+ buffer << (Q_INT32)high;
+ buffer << (Q_INT32)low;
+
+ buffer.device()->reset();
+ buffer.setByteOrder(QDataStream::BigEndian);
+ Q_INT64 key;
+ buffer >> key;
+
+ return key;
+}
+
+QString MSNChallengeHandler::hexSwap(const QString& in)
+{
+ QString sHex = in, swapped;
+ while(sHex.length() > 0)
+ {
+ swapped = swapped + sHex.mid(sHex.length() - 2, 2);
+ sHex = sHex.remove(sHex.length() - 2, 2);
+ }
+ return swapped;
+}
+
+QString MSNChallengeHandler::productId()
+{
+ return m_productId;
+}
+
+#include "msnchallengehandler.moc"