summaryrefslogtreecommitdiffstats
path: root/kopete/protocols/msn/msnchallengehandler.cpp
blob: 46d4b8a043435c38e5cff8d8d1ae7171fd826347 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/*
    msnchallengehandler.h - Computes a msn challenge response hash key.

    Copyright (c) 2005 by Gregg Edghill       <[email protected]>
    Kopete    (c) 2003-2005 by The Kopete developers <[email protected]>

    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 <tqdatastream.h>

#include <kdebug.h>
#include <kmdcodec.h>

MSNChallengeHandler::MSNChallengeHandler(const TQString& productKey, const TQString& productId)
{
	m_productKey = productKey;
	m_productId  = productId;
}


MSNChallengeHandler::~MSNChallengeHandler()
{
	kdDebug(14140) << k_funcinfo << endl;
}

TQString MSNChallengeHandler::computeHash(const TQString& challengeString)
{
  	// Step One: THe MD5 Hash.

  	// Combine the received challenge string with the product key.
 	KMD5 md5((challengeString + m_productKey).utf8());
 	TQCString digest = md5.hexDigest();

 	kdDebug(14140) << k_funcinfo << "md5: " << digest << endl;

 	TQValueVector<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

	TQString 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;

	TQValueVector<Q_INT32> challengeIntegers(challengeKey.length() / 4);
	for(Q_UINT32 i=0; i < challengeIntegers.count(); i++)
	{
		TQString 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 += TQString::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.

	TQString upper = TQString::number(TQString(digest.mid(0, 16)).toULongLong(0, 16)^key, 16);
	if(upper.length() % 16 != 0)
		upper = upper.rightJustify(upper.length() + (16 - upper.length() % 16), '0');

	TQString lower = TQString::number(TQString(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 TQValueVector<Q_INT32>& md5Integers,
	const TQValueVector<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;

	TQDataStream buffer(TQByteArray(8), IO_ReadWrite);
	buffer.setByteOrder(TQDataStream::LittleEndian);
	buffer << (Q_INT32)high;
	buffer << (Q_INT32)low;

	buffer.device()->reset();
	buffer.setByteOrder(TQDataStream::BigEndian);
	Q_INT64 key;
	buffer >> key;
	
	return key;
}

TQString MSNChallengeHandler::hexSwap(const TQString& in)
{
	TQString sHex = in, swapped;
	while(sHex.length() > 0)
	{
		swapped = swapped + sHex.mid(sHex.length() - 2, 2);
		sHex = sHex.remove(sHex.length() - 2, 2);
	}
	return swapped;
}

TQString MSNChallengeHandler::productId()
{
	return m_productId;
}

#include "msnchallengehandler.moc"