Developer Documentation

keygenWidget.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4 * Copyright (c) 2001-2015, RWTH-Aachen University *
5 * Department of Computer Graphics and Multimedia *
6 * All rights reserved. *
7 * www.openflipper.org *
8 * *
9 *---------------------------------------------------------------------------*
10 * This file is part of OpenFlipper. *
11 *---------------------------------------------------------------------------*
12 * *
13 * Redistribution and use in source and binary forms, with or without *
14 * modification, are permitted provided that the following conditions *
15 * are met: *
16 * *
17 * 1. Redistributions of source code must retain the above copyright notice, *
18 * this list of conditions and the following disclaimer. *
19 * *
20 * 2. Redistributions in binary form must reproduce the above copyright *
21 * notice, this list of conditions and the following disclaimer in the *
22 * documentation and/or other materials provided with the distribution. *
23 * *
24 * 3. Neither the name of the copyright holder nor the names of its *
25 * contributors may be used to endorse or promote products derived from *
26 * this software without specific prior written permission. *
27 * *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41
42
43
44
45 #include <QtWidgets>
46
47 #include <QMessageBox>
48
49 #include "keygenWidget.hh"
50 #include <iostream>
51
52 #include "salt.hh"
53
54 KeyGen::KeyGen(QString n, QString cHash, QString pHash, QString cpHash, QString prHash, QStringList mHashes, QString request) :
55 name (n),
56 coreHash(cHash),
57 pluginHash(pHash),
58 cpuHash(cpHash),
59 productHash(prHash),
60 macHashes(mHashes),
61 requestSig(request)
62 {
63 }
64
65 QString KeyGen::computeSignature(const bool _utf8 ) const {
66 // Get the salts
67 QString saltPre;
68 ADD_SALT_PRE(saltPre);
69 QString saltPost;
70 ADD_SALT_POST(saltPost);
71
72 QString keyRequest = saltPre + name + coreHash + pluginHash + cpuHash
73 + productHash + macHashes.join("") + saltPost;
74
75 QString requestSigCheck;
76
77 if ( _utf8 )
78 requestSigCheck =
79 QCryptographicHash::hash(keyRequest.toUtf8(),
80 QCryptographicHash::Sha1).toHex();
81 else
82 requestSigCheck =
83 QCryptographicHash::hash(keyRequest.toLatin1(),
84 QCryptographicHash::Sha1).toHex();
85
86 return requestSigCheck;
87 }
88
89 KeyGen::ValidationResult KeyGen::isValid() const
90 {
91 if (requestSig == computeSignature(true))
92 {
93 return UTF8;
94 }
95 else if(requestSig == computeSignature(false))
96 {
97 return LATIN1;
98 }
99 return INVALID;
100 }
101
102 QString KeyGen::Generate(QString expiryDate) const
103 {
104 // Get the salts
105 QString saltPre;
106 ADD_SALT_PRE(saltPre);
107 QString saltPost;
108 ADD_SALT_POST(saltPost);
109
110 KeyGen::ValidationResult valid = isValid();
111
112 if ( !valid ){
113 return "ERROR";
114 }
115 else{
116 QString license_ = "";
117
118 // Add basic hashes
119 license_ += expiryDate + "\n";
120 license_ += name + "\n";
121 license_ += coreHash + "\n";
122 license_ += pluginHash + "\n";
123 license_ += cpuHash + "\n";
124 license_ += productHash + "\n";
125 license_ += macHashes.join("\n") + "\n";
126
127 QString licenseTmp = saltPre + expiryDate + name + coreHash + pluginHash + cpuHash + productHash + macHashes.join("") + saltPost;
128 QString licenseHash;
129 if (valid == UTF8)
130 licenseHash = QCryptographicHash::hash ( licenseTmp.toUtf8() , QCryptographicHash::Sha1 ).toHex();
131 else
132 licenseHash = QCryptographicHash::hash ( licenseTmp.toLatin1() , QCryptographicHash::Sha1 ).toHex();
133 // Prepend signature
134 license_ = licenseHash + "\n" + license_;
135 return license_;
136 }
137 }
138
139 QString KeyGen::filterString(QString in) {
140 const QRegExp validChar("[a-f0-9]");
141 QString out; out.reserve(in.size());
142 for (QString::iterator it = in.begin(), it_end = in.end(); it != it_end; ++it) {
143 if (validChar.exactMatch(*it))
144 out.append(*it);
145 }
146 return out;
147 }
148
149 std::vector<KeyGen> KeyGen::CreateFromMessyString(QString info)
150 {
151 const QString dirt = "[\\s;>]*";
152 const QRegExp rx("\\b([\\w-]+)" + dirt + "((?:(?:[a-f0-9]" + dirt + "){40}){6,})\\b");
153 const QRegExp partRe("((?:[a-f0-9]" + dirt + "){40})");
154
155 std::vector<KeyGen> R;
156 int pos = 0;
157 while ((pos = rx.indexIn(info, pos)) != -1) {
158 QString hashesStr = rx.cap(2);
159 QStringList hashes;
160 int hashPos = 0;
161 while ((hashPos = partRe.indexIn(hashesStr, hashPos)) != -1) {
162 hashes.append(filterString(partRe.cap(1)));
163 hashPos += partRe.matchedLength();
164 }
165
166 QStringList macList;
167 std::copy(hashes.begin() + 4, hashes.end() - 1, std::back_inserter(macList));
168
169 KeyGen K(rx.cap(1),
170 hashes[0],
171 hashes[1],
172 hashes[2],
173 hashes[3],
174 macList,
175 hashes[hashes.count()-1]);
176 R.push_back(K);
177 pos += rx.matchedLength();
178 }
179
180 return R;
181 }
182
183 KeyGenWidget::KeyGenWidget(QMainWindow *parent)
184 : QMainWindow(parent)
185 {
186 setupUi(this);
187 connect(generateAllButton,SIGNAL(clicked()),this,SLOT(slotGenerateAllButton()));
188 connect(generateLocalButton,SIGNAL(clicked()),this,SLOT(slotGenerateButton()));
189 connect(keyList->selectionModel(),SIGNAL(selectionChanged(QItemSelection,QItemSelection)),this, SLOT(handleSelectionChanged(QItemSelection)));
190
191 connect(splitButton,SIGNAL(clicked()),this,SLOT(slotSplit()));
192
193 connect(requestData,SIGNAL(textChanged()),this,SLOT(slotAnalyze()));
194
195 // connect spinboxes forexpiry date
196 connect(days ,SIGNAL(valueChanged(int)),this,SLOT(slotDate()));
197 connect(months,SIGNAL(valueChanged(int)),this,SLOT(slotDate()));
198 connect(years ,SIGNAL(valueChanged(int)),this,SLOT(slotDate()));
199
200 /*
201 * Mangle Tab
202 */
203 connect(mangle_pb, SIGNAL(clicked()), this, SLOT(slotMangle()));
204
205 // Automatically set expire date to current date
206 // For security reasons no default span is set here!
207 expires->setDate( QDate::currentDate());
208
209 generateLocalButton->setVisible(false);
210 generateAllButton->setVisible(false);
211 }
212
213 void KeyGenWidget::slotMangle() {
214 const QString hardwareHash_raw = hardwareHashDump_te->toPlainText();
215 const QString pluginHashes_raw = pluginHashDump_te->toPlainText();
216
217 const std::vector<KeyGen> hardwareKeygens = KeyGen::CreateFromMessyString(hardwareHash_raw);
218 if (hardwareKeygens.empty()) {
219 QMessageBox::critical(this, tr("Unable to Mangle"), tr("No valid request found in hardware textbox."));
220 return;
221 }
222 KeyGen hardwareKeygen = hardwareKeygens.front();
223
224 std::vector<KeyGen> pluginKeygens = KeyGen::CreateFromMessyString(pluginHashes_raw);
225 if (pluginKeygens.empty()) {
226 QMessageBox::critical(this, tr("Unable to Mangle"), tr("No valid request found in plugins textbox."));
227 return;
228 }
229
230 QString generatedRequest;
231 for (std::vector<KeyGen>::iterator it = pluginKeygens.begin(), it_end = pluginKeygens.end();
232 it != it_end; ++it) {
233
234 it->copyHardwareHashesFrom(hardwareKeygen);
235
236 generatedRequest += it->generateRequest();
237 }
238
239 requestData->setPlainText(generatedRequest);
240 }
241
242 void KeyGenWidget::slotDate() {
243 QDate today = QDate::currentDate();
244 today = today.addDays(days->value());
245 today = today.addMonths(months->value());
246 today = today.addYears(years->value());
247
248 expires->setDate(today);
249 }
250
251 void KeyGenWidget::slotAnalyze() {
252 QString inputData = requestData->toPlainText();
253 keygens_ = KeyGen::CreateFromMessyString(inputData);
254
255 keyList->clear();
256 for (std::vector<KeyGen>::const_iterator it = keygens_.begin(), it_end = keygens_.end();
257 it != it_end; ++it) {
258 QListWidgetItem *newItem = new QListWidgetItem( keyList);
259 newItem->setText(it->name);
260 newItem->setHidden(false);
261 KeyGen::ValidationResult r = it->isValid();
262 if (!r)
263 newItem->setTextColor(QColor(255, 0, 0));
264 else if (r == KeyGen::LATIN1)
265 newItem->setTextColor(QColor(128, 128, 0));
266 }
267
268 generateLocalButton->setVisible(false);
269 generateAllButton->setVisible(keygens_.size());
270 }
271
272 void KeyGenWidget::slotSplit() {
273 // Get request data
274 QString inputData = requestData->toPlainText();
275
276 // Split with ;
277 QStringList data = inputData.split(";",QString::SkipEmptyParts);
278
279 QString newText = data.join("\n");
280
281 requestData->setText(newText);
282
283 }
284
285 void KeyGenWidget::handleSelectionChanged(const QItemSelection& selection){
286 generateLocalButton->setVisible(false);
287 if(keyList->selectionModel()->selectedIndexes().count())
288 {
289 int i = keyList->selectionModel()->selectedIndexes()[0].row();
290 setKeyGen(&keygens_[i]);
291 generateLocalButton->setVisible(true);
292 generateAllButton->setVisible(true);
293
294 KeyGen::ValidationResult valid = keygens_[i].isValid();
295 if (valid == KeyGen::INVALID)
296 lbWarning->setText("ERROR: Signature does not match.\nCannot generate key");
297 else if (valid == KeyGen::LATIN1)
298 lbWarning->setText("WARNING: Request uses old Ascii format.\nKey will be generated with Ascii encoding.");
299 else
300 lbWarning->setText("");
301 }
302 }
303
304 KeyGenWidget::~KeyGenWidget() {
305
306 }
307
308 void KeyGenWidget::toFile(const KeyGen* gen)
309 {
310 QString licenseFileName_ = gen->name;
311 std::cerr << "Writing License file to output : " << licenseFileName_.toStdString() << std::endl;
312 QFile outFile(licenseFileName_ + ".lic");
313
314 if (!outFile.open(QIODevice::WriteOnly|QIODevice::Text)) {
315 QMessageBox::critical(this,tr("Unable to open file"),tr("Unable to Open output File"));
316 return;
317 }
318
319 QTextStream output(&outFile);
320 output << gen->Generate(expires->date().toString(Qt::ISODate));
321 outFile.close();
322 }
323
324 void KeyGenWidget::setKeyGen(const KeyGen* gen) {
325 fileNameBox->setText(gen->name);
326 coreHashBox->setText(gen->coreHash);
327 pluginHashBox->setText(gen->pluginHash);
328 cpuHashBox->setText(gen->cpuHash);
329 productIDBox->setText(gen->productHash);
330 macHashBox->setText(gen->macHashes.join("\n"));
331 signatureBox->setText(gen->requestSig);
332 generateLocalButton->setEnabled(gen->isValid());
333 }
334
335 void KeyGenWidget::slotGenerateButton() {
336 if(keyList->selectionModel()->selectedIndexes().count())
337 {
338 int i = keyList->selectionModel()->selectedIndexes()[0].row();
339 toFile(&keygens_[i]);
340 }
341 }
342
343 void KeyGenWidget::slotGenerateAllButton() {
344 for(unsigned int i = 0; i < keygens_.size(); i++)
345 toFile(&keygens_[i]);
346 }
KeyGen
Definition: keygenWidget.hh:46