1//
2// This file is part of the aMule Project.
3//
4// Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5// Copyright (c) 2002-2011 Merkur ( devs@emule-project.net / http://www.emule-project.net )
6//
7// Any parts of this program derived from the xMule, lMule or eMule project,
8// or contributed by third-party developers are copyrighted by their
9// respective authors.
10//
11// This program is free software; you can redistribute it and/or modify
12// it under the terms of the GNU General Public License as published by
13// the Free Software Foundation; either version 2 of the License, or
14// (at your option) any later version.
15//
16// This program is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19// GNU General Public License for more details.
20//
21// You should have received a copy of the GNU General Public License
22// along with this program; if not, write to the Free Software
23// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
24//
25
26
27#include "RC4Encrypt.h"
28#include <common/MD5Sum.h>
29
30
31#include <stdexcept>
32
33CRC4EncryptableBuffer::CRC4EncryptableBuffer() : m_encrypted(false), m_hasKey(false), m_key()
34{
35}
36
37
38CRC4EncryptableBuffer::~CRC4EncryptableBuffer()
39{
40}
41
42void CRC4EncryptableBuffer::Append(const uint8* buffer, int n)
43{
44	wxASSERT(!m_encrypted);
45	if (!m_encrypted) {
46		CMemFile::Append(buffer, n);
47	} else {
48		throw std::runtime_error(
49			"(CRC4EncryptableBuffer::Append): "
50			"Tryed to append data to an encrypted buffer.");
51	}
52}
53
54
55void CRC4EncryptableBuffer::Encrypt()
56{
57	wxASSERT(!m_encrypted);
58	RC4Crypt(GetRawBuffer(), GetRawBuffer(), GetLength());
59	m_encrypted = true;
60}
61
62void CRC4EncryptableBuffer::RC4Crypt( const uint8 *pachIn, uint8 *pachOut, uint32 nLen)
63{
64	wxASSERT( m_hasKey && nLen > 0 );
65
66	if (m_hasKey) {
67		uint8 byX = m_key.byX;;
68		uint8 byY = m_key.byY;
69		uint8* pabyState = &m_key.abyState[0];;
70		uint8 byXorIndex;
71
72		for (uint32 i = 0; i < nLen; ++i) {
73			byX = (byX + 1) % 256;
74			byY = (pabyState[byX] + byY) % 256;
75			std::swap(pabyState[byX], pabyState[byY]);
76			byXorIndex = (pabyState[byX] + pabyState[byY]) % 256;
77
78			if (pachIn != NULL) {
79				pachOut[i] = pachIn[i] ^ pabyState[byXorIndex];
80			}
81		}
82
83		m_key.byX = byX;
84		m_key.byY = byY;
85	} else {
86		throw std::runtime_error(
87			"(CRC4EncryptableBuffer::RC4Crypt): "
88			"Encrypt() has been called without a previous call"
89			"to SetKey().");
90	}
91}
92
93uint8 *CRC4EncryptableBuffer::Detach()
94{
95	int n = GetLength();
96	uint8 *ret = new uint8[n];
97	memcpy(ret, GetRawBuffer(), n);
98	ResetData();
99	m_encrypted = false;
100	return ret;
101}
102
103
104void CRC4EncryptableBuffer::SetKey(const MD5Sum& keyhash, bool bSkipDiscard)
105{
106	wxASSERT(!m_hasKey);
107	if (!m_hasKey) {
108		m_hasKey = true;
109		RC4CreateKey( keyhash.GetRawHash(), 16, bSkipDiscard);
110	} else {
111		throw std::runtime_error( "(CRC4EncryptableBuffer::SetKey): SetKey() has been called twice.");
112	}
113}
114
115
116void CRC4EncryptableBuffer::RC4CreateKey(const uint8* pachKeyData, uint32 nLen, bool bSkipDiscard)
117{
118	uint8 index1;
119	uint8 index2;
120	uint8* pabyState;
121
122	pabyState= &m_key.abyState[0];
123	for (int i = 0; i < 256; ++i) {
124		pabyState[i] = (uint8)i;
125	}
126
127	m_key.byX = 0;
128	m_key.byY = 0;
129	index1 = 0;
130	index2 = 0;
131
132	for (int i = 0; i < 256; ++i) {
133		index2 = (pachKeyData[index1] + pabyState[i] + index2) % 256;
134		std::swap(pabyState[i], pabyState[index2]);
135		index1 = (uint8)((index1 + 1) % nLen);
136	}
137
138	if (!bSkipDiscard) {
139		RC4Crypt(NULL, NULL, 1024);
140	}
141}
142
143void CRC4EncryptableBuffer::ResetData()
144{
145	m_encrypted = false;
146	// Not touching the keys.
147	CMemFile::ResetData();
148}
149
150void CRC4EncryptableBuffer::FullReset()
151{
152	ResetData();
153	m_hasKey = false;
154	memset(&m_key, 0, sizeof(RC4_Key_Struct));
155}
156