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 }