qTox  Version: nightly | Commit: bc751c8e1cac455f9690654fcfe0f560d2d7dfdd
toxencrypt.cpp
Go to the documentation of this file.
1 /*
2  Copyright © 2017-2019 by The qTox Project Contributors
3 
4  This file is part of qTox, a Qt-based graphical interface for Tox.
5 
6  qTox is libre software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  qTox is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with qTox. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "toxencrypt.h"
21 #include <tox/toxencryptsave.h>
22 
23 #include <QByteArray>
24 #include <QDebug>
25 #include <QString>
26 #include <memory>
27 
28 // functions for nice debug output
29 static QString getKeyDerivationError(Tox_Err_Key_Derivation error);
30 static QString getEncryptionError(Tox_Err_Encryption error);
31 static QString getDecryptionError(Tox_Err_Decryption error);
32 static QString getSaltError(Tox_Err_Get_Salt error);
33 
46 {
47  tox_pass_key_free(passKey);
48 }
49 
54 ToxEncrypt::ToxEncrypt(Tox_Pass_Key* key)
55  : passKey{key}
56 {
57 }
58 
65 {
66  return TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
67 }
68 
74 bool ToxEncrypt::isEncrypted(const QByteArray& ciphertext)
75 {
76  if (ciphertext.length() < TOX_PASS_ENCRYPTION_EXTRA_LENGTH) {
77  return false;
78  }
79 
80  return tox_is_data_encrypted(reinterpret_cast<const uint8_t*>(ciphertext.constData()));
81 }
82 
83 
90 QByteArray ToxEncrypt::encryptPass(const QString& password, const QByteArray& plaintext)
91 {
92  if (password.length() == 0) {
93  qWarning() << "Empty password supplied, probably not what you intended.";
94  }
95 
96  QByteArray pass = password.toUtf8();
97  QByteArray ciphertext(plaintext.length() + TOX_PASS_ENCRYPTION_EXTRA_LENGTH, 0x00);
98  Tox_Err_Encryption error;
99  tox_pass_encrypt(reinterpret_cast<const uint8_t*>(plaintext.constData()),
100  static_cast<size_t>(plaintext.size()),
101  reinterpret_cast<const uint8_t*>(pass.constData()),
102  static_cast<size_t>(pass.size()),
103  reinterpret_cast<uint8_t*>(ciphertext.data()), &error);
104 
105  if (error != TOX_ERR_ENCRYPTION_OK) {
106  qCritical() << getEncryptionError(error);
107  return QByteArray{};
108  }
109 
110  return ciphertext;
111 }
112 
113 
120 QByteArray ToxEncrypt::decryptPass(const QString& password, const QByteArray& ciphertext)
121 {
122  if (!isEncrypted(ciphertext)) {
123  qWarning() << "The data was not encrypted using this module, or it's corrupted.";
124  return QByteArray{};
125  }
126 
127  if (password.length() == 0) {
128  qDebug() << "Empty password supplied, probably not what you intended.";
129  }
130 
131  QByteArray pass = password.toUtf8();
132  QByteArray plaintext(ciphertext.length() - TOX_PASS_ENCRYPTION_EXTRA_LENGTH, 0x00);
133  Tox_Err_Decryption error;
134  tox_pass_decrypt(reinterpret_cast<const uint8_t*>(ciphertext.constData()),
135  static_cast<size_t>(ciphertext.size()),
136  reinterpret_cast<const uint8_t*>(pass.constData()),
137  static_cast<size_t>(pass.size()), reinterpret_cast<uint8_t*>(plaintext.data()),
138  &error);
139 
140  if (error != TOX_ERR_DECRYPTION_OK) {
141  qWarning() << getDecryptionError(error);
142  return QByteArray{};
143  }
144 
145  return plaintext;
146 }
147 
156 std::unique_ptr<ToxEncrypt> ToxEncrypt::makeToxEncrypt(const QString& password)
157 {
158  const QByteArray pass = password.toUtf8();
159  Tox_Err_Key_Derivation error;
160  Tox_Pass_Key* const passKey = tox_pass_key_derive(
161  reinterpret_cast<const uint8_t*>(pass.constData()),
162  static_cast<size_t>(pass.length()), &error);
163 
164  if (error != TOX_ERR_KEY_DERIVATION_OK) {
165  tox_pass_key_free(passKey);
166  qCritical() << getKeyDerivationError(error);
167  return std::unique_ptr<ToxEncrypt>{};
168  }
169 
170  return std::unique_ptr<ToxEncrypt>(new ToxEncrypt(passKey));
171 }
172 
182 std::unique_ptr<ToxEncrypt> ToxEncrypt::makeToxEncrypt(const QString& password, const QByteArray& toxSave)
183 {
184  if (!isEncrypted(toxSave)) {
185  qWarning() << "The data was not encrypted using this module, or it's corrupted.";
186  return std::unique_ptr<ToxEncrypt>{};
187  }
188 
189  Tox_Err_Get_Salt saltError;
190  uint8_t salt[TOX_PASS_SALT_LENGTH];
191  tox_get_salt(reinterpret_cast<const uint8_t*>(toxSave.constData()), salt, &saltError);
192 
193  if (saltError != TOX_ERR_GET_SALT_OK) {
194  qWarning() << getSaltError(saltError);
195  return std::unique_ptr<ToxEncrypt>{};
196  }
197 
198  QByteArray pass = password.toUtf8();
199  Tox_Err_Key_Derivation keyError;
200  Tox_Pass_Key* const passKey = tox_pass_key_derive_with_salt(
201  reinterpret_cast<const uint8_t*>(pass.constData()),
202  static_cast<size_t>(pass.length()), salt, &keyError);
203 
204  if (keyError != TOX_ERR_KEY_DERIVATION_OK) {
205  tox_pass_key_free(passKey);
206  qWarning() << getKeyDerivationError(keyError);
207  return std::unique_ptr<ToxEncrypt>{};
208  }
209 
210  return std::unique_ptr<ToxEncrypt>(new ToxEncrypt(passKey));
211 }
212 
218 QByteArray ToxEncrypt::encrypt(const QByteArray& plaintext) const
219 {
220  if (!passKey) {
221  qCritical() << "The passkey is invalid.";
222  return QByteArray{};
223  }
224 
225  QByteArray ciphertext(plaintext.length() + TOX_PASS_ENCRYPTION_EXTRA_LENGTH, 0x00);
226  Tox_Err_Encryption error;
227  tox_pass_key_encrypt(passKey, reinterpret_cast<const uint8_t*>(plaintext.constData()),
228  static_cast<size_t>(plaintext.size()),
229  reinterpret_cast<uint8_t*>(ciphertext.data()), &error);
230 
231  if (error != TOX_ERR_ENCRYPTION_OK) {
232  qCritical() << getEncryptionError(error);
233  return QByteArray{};
234  }
235 
236  return ciphertext;
237 }
238 
239 
245 QByteArray ToxEncrypt::decrypt(const QByteArray& ciphertext) const
246 {
247  if (!isEncrypted(ciphertext)) {
248  qWarning() << "The data was not encrypted using this module, or it's corrupted.";
249  return QByteArray{};
250  }
251 
252  QByteArray plaintext(ciphertext.length() - TOX_PASS_ENCRYPTION_EXTRA_LENGTH, 0x00);
253  Tox_Err_Decryption error;
254  tox_pass_key_decrypt(passKey, reinterpret_cast<const uint8_t*>(ciphertext.constData()),
255  static_cast<size_t>(ciphertext.size()),
256  reinterpret_cast<uint8_t*>(plaintext.data()), &error);
257 
258  if (error != TOX_ERR_DECRYPTION_OK) {
259  qWarning() << getDecryptionError(error);
260  return QByteArray{};
261  }
262 
263  return plaintext;
264 }
265 
271 QString getKeyDerivationError(Tox_Err_Key_Derivation error)
272 {
273  switch (error) {
274  case TOX_ERR_KEY_DERIVATION_OK:
275  return QStringLiteral("The function returned successfully.");
276  case TOX_ERR_KEY_DERIVATION_NULL:
277  return QStringLiteral(
278  "One of the arguments to the function was NULL when it was not expected.");
279  case TOX_ERR_KEY_DERIVATION_FAILED:
280  return QStringLiteral(
281  "The crypto lib was unable to derive a key from the given passphrase.");
282  default:
283  return QStringLiteral("Unknown key derivation error.");
284  }
285 }
286 
292 QString getEncryptionError(Tox_Err_Encryption error)
293 {
294  switch (error) {
295  case TOX_ERR_ENCRYPTION_OK:
296  return QStringLiteral("The function returned successfully.");
297  case TOX_ERR_ENCRYPTION_NULL:
298  return QStringLiteral(
299  "One of the arguments to the function was NULL when it was not expected.");
300  case TOX_ERR_ENCRYPTION_KEY_DERIVATION_FAILED:
301  return QStringLiteral(
302  "The crypto lib was unable to derive a key from the given passphrase.");
303  case TOX_ERR_ENCRYPTION_FAILED:
304  return QStringLiteral("The encryption itself failed.");
305  default:
306  return QStringLiteral("Unknown encryption error.");
307  }
308 }
309 
315 QString getDecryptionError(Tox_Err_Decryption error)
316 {
317  switch (error) {
318  case TOX_ERR_DECRYPTION_OK:
319  return QStringLiteral("The function returned successfully.");
320  case TOX_ERR_DECRYPTION_NULL:
321  return QStringLiteral(
322  "One of the arguments to the function was NULL when it was not expected.");
323  case TOX_ERR_DECRYPTION_INVALID_LENGTH:
324  return QStringLiteral(
325  "The input data was shorter than TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes.");
326  case TOX_ERR_DECRYPTION_BAD_FORMAT:
327  return QStringLiteral("The input data is missing the magic number or is corrupted.");
328  case TOX_ERR_DECRYPTION_KEY_DERIVATION_FAILED:
329  return QStringLiteral("The crypto lib was unable to derive a key from the given passphrase.");
330  case TOX_ERR_DECRYPTION_FAILED:
331  return QStringLiteral("Decryption failed. Either the data was corrupted or the password/key was incorrect.");
332  default:
333  return QStringLiteral("Unknown decryption error.");
334  }
335 }
336 
342 QString getSaltError(Tox_Err_Get_Salt error)
343 {
344  switch (error) {
345  case TOX_ERR_GET_SALT_OK:
346  return QStringLiteral("The function returned successfully.");
347  case TOX_ERR_GET_SALT_NULL:
348  return QStringLiteral(
349  "One of the arguments to the function was NULL when it was not expected.");
350  case TOX_ERR_GET_SALT_BAD_FORMAT:
351  return QStringLiteral("The input data is missing the magic number or is corrupted.");
352  default:
353  return QStringLiteral("Unknown salt error.");
354  }
355 }
ToxEncrypt::encrypt
QByteArray encrypt(const QByteArray &plaintext) const
Encrypts the plaintext with the stored key.
Definition: toxencrypt.cpp:218
ToxEncrypt::~ToxEncrypt
~ToxEncrypt()
Frees the passKey before destruction.
Definition: toxencrypt.cpp:45
ToxEncrypt::makeToxEncrypt
static std::unique_ptr< ToxEncrypt > makeToxEncrypt(const QString &password)
Factory method for the ToxEncrypt object.
Definition: toxencrypt.cpp:156
ToxEncrypt::decrypt
QByteArray decrypt(const QByteArray &ciphertext) const
Decrypts data encrypted with this module, using the stored key.
Definition: toxencrypt.cpp:245
ToxEncrypt::isEncrypted
static bool isEncrypted(const QByteArray &ciphertext)
Checks if the data was encrypted by this module.
Definition: toxencrypt.cpp:74
ToxEncrypt::getMinBytes
static int getMinBytes()
Gets the minimum number of bytes needed for isEncrypted()
Definition: toxencrypt.cpp:64
ToxEncrypt::decryptPass
static QByteArray decryptPass(const QString &password, const QByteArray &ciphertext)
Decrypts data encrypted with this module.
Definition: toxencrypt.cpp:120
ToxEncrypt::encryptPass
static QByteArray encryptPass(const QString &password, const QByteArray &plaintext)
Encrypts the plaintext with the given password.
Definition: toxencrypt.cpp:90
ToxEncrypt::passKey
Tox_Pass_Key * passKey
Definition: toxencrypt.h:51
toxencrypt.h
ToxEncrypt::ToxEncrypt
ToxEncrypt()=delete