Developer Documentation
Loading...
Searching...
No Matches
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#include <QRegularExpression>
49
50#include "keygenWidget.hh"
51#include <iostream>
52
53#include "salt.hh"
54
55KeyGen::KeyGen(QString n, QString cHash, QString pHash, QString cpHash, QString prHash, QStringList mHashes, QString request) :
56 name (n),
57 coreHash(cHash),
58 pluginHash(pHash),
59 cpuHash(cpHash),
60 productHash(prHash),
61 macHashes(mHashes),
62 requestSig(request)
63{
64}
65
66QString KeyGen::computeSignature(const bool _utf8 ) const {
67 // Get the salts
68 QString saltPre;
69 ADD_SALT_PRE(saltPre);
70 QString saltPost;
71 ADD_SALT_POST(saltPost);
72
73 QString keyRequest = saltPre + name + coreHash + pluginHash + cpuHash
74 + productHash + macHashes.join("") + saltPost;
75
76 QString requestSigCheck;
77
78 if ( _utf8 )
79 requestSigCheck =
80 QCryptographicHash::hash(keyRequest.toUtf8(),
81 QCryptographicHash::Sha1).toHex();
82 else
83 requestSigCheck =
84 QCryptographicHash::hash(keyRequest.toLatin1(),
85 QCryptographicHash::Sha1).toHex();
86
87 return requestSigCheck;
88}
89
90KeyGen::ValidationResult KeyGen::isValid() const
91{
92 if (requestSig == computeSignature(true))
93 {
94 return UTF8;
95 }
96 else if(requestSig == computeSignature(false))
97 {
98 return LATIN1;
99 }
100 return INVALID;
101}
102
103QString KeyGen::Generate(QString expiryDate) const
104{
105 // Get the salts
106 QString saltPre;
107 ADD_SALT_PRE(saltPre);
108 QString saltPost;
109 ADD_SALT_POST(saltPost);
110
111 KeyGen::ValidationResult valid = isValid();
112
113 if ( !valid ){
114 return "ERROR";
115 }
116 else{
117 QString license_ = "";
118
119 // Add basic hashes
120 license_ += expiryDate + "\n";
121 license_ += name + "\n";
122 license_ += coreHash + "\n";
123 license_ += pluginHash + "\n";
124 license_ += cpuHash + "\n";
125 license_ += productHash + "\n";
126 license_ += macHashes.join("\n") + "\n";
127
128 QString licenseTmp = saltPre + expiryDate + name + coreHash + pluginHash + cpuHash + productHash + macHashes.join("") + saltPost;
129 QString licenseHash;
130 if (valid == UTF8)
131 licenseHash = QCryptographicHash::hash ( licenseTmp.toUtf8() , QCryptographicHash::Sha1 ).toHex();
132 else
133 licenseHash = QCryptographicHash::hash ( licenseTmp.toLatin1() , QCryptographicHash::Sha1 ).toHex();
134 // Prepend signature
135 license_ = licenseHash + "\n" + license_;
136 return license_;
137 }
138}
139
140QString KeyGen::filterString(QString in) {
141 const QRegularExpression validChar("[a-f0-9]");
142 QString out;
143 out.reserve(in.size());
144 for (QString::iterator it = in.begin(), it_end = in.end(); it != it_end; ++it) {
145 if (validChar.match(*it).hasMatch())
146 out.append(*it);
147 }
148 return out;
149}
150
151std::vector<KeyGen> KeyGen::CreateFromMessyString(QString info)
152{
153 const QString dirt = "[\\s;>]*";
154 const QRegularExpression rx("\\b([\\w-]+)" + dirt + "((?:(?:[a-f0-9]" + dirt + "){40}){6,})\\b");
155 const QRegularExpression partRe("((?:[a-f0-9]" + dirt + "){40})");
156
157 std::vector<KeyGen> R;
158 QRegularExpressionMatch rxMatch;
159 int pos = 0;
160 while ((pos = info.indexOf(rx, pos, &rxMatch)) != -1) {
161 QString hashesStr = rxMatch.captured(2);
162 QStringList hashes;
163 QRegularExpressionMatch partReMatch;
164 int hashPos = 0;
165 while ((hashPos = hashesStr.indexOf(partRe, hashPos, &partReMatch)) != -1) {
166 hashes.append(filterString(partReMatch.captured(1)));
167 hashPos += partReMatch.capturedLength(1);
168 }
169
170 QStringList macList;
171 std::copy(hashes.begin() + 4, hashes.end() - 1, std::back_inserter(macList));
172
173 KeyGen K(rxMatch.captured(1),
174 hashes[0],
175 hashes[1],
176 hashes[2],
177 hashes[3],
178 macList,
179 hashes[hashes.count() - 1]);
180 R.push_back(K);
181 pos += rxMatch.capturedLength(0);
182 }
183
184 return R;
185}
186
187KeyGenWidget::KeyGenWidget(QMainWindow *parent)
188 : QMainWindow(parent)
189{
190 setupUi(this);
191 connect(generateAllButton,SIGNAL(clicked()),this,SLOT(slotGenerateAllButton()));
192 connect(generateLocalButton,SIGNAL(clicked()),this,SLOT(slotGenerateButton()));
193 connect(keyList->selectionModel(),SIGNAL(selectionChanged(QItemSelection,QItemSelection)),this, SLOT(handleSelectionChanged(QItemSelection)));
194
195 connect(splitButton,SIGNAL(clicked()),this,SLOT(slotSplit()));
196
197 connect(requestData,SIGNAL(textChanged()),this,SLOT(slotAnalyze()));
198
199 // connect spinboxes forexpiry date
200 connect(days ,SIGNAL(valueChanged(int)),this,SLOT(slotDate()));
201 connect(months,SIGNAL(valueChanged(int)),this,SLOT(slotDate()));
202 connect(years ,SIGNAL(valueChanged(int)),this,SLOT(slotDate()));
203
204 /*
205 * Mangle Tab
206 */
207 connect(mangle_pb, SIGNAL(clicked()), this, SLOT(slotMangle()));
208
209 // Automatically set expire date to current date
210 // For security reasons no default span is set here!
211 expires->setDate( QDate::currentDate());
212
213 generateLocalButton->setVisible(false);
214 generateAllButton->setVisible(false);
215}
216
217void KeyGenWidget::slotMangle() {
218 const QString hardwareHash_raw = hardwareHashDump_te->toPlainText();
219 const QString pluginHashes_raw = pluginHashDump_te->toPlainText();
220
221 const std::vector<KeyGen> hardwareKeygens = KeyGen::CreateFromMessyString(hardwareHash_raw);
222 if (hardwareKeygens.empty()) {
223 QMessageBox::critical(this, tr("Unable to Mangle"), tr("No valid request found in hardware textbox."));
224 return;
225 }
226 KeyGen hardwareKeygen = hardwareKeygens.front();
227
228 std::vector<KeyGen> pluginKeygens = KeyGen::CreateFromMessyString(pluginHashes_raw);
229 if (pluginKeygens.empty()) {
230 QMessageBox::critical(this, tr("Unable to Mangle"), tr("No valid request found in plugins textbox."));
231 return;
232 }
233
234 QString generatedRequest;
235 for (std::vector<KeyGen>::iterator it = pluginKeygens.begin(), it_end = pluginKeygens.end();
236 it != it_end; ++it) {
237
238 it->copyHardwareHashesFrom(hardwareKeygen);
239
240 generatedRequest += it->generateRequest();
241 }
242
243 requestData->setPlainText(generatedRequest);
244}
245
246void KeyGenWidget::slotDate() {
247 QDate today = QDate::currentDate();
248 today = today.addDays(days->value());
249 today = today.addMonths(months->value());
250 today = today.addYears(years->value());
251
252 expires->setDate(today);
253}
254
255void KeyGenWidget::slotAnalyze() {
256 QString inputData = requestData->toPlainText();
257 keygens_ = KeyGen::CreateFromMessyString(inputData);
258
259 keyList->clear();
260 for (const auto& keygen : keygens_) {
261 QListWidgetItem *newItem = new QListWidgetItem( keyList);
262 newItem->setText(keygen.name);
263 newItem->setHidden(false);
264 KeyGen::ValidationResult r = keygen.isValid();
265 if (!r)
266 newItem->setForeground(QColor(255, 0, 0));
267 else if (r == KeyGen::LATIN1)
268 newItem->setForeground(QColor(128, 128, 0));
269 }
270
271 generateLocalButton->setVisible(false);
272 generateAllButton->setVisible(!keygens_.empty());
273}
274
275void KeyGenWidget::slotSplit() {
276 // Get request data
277 QString inputData = requestData->toPlainText();
278
279 // Split with ;
280 QStringList data = inputData.split(";",Qt::SkipEmptyParts);
281
282 QString newText = data.join("\n");
283
284 requestData->setText(newText);
285
286}
287
288void KeyGenWidget::handleSelectionChanged(const QItemSelection& selection){
289 generateLocalButton->setVisible(false);
290 if(keyList->selectionModel()->selectedIndexes().count())
291 {
292 int i = keyList->selectionModel()->selectedIndexes()[0].row();
293 setKeyGen(&keygens_[i]);
294 generateLocalButton->setVisible(true);
295 generateAllButton->setVisible(true);
296
297 KeyGen::ValidationResult valid = keygens_[i].isValid();
298 if (valid == KeyGen::INVALID)
299 lbWarning->setText("ERROR: Signature does not match.\nCannot generate key");
300 else if (valid == KeyGen::LATIN1)
301 lbWarning->setText("WARNING: Request uses old Ascii format.\nKey will be generated with Ascii encoding.");
302 else
303 lbWarning->setText("");
304 }
305}
306
307KeyGenWidget::~KeyGenWidget() {
308
309}
310
311void KeyGenWidget::toFile(const KeyGen* gen)
312{
313 QString licenseFileName_ = gen->name;
314 std::cerr << "Writing License file to output : " << licenseFileName_.toStdString() << std::endl;
315 QFile outFile(licenseFileName_ + ".lic");
316
317 if (!outFile.open(QIODevice::WriteOnly|QIODevice::Text)) {
318 QMessageBox::critical(this,tr("Unable to open file"),tr("Unable to Open output File"));
319 return;
320 }
321
322 QTextStream output(&outFile);
323 output << gen->Generate(expires->date().toString(Qt::ISODate));
324 outFile.close();
325}
326
327void KeyGenWidget::setKeyGen(const KeyGen* gen) {
328 fileNameBox->setText(gen->name);
329 coreHashBox->setText(gen->coreHash);
330 pluginHashBox->setText(gen->pluginHash);
331 cpuHashBox->setText(gen->cpuHash);
332 productIDBox->setText(gen->productHash);
333 macHashBox->setText(gen->macHashes.join("\n"));
334 signatureBox->setText(gen->requestSig);
335 generateLocalButton->setEnabled(gen->isValid());
336}
337
338void KeyGenWidget::slotGenerateButton() {
339 if(keyList->selectionModel()->selectedIndexes().count())
340 {
341 int i = keyList->selectionModel()->selectedIndexes()[0].row();
342 toFile(&keygens_[i]);
343 }
344}
345
346void KeyGenWidget::slotGenerateAllButton() {
347 for(unsigned int i = 0; i < keygens_.size(); i++)
348 toFile(&keygens_[i]);
349}