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