From b5890340e357124e7b691e59f03323b92b2766ca Mon Sep 17 00:00:00 2001 From: pokamest Date: Tue, 23 Aug 2022 22:47:23 +0300 Subject: [PATCH] Secure settings rework --- client/3rd/QSimpleCrypto/QSimpleCrypto.pri | 18 + client/3rd/QSimpleCrypto/include/QAead.h | 87 +++++ .../3rd/QSimpleCrypto/include/QBlockCipher.h | 83 ++++ .../3rd/QSimpleCrypto/include/QCryptoError.h | 45 +++ client/3rd/QSimpleCrypto/include/QRsa.h | 104 +++++ .../include/QSimpleCrypto_global.h | 9 + client/3rd/QSimpleCrypto/include/QX509.h | 87 +++++ client/3rd/QSimpleCrypto/include/QX509Store.h | 120 ++++++ client/3rd/QSimpleCrypto/sources/QAead.cpp | 364 ++++++++++++++++++ .../QSimpleCrypto/sources/QBlockCipher.cpp | 184 +++++++++ .../QSimpleCrypto/sources/QCryptoError.cpp | 6 + client/3rd/QSimpleCrypto/sources/QRsa.cpp | 274 +++++++++++++ client/3rd/QSimpleCrypto/sources/QX509.cpp | 234 +++++++++++ .../3rd/QSimpleCrypto/sources/QX509Store.cpp | 176 +++++++++ client/client.pro | 5 +- client/encryption_helper.cpp | 143 ------- client/encryption_helper.h | 31 -- client/secure_qsettings.cpp | 103 +++-- client/secure_qsettings.h | 11 +- client/settings.cpp | 1 - client/settings.h | 1 - 21 files changed, 1863 insertions(+), 223 deletions(-) create mode 100644 client/3rd/QSimpleCrypto/QSimpleCrypto.pri create mode 100644 client/3rd/QSimpleCrypto/include/QAead.h create mode 100644 client/3rd/QSimpleCrypto/include/QBlockCipher.h create mode 100644 client/3rd/QSimpleCrypto/include/QCryptoError.h create mode 100644 client/3rd/QSimpleCrypto/include/QRsa.h create mode 100644 client/3rd/QSimpleCrypto/include/QSimpleCrypto_global.h create mode 100644 client/3rd/QSimpleCrypto/include/QX509.h create mode 100644 client/3rd/QSimpleCrypto/include/QX509Store.h create mode 100644 client/3rd/QSimpleCrypto/sources/QAead.cpp create mode 100644 client/3rd/QSimpleCrypto/sources/QBlockCipher.cpp create mode 100644 client/3rd/QSimpleCrypto/sources/QCryptoError.cpp create mode 100644 client/3rd/QSimpleCrypto/sources/QRsa.cpp create mode 100644 client/3rd/QSimpleCrypto/sources/QX509.cpp create mode 100644 client/3rd/QSimpleCrypto/sources/QX509Store.cpp delete mode 100644 client/encryption_helper.cpp delete mode 100644 client/encryption_helper.h diff --git a/client/3rd/QSimpleCrypto/QSimpleCrypto.pri b/client/3rd/QSimpleCrypto/QSimpleCrypto.pri new file mode 100644 index 000000000..99a1c1293 --- /dev/null +++ b/client/3rd/QSimpleCrypto/QSimpleCrypto.pri @@ -0,0 +1,18 @@ +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/include/QAead.h \ + $$PWD/include/QBlockCipher.h \ + $$PWD/include/QCryptoError.h \ + $$PWD/include/QRsa.h \ + $$PWD/include/QSimpleCrypto_global.h \ + $$PWD/include/QX509.h \ + $$PWD/include/QX509Store.h + +SOURCES += \ + $$PWD/sources/QAead.cpp \ + $$PWD/sources/QBlockCipher.cpp \ + $$PWD/sources/QCryptoError.cpp \ + $$PWD/sources/QRsa.cpp \ + $$PWD/sources/QX509.cpp \ + $$PWD/sources/QX509Store.cpp diff --git a/client/3rd/QSimpleCrypto/include/QAead.h b/client/3rd/QSimpleCrypto/include/QAead.h new file mode 100644 index 000000000..11f60b31f --- /dev/null +++ b/client/3rd/QSimpleCrypto/include/QAead.h @@ -0,0 +1,87 @@ +/** + * Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution +**/ + +#ifndef QAEAD_H +#define QAEAD_H + +#include "QSimpleCrypto_global.h" + +#include + +#include + +#include +#include +#include +#include + +#include "QCryptoError.h" + +// clang-format off +namespace QSimpleCrypto +{ + class QSIMPLECRYPTO_EXPORT QAead { + public: + QAead(); + + /// + /// \brief encryptAesGcm - Function encrypts data with Gcm algorithm. + /// \param data - Data that will be encrypted. + /// \param key - AES key. + /// \param iv - Initialization vector. + /// \param tag - Authorization tag. + /// \param aad - Additional authenticated data. Must be nullptr, if not used. + /// \param cipher - Can be used with OpenSSL EVP_CIPHER (gcm) - 128, 192, 256. Example: EVP_aes_256_gcm(). + /// \return Returns encrypted data or "", if error happened. + /// + QByteArray encryptAesGcm(QByteArray data, QByteArray key, QByteArray iv, QByteArray* tag, QByteArray aad = "", const EVP_CIPHER* cipher = EVP_aes_256_gcm()); + + /// + /// \brief decryptAesGcm - Function decrypts data with Gcm algorithm. + /// \param data - Data that will be decrypted + /// \param key - AES key + /// \param iv - Initialization vector + /// \param tag - Authorization tag + /// \param aad - Additional authenticated data. Must be nullptr, if not used + /// \param cipher - Can be used with OpenSSL EVP_CIPHER (gcm) - 128, 192, 256. Example: EVP_aes_256_gcm() + /// \return Returns decrypted data or "", if error happened. + /// + QByteArray decryptAesGcm(QByteArray data, QByteArray key, QByteArray iv, QByteArray* tag, QByteArray aad = "", const EVP_CIPHER* cipher = EVP_aes_256_gcm()); + + /// + /// \brief encryptAesCcm - Function encrypts data with Ccm algorithm. + /// \param data - Data that will be encrypted. + /// \param key - AES key. + /// \param iv - Initialization vector. + /// \param tag - Authorization tag. + /// \param aad - Additional authenticated data. Must be nullptr, if not used. + /// \param cipher - Can be used with OpenSSL EVP_CIPHER (ccm) - 128, 192, 256. Example: EVP_aes_256_ccm(). + /// \return Returns encrypted data or "", if error happened. + /// + QByteArray encryptAesCcm(QByteArray data, QByteArray key, QByteArray iv, QByteArray* tag, QByteArray aad = "", const EVP_CIPHER* cipher = EVP_aes_256_ccm()); + + /// + /// \brief decryptAesCcm - Function decrypts data with Ccm algorithm. + /// \param data - Data that will be decrypted. + /// \param key - AES key. + /// \param iv - Initialization vector. + /// \param tag - Authorization tag. + /// \param aad - Additional authenticated data. Must be nullptr, if not used. + /// \param cipher - Can be used with OpenSSL EVP_CIPHER (ccm) - 128, 192, 256. Example: EVP_aes_256_ccm(). + /// \return Returns decrypted data or "", if error happened. + /// + QByteArray decryptAesCcm(QByteArray data, QByteArray key, QByteArray iv, QByteArray* tag, QByteArray aad = "", const EVP_CIPHER* cipher = EVP_aes_256_ccm()); + + /// + /// \brief error - Error handler class. + /// + QCryptoError error; + }; +} // namespace QSimpleCrypto + +#endif // QAEAD_H diff --git a/client/3rd/QSimpleCrypto/include/QBlockCipher.h b/client/3rd/QSimpleCrypto/include/QBlockCipher.h new file mode 100644 index 000000000..af57b650f --- /dev/null +++ b/client/3rd/QSimpleCrypto/include/QBlockCipher.h @@ -0,0 +1,83 @@ +/** + * Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution +**/ + +#ifndef QBLOCKCIPHER_H +#define QBLOCKCIPHER_H + +#include "QSimpleCrypto_global.h" + +#include + +#include + +#include +#include +#include +#include + +#include "QCryptoError.h" + +// clang-format off +namespace QSimpleCrypto +{ + class QSIMPLECRYPTO_EXPORT QBlockCipher { + + #define Aes128Rounds 10 + #define Aes192Rounds 12 + #define Aes256Rounds 14 + + public: + QBlockCipher(); + + /// + /// \brief generateRandomBytes - Function generates random bytes by size. + /// \param size - Size of generated bytes. + /// \return Returns random bytes. + /// + QByteArray generateRandomBytes(const int& size); + + /// + /// \brief encryptAesBlockCipher - Function encrypts data with Aes Block Cipher algorithm. + /// \param data - Data that will be encrypted. + /// \param key - AES key. + /// \param iv - Initialization vector. + /// \param password - Encryption password. + /// \param salt - Random delta. + /// \param rounds - Transformation rounds. + /// \param chiper - Can be used with OpenSSL EVP_CIPHER (ecb, cbc, cfb, ofb, ctr) - 128, 192, 256. Example: EVP_aes_256_cbc(). + /// \param md - Hash algroitm (OpenSSL EVP_MD). Example: EVP_sha512(). + /// \return Returns decrypted data or "", if error happened. + /// + QByteArray encryptAesBlockCipher(QByteArray data, QByteArray key, + QByteArray iv = "", const int& rounds = Aes256Rounds, + const EVP_CIPHER* cipher = EVP_aes_256_cbc(), const EVP_MD* md = EVP_sha512()); + + /// + /// \brief decryptAesBlockCipher - Function decrypts data with Aes Block Cipher algorithm. + /// \param data - Data that will be decrypted. + /// \param key - AES key. + /// \param iv - Initialization vector. + /// \param password - Decryption password. + /// \param salt - Random delta. + /// \param rounds - Transformation rounds. + /// \param chiper - Can be used with OpenSSL EVP_CIPHER (ecb, cbc, cfb, ofb, ctr) - 128, 192, 256. Example: EVP_aes_256_cbc(). + /// \param md - Hash algroitm (OpenSSL EVP_MD). Example: EVP_sha512(). + /// \return Returns decrypted data or "", if error happened. + /// + QByteArray decryptAesBlockCipher(QByteArray data, QByteArray key, + QByteArray iv = "", const int& rounds = Aes256Rounds, + const EVP_CIPHER* cipher = EVP_aes_256_cbc(), const EVP_MD* md = EVP_sha512()); + + /// + /// \brief error - Error handler class. + /// + QCryptoError error; + }; +} // namespace QSimpleCrypto + +#endif // QBLOCKCIPHER_H diff --git a/client/3rd/QSimpleCrypto/include/QCryptoError.h b/client/3rd/QSimpleCrypto/include/QCryptoError.h new file mode 100644 index 000000000..fc0596545 --- /dev/null +++ b/client/3rd/QSimpleCrypto/include/QCryptoError.h @@ -0,0 +1,45 @@ +#ifndef QCRYPTOERROR_H +#define QCRYPTOERROR_H + +#include + +#include "QSimpleCrypto_global.h" + +/// TODO: Add Special error code for each error. + +// clang-format off +namespace QSimpleCrypto +{ + class QSIMPLECRYPTO_EXPORT QCryptoError : public QObject { + Q_OBJECT + + public: + explicit QCryptoError(QObject* parent = nullptr); + + /// + /// \brief setError - Sets error information + /// \param errorCode - Error code. + /// \param errorSummary - Error summary. + /// + inline void setError(const quint8 errorCode, const QString& errorSummary) + { + m_currentErrorCode = errorCode; + m_errorSummary = errorSummary; + } + + /// + /// \brief lastError - Returns last error. + /// \return Returns eror ID and error Text. + /// + inline QPair lastError() const + { + return QPair(m_currentErrorCode, m_errorSummary); + } + + private: + quint8 m_currentErrorCode; + QString m_errorSummary; + }; +} + +#endif // QCRYPTOERROR_H diff --git a/client/3rd/QSimpleCrypto/include/QRsa.h b/client/3rd/QSimpleCrypto/include/QRsa.h new file mode 100644 index 000000000..45eb31693 --- /dev/null +++ b/client/3rd/QSimpleCrypto/include/QRsa.h @@ -0,0 +1,104 @@ +/** + * Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution +**/ + +#ifndef QRSA_H +#define QRSA_H + +#include "QSimpleCrypto_global.h" + +#include +#include + +#include + +#include +#include +#include + +#include "QCryptoError.h" + +// clang-format off +namespace QSimpleCrypto +{ + class QSIMPLECRYPTO_EXPORT QRsa { + + #define PublicEncrypt 0 + #define PrivateEncrypt 1 + #define PublicDecrypt 2 + #define PrivateDecrypt 3 + + public: + QRsa(); + + /// + /// \brief generateRsaKeys - Function generate Rsa Keys and returns them in OpenSSL structure. + /// \param bits - RSA key size. + /// \param rsaBigNumber - The exponent is an odd number, typically 3, 17 or 65537. + /// \return Returns 'OpenSSL RSA structure' or 'nullptr', if error happened. Returned value must be cleaned up with 'RSA_free()' to avoid memory leak. + /// + RSA* generateRsaKeys(const int& bits, const int& rsaBigNumber); + + /// + /// \brief savePublicKey - Saves to file RSA public key. + /// \param rsa - OpenSSL RSA structure. + /// \param publicKeyFileName - Public key file name. + /// + void savePublicKey(RSA *rsa, const QByteArray& publicKeyFileName); + + /// + /// \brief savePrivateKey - Saves to file RSA private key. + /// \param rsa - OpenSSL RSA structure. + /// \param privateKeyFileName - Private key file name. + /// \param password - Private key password. + /// \param cipher - Can be used with 'OpenSSL EVP_CIPHER' (ecb, cbc, cfb, ofb, ctr) - 128, 192, 256. Example: EVP_aes_256_cbc(). + /// + void savePrivateKey(RSA* rsa, const QByteArray& privateKeyFileName, QByteArray password = "", const EVP_CIPHER* cipher = nullptr); + + /// + /// \brief getPublicKeyFromFile - Gets RSA public key from a file. + /// \param filePath - File path to public key file. + /// \return Returns 'OpenSSL EVP_PKEY structure' or 'nullptr', if error happened. Returned value must be cleaned up with 'EVP_PKEY_free()' to avoid memory leak. + /// + EVP_PKEY* getPublicKeyFromFile(const QByteArray& filePath); + + /// + /// \brief getPrivateKeyFromFile - Gets RSA private key from a file. + /// \param filePath - File path to private key file. + /// \param password - Private key password. + /// \return - Returns 'OpenSSL EVP_PKEY structure' or 'nullptr', if error happened. Returned value must be cleaned up with 'EVP_PKEY_free()' to avoid memory leak. + /// + EVP_PKEY* getPrivateKeyFromFile(const QByteArray& filePath, const QByteArray& password = ""); + + /// + /// \brief encrypt - Encrypt data with RSA algorithm. + /// \param plaintext - Text that must be encrypted. + /// \param rsa - OpenSSL RSA structure. + /// \param encryptType - Public or private encrypt type. (PUBLIC_ENCRYPT, PRIVATE_ENCRYPT). + /// \param padding - OpenSSL RSA padding can be used with: 'RSA_PKCS1_PADDING', 'RSA_NO_PADDING' and etc. + /// \return Returns encrypted data or "", if error happened. + /// + QByteArray encrypt(QByteArray plainText, RSA* rsa, const int& encryptType = PublicEncrypt, const int& padding = RSA_PKCS1_PADDING); + + /// + /// \brief decrypt - Decrypt data with RSA algorithm. + /// \param cipherText - Text that must be decrypted. + /// \param rsa - OpenSSL RSA structure. + /// \param decryptType - Public or private type. (PUBLIC_DECRYPT, PRIVATE_DECRYPT). + /// \param padding - RSA padding can be used with: 'RSA_PKCS1_PADDING', 'RSA_NO_PADDING' and etc. + /// \return - Returns decrypted data or "", if error happened. + /// + QByteArray decrypt(QByteArray cipherText, RSA* rsa, const int& decryptType = PrivateDecrypt, const int& padding = RSA_PKCS1_PADDING); + + /// + /// \brief error - Error handler class. + /// + QCryptoError error; + }; +} // namespace QSimpleCrypto + +#endif // QRSA_H diff --git a/client/3rd/QSimpleCrypto/include/QSimpleCrypto_global.h b/client/3rd/QSimpleCrypto/include/QSimpleCrypto_global.h new file mode 100644 index 000000000..fdd6c020b --- /dev/null +++ b/client/3rd/QSimpleCrypto/include/QSimpleCrypto_global.h @@ -0,0 +1,9 @@ +#ifndef QSIMPLECRYPTO_GLOBAL_H +#define QSIMPLECRYPTO_GLOBAL_H + +#include +#include + +#define QSIMPLECRYPTO_EXPORT + +#endif // QSIMPLECRYPTO_GLOBAL_H diff --git a/client/3rd/QSimpleCrypto/include/QX509.h b/client/3rd/QSimpleCrypto/include/QX509.h new file mode 100644 index 000000000..96e0c76cb --- /dev/null +++ b/client/3rd/QSimpleCrypto/include/QX509.h @@ -0,0 +1,87 @@ +/** + * Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution +**/ + +#ifndef QX509_H +#define QX509_H + +#include "QSimpleCrypto_global.h" + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "QCryptoError.h" + +// clang-format off +namespace QSimpleCrypto +{ + class QSIMPLECRYPTO_EXPORT QX509 { + + #define oneYear 31536000L + #define x509LastVersion 2 + + public: + QX509(); + + /// + /// \brief loadCertificateFromFile - Function load X509 from file and returns OpenSSL structure. + /// \param fileName - File path to certificate. + /// \return Returns OpenSSL X509 structure or nullptr, if error happened. Returned value must be cleaned up with 'X509_free' to avoid memory leak. + /// + X509* loadCertificateFromFile(const QByteArray& fileName); + + /// + /// \brief signCertificate - Function signs X509 certificate and returns signed X509 OpenSSL structure. + /// \param endCertificate - Certificate that will be signed + /// \param caCertificate - CA certificate that will sign end certificate + /// \param caPrivateKey - CA certificate private key + /// \param fileName - With that name certificate will be saved. Leave "", if don't need to save it + /// \return Returns OpenSSL X509 structure or nullptr, if error happened. + /// + X509* signCertificate(X509* endCertificate, X509* caCertificate, EVP_PKEY* caPrivateKey, const QByteArray& fileName = ""); + + /// + /// \brief verifyCertificate - Function verifies X509 certificate and returns verified X509 OpenSSL structure. + /// \param x509 - OpenSSL X509. That certificate will be verified. + /// \param store - Trusted certificate must be added to X509_Store with 'addCertificateToStore(X509_STORE* ctx, X509* x509)'. + /// \return Returns OpenSSL X509 structure or nullptr, if error happened + /// + X509* verifyCertificate(X509* x509, X509_STORE* store); + + /// + /// \brief generateSelfSignedCertificate - Function generatesand returns self signed X509. + /// \param rsa - OpenSSL RSA. + /// \param additionalData - Certificate information. + /// \param certificateFileName - With that name certificate will be saved. Leave "", if don't need to save it. + /// \param md - OpenSSL EVP_MD structure. Example: EVP_sha512(). + /// \param serialNumber - X509 certificate serial number. + /// \param version - X509 certificate version. + /// \param notBefore - X509 start date. + /// \param notAfter - X509 end date. + /// \return Returns OpenSSL X509 structure or nullptr, if error happened. Returned value must be cleaned up with 'X509_free' to avoid memory leak. + /// + X509* generateSelfSignedCertificate(const RSA* rsa, const QMap& additionalData, + const QByteArray& certificateFileName = "", const EVP_MD* md = EVP_sha512(), + const long& serialNumber = 1, const long& version = x509LastVersion, + const long& notBefore = 0, const long& notAfter = oneYear); + + /// + /// \brief error - Error handler class. + /// + QCryptoError error; + }; +} // namespace QSimpleCrypto + +#endif // QX509_H diff --git a/client/3rd/QSimpleCrypto/include/QX509Store.h b/client/3rd/QSimpleCrypto/include/QX509Store.h new file mode 100644 index 000000000..8cd8ca82b --- /dev/null +++ b/client/3rd/QSimpleCrypto/include/QX509Store.h @@ -0,0 +1,120 @@ +/** + * Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution +**/ + +#ifndef QX509STORE_H +#define QX509STORE_H + +#include "QSimpleCrypto_global.h" + +#include +#include +#include + +#include + +#include +#include +#include + +#include "QCryptoError.h" + +// clang-format off +namespace QSimpleCrypto +{ + class QSIMPLECRYPTO_EXPORT QX509Store { + public: + QX509Store(); + + /// + /// \brief addCertificateToStore + /// \param store - OpenSSL X509_STORE. + /// \param x509 - OpenSSL X509. + /// \return Returns 'true' on success and 'false', if error happened. + /// + bool addCertificateToStore(X509_STORE* store, X509* x509); + + /// + /// \brief addLookup + /// \param store - OpenSSL X509_STORE. + /// \param method - OpenSSL X509_LOOKUP_METHOD. Example: X509_LOOKUP_file. + /// \return Returns 'true' on success and 'false', if error happened. + /// + bool addLookup(X509_STORE* store, X509_LOOKUP_METHOD* method); + + /// + /// \brief setCertificateDepth + /// \param store - OpenSSL X509_STORE. + /// \param depth - That is the maximum number of untrusted CA certificates that can appear in a chain. Example: 0. + /// \return Returns 'true' on success and 'false', if error happened. + /// + bool setDepth(X509_STORE* store, const int& depth); + + /// + /// \brief setFlag + /// \param store - OpenSSL X509_STORE. + /// \param flag - The verification flags consists of zero or more of the following flags ored together. Example: X509_V_FLAG_CRL_CHECK. + /// \return Returns 'true' on success and 'false', if error happened. + /// + bool setFlag(X509_STORE* store, const unsigned long& flag); + + /// + /// \brief setFlag + /// \param store - OpenSSL X509_STORE. + /// \param purpose - Verification purpose in param to purpose. Example: X509_PURPOSE_ANY. + /// \return Returns 'true' on success and 'false', if error happened. + /// + bool setPurpose(X509_STORE* store, const int& purpose); + + /// + /// \brief setTrust + /// \param store - OpenSSL X509_STORE. + /// \param trust - Trust Level. Example: X509_TRUST_SSL_SERVER. + /// \return Returns 'true' on success and 'false', if error happened. + /// + bool setTrust(X509_STORE* store, const int& trust); + + /// + /// \brief setDefaultPaths + /// \param store - OpenSSL X509_STORE. + /// \return Returns 'true' on success and 'false', if error happened. + /// + bool setDefaultPaths(X509_STORE* store); + + /// + /// \brief loadLocations + /// \param store - OpenSSL X509_STORE. + /// \param fileName - File name. Example: "caCertificate.pem". + /// \param dirPath - Path to file. Example: "path/To/File". + /// \return Returns 'true' on success and 'false', if error happened. + /// + bool loadLocations(X509_STORE* store, const QByteArray& fileName, const QByteArray& dirPath); + + /// + /// \brief loadLocations + /// \param store - OpenSSL X509_STORE. + /// \param file - Qt QFile that will be loaded. + /// \return Returns 'true' on success and 'false', if error happened. + /// + bool loadLocations(X509_STORE* store, const QFile& file); + + /// + /// \brief loadLocations + /// \param store - OpenSSL X509_STORE. + /// \param fileInfo - Qt QFileInfo. + /// \return Returns 'true' on success and 'false', if error happened. + /// + bool loadLocations(X509_STORE* store, const QFileInfo& fileInfo); + + /// + /// \brief error - Error handler class. + /// + QCryptoError error; + }; +} + +#endif // QX509STORE_H diff --git a/client/3rd/QSimpleCrypto/sources/QAead.cpp b/client/3rd/QSimpleCrypto/sources/QAead.cpp new file mode 100644 index 000000000..968c88417 --- /dev/null +++ b/client/3rd/QSimpleCrypto/sources/QAead.cpp @@ -0,0 +1,364 @@ +/** + * Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution +**/ + +#include "include/QAead.h" + +QSimpleCrypto::QAead::QAead() +{ +} + +/// +/// \brief QSimpleCrypto::QAEAD::encryptAesGcm - Function encrypts data with Gcm algorithm. +/// \param data - Data that will be encrypted. +/// \param key - AES key. +/// \param iv - Initialization vector. +/// \param tag - Authorization tag. +/// \param aad - Additional authenticated data. Must be nullptr, if not used. +/// \param cipher - Can be used with OpenSSL EVP_CIPHER (gcm) - 128, 192, 256. Example: EVP_aes_256_gcm(). +/// \return Returns encrypted data or "", if error happened. +/// +QByteArray QSimpleCrypto::QAead::encryptAesGcm(QByteArray data, QByteArray key, QByteArray iv, QByteArray* tag, QByteArray aad, const EVP_CIPHER* cipher) +{ + try { + /* Initialize EVP_CIPHER_CTX */ + std::unique_ptr encryptionCipher { EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free }; + if (encryptionCipher == nullptr) { + throw std::runtime_error("Couldn't initialize \'encryptionCipher\'. EVP_CIPHER_CTX_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Set data length */ + int plainTextLength = data.size(); + int cipherTextLength = 0; + + /* Initialize cipherText. Here encrypted data will be stored */ + std::unique_ptr cipherText { new unsigned char[plainTextLength]() }; + if (cipherText == nullptr) { + throw std::runtime_error("Couldn't allocate memory for 'ciphertext'."); + } + + /* Initialize encryption operation. */ + if (!EVP_EncryptInit_ex(encryptionCipher.get(), cipher, nullptr, reinterpret_cast(key.data()), reinterpret_cast(iv.data()))) { + throw std::runtime_error("Couldn't initialize encryption operation. EVP_EncryptInit_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Set IV length if default 12 bytes (96 bits) is not appropriate */ + if (!EVP_CIPHER_CTX_ctrl(encryptionCipher.get(), EVP_CTRL_GCM_SET_IVLEN, iv.length(), nullptr)) { + throw std::runtime_error("Couldn't set IV length. EVP_CIPHER_CTX_ctrl(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + +// /* Check if aad need to be used */ +// if (aad.length() > 0) { +// /* Provide any AAD data. This can be called zero or more times as required */ +// if (!EVP_EncryptUpdate(encryptionCipher.get(), nullptr, &cipherTextLength, reinterpret_cast(aad.data()), aad.length())) { +// throw std::runtime_error("Couldn't provide aad data. EVP_EncryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); +// } +// } + + /* + * Provide the message to be encrypted, and obtain the encrypted output. + * EVP_EncryptUpdate can be called multiple times if necessary + */ + if (!EVP_EncryptUpdate(encryptionCipher.get(), cipherText.get(), &cipherTextLength, reinterpret_cast(data.data()), plainTextLength)) { + throw std::runtime_error("Couldn't provide message to be encrypted. EVP_EncryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* + * Finalize the encryption. Normally cipher text bytes may be written at + * this stage, but this does not occur in GCM mode + */ + if (!EVP_EncryptFinal_ex(encryptionCipher.get(), cipherText.get(), &plainTextLength)) { + throw std::runtime_error("Couldn't finalize encryption. EVP_EncryptFinal_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + +// /* Get tag */ +// if (!EVP_CIPHER_CTX_ctrl(encryptionCipher.get(), EVP_CTRL_GCM_GET_TAG, tag->length(), reinterpret_cast(tag->data()))) { +// throw std::runtime_error("Couldn't get tag. EVP_CIPHER_CTX_ctrl(. Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); +// } + + /* Finilize data to be readable with qt */ + QByteArray encryptedData = QByteArray(reinterpret_cast(cipherText.get()), cipherTextLength); + + return encryptedData; + + } catch (std::exception& exception) { + QSimpleCrypto::QAead::error.setError(1, exception.what()); + return QByteArray(); + } catch (...) { + QSimpleCrypto::QAead::error.setError(2, "Unknown error!"); + return QByteArray(); + } + + return QByteArray(); +} + +/// +/// \brief QSimpleCrypto::QAEAD::decryptAesGcm - Function decrypts data with Gcm algorithm. +/// \param data - Data that will be decrypted +/// \param key - AES key +/// \param iv - Initialization vector +/// \param tag - Authorization tag +/// \param aad - Additional authenticated data. Must be nullptr, if not used +/// \param cipher - Can be used with OpenSSL EVP_CIPHER (gcm) - 128, 192, 256. Example: EVP_aes_256_gcm() +/// \return Returns decrypted data or "", if error happened. +/// +QByteArray QSimpleCrypto::QAead::decryptAesGcm(QByteArray data, QByteArray key, QByteArray iv, QByteArray* tag, QByteArray aad, const EVP_CIPHER* cipher) +{ + try { + /* Initialize EVP_CIPHER_CTX */ + std::unique_ptr decryptionCipher { EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free }; + if (decryptionCipher.get() == nullptr) { + throw std::runtime_error("Couldn't initialize \'decryptionCipher\'. EVP_CIPHER_CTX_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Set data length */ + int cipherTextLength = data.size(); + int plainTextLength = 0; + + /* Initialize plainText. Here decrypted data will be stored */ + std::unique_ptr plainText { new unsigned char[cipherTextLength]() }; + if (plainText == nullptr) { + throw std::runtime_error("Couldn't allocate memory for 'plaintext'."); + } + + /* Initialize decryption operation. */ + if (!EVP_DecryptInit_ex(decryptionCipher.get(), cipher, nullptr, reinterpret_cast(key.data()), reinterpret_cast(iv.data()))) { + throw std::runtime_error("Couldn't initialize decryption operation. EVP_DecryptInit_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Set IV length. Not necessary if this is 12 bytes (96 bits) */ + if (!EVP_CIPHER_CTX_ctrl(decryptionCipher.get(), EVP_CTRL_GCM_SET_IVLEN, iv.length(), nullptr)) { + throw std::runtime_error("Couldn't set IV length. EVP_CIPHER_CTX_ctrl(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + +// /* Check if aad need to be used */ +// if (aad.length() > 0) { +// /* Provide any AAD data. This can be called zero or more times as required */ +// if (!EVP_DecryptUpdate(decryptionCipher.get(), nullptr, &plainTextLength, reinterpret_cast(aad.data()), aad.length())) { +// throw std::runtime_error("Couldn't provide aad data. EVP_DecryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); +// } +// } + + /* + * Provide the message to be decrypted, and obtain the plain text output. + * EVP_DecryptUpdate can be called multiple times if necessary + */ + if (!EVP_DecryptUpdate(decryptionCipher.get(), plainText.get(), &plainTextLength, reinterpret_cast(data.data()), cipherTextLength)) { + throw std::runtime_error("Couldn't provide message to be decrypted. EVP_DecryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + +// /* Set expected tag value. Works in OpenSSL 1.0.1d and later */ +// if (!EVP_CIPHER_CTX_ctrl(decryptionCipher.get(), EVP_CTRL_GCM_SET_TAG, tag->length(), reinterpret_cast(tag->data()))) { +// throw std::runtime_error("Coldn't set tag. EVP_CIPHER_CTX_ctrl(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); +// } + + /* + * Finalize the decryption. A positive return value indicates success, + * anything else is a failure - the plain text is not trustworthy. + */ + if (!EVP_DecryptFinal_ex(decryptionCipher.get(), plainText.get(), &cipherTextLength)) { + throw std::runtime_error("Couldn't finalize decryption. EVP_DecryptFinal_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Finilize data to be readable with qt */ + QByteArray decryptedData = QByteArray(reinterpret_cast(plainText.get()), plainTextLength); + + return decryptedData; + + } catch (std::exception& exception) { + QSimpleCrypto::QAead::error.setError(1, exception.what()); + return QByteArray(); + } catch (...) { + QSimpleCrypto::QAead::error.setError(2, "Unknown error!"); + return QByteArray(); + } + + return QByteArray(); +} + +/// +/// \brief QSimpleCrypto::QAEAD::encryptAesCcm - Function encrypts data with Ccm algorithm. +/// \param data - Data that will be encrypted. +/// \param key - AES key. +/// \param iv - Initialization vector. +/// \param tag - Authorization tag. +/// \param aad - Additional authenticated data. Must be nullptr, if not used. +/// \param cipher - Can be used with OpenSSL EVP_CIPHER (ccm) - 128, 192, 256. Example: EVP_aes_256_ccm(). +/// \return Returns encrypted data or "", if error happened. +/// +QByteArray QSimpleCrypto::QAead::encryptAesCcm(QByteArray data, QByteArray key, QByteArray iv, QByteArray* tag, QByteArray aad, const EVP_CIPHER* cipher) +{ + try { + /* Initialize EVP_CIPHER_CTX */ + std::unique_ptr encryptionCipher { EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free }; + if (encryptionCipher == nullptr) { + throw std::runtime_error("Couldn't initialize \'encryptionCipher\'. EVP_CIPHER_CTX_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Set data length */ + int plainTextLength = data.size(); + int cipherTextLength = 0; + + /* Initialize cipherText. Here encrypted data will be stored */ + std::unique_ptr cipherText { new unsigned char[plainTextLength]() }; + if (cipherText.get() == nullptr) { + throw std::runtime_error("Couldn't allocate memory for 'ciphertext'."); + } + + /* Initialize encryption operation. */ + if (!EVP_EncryptInit_ex(encryptionCipher.get(), cipher, nullptr, reinterpret_cast(key.data()), reinterpret_cast(iv.data()))) { + throw std::runtime_error("Couldn't initialize encryption operation. EVP_EncryptInit_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Set IV length if default 12 bytes (96 bits) is not appropriate */ + if (!EVP_CIPHER_CTX_ctrl(encryptionCipher.get(), EVP_CTRL_CCM_SET_IVLEN, iv.length(), nullptr)) { + throw std::runtime_error("Couldn't set IV length. EVP_CIPHER_CTX_ctrl(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Set tag length */ + if (!EVP_CIPHER_CTX_ctrl(encryptionCipher.get(), EVP_CTRL_CCM_SET_TAG, tag->length(), nullptr)) { + throw std::runtime_error("Coldn't set tag. EVP_CIPHER_CTX_ctrl(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Check if aad need to be used */ + if (aad.length() > 0) { + /* Provide the total plain text length */ + if (!EVP_EncryptUpdate(encryptionCipher.get(), nullptr, &cipherTextLength, nullptr, plainTextLength)) { + throw std::runtime_error("Couldn't provide total plaintext length. EVP_EncryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Provide any AAD data. This can be called zero or more times as required */ + if (!EVP_EncryptUpdate(encryptionCipher.get(), nullptr, &cipherTextLength, reinterpret_cast(aad.data()), aad.length())) { + throw std::runtime_error("Couldn't provide aad data. EVP_EncryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + } + + /* + * Provide the message to be encrypted, and obtain the encrypted output. + * EVP_EncryptUpdate can be called multiple times if necessary + */ + if (!EVP_EncryptUpdate(encryptionCipher.get(), cipherText.get(), &cipherTextLength, reinterpret_cast(data.data()), plainTextLength)) { + throw std::runtime_error("Couldn't provide message to be encrypted. EVP_EncryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* + * Finalize the encryption. Normally ciphertext bytes may be written at + * this stage, but this does not occur in GCM mode + */ + if (!EVP_EncryptFinal_ex(encryptionCipher.get(), cipherText.get(), &plainTextLength)) { + throw std::runtime_error("Couldn't finalize encryption. EVP_EncryptFinal_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Get tag */ + if (!EVP_CIPHER_CTX_ctrl(encryptionCipher.get(), EVP_CTRL_CCM_GET_TAG, tag->length(), reinterpret_cast(tag->data()))) { + throw std::runtime_error("Couldn't get tag. EVP_CIPHER_CTX_ctrl(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Finilize data to be readable with qt */ + QByteArray encryptedData = QByteArray(reinterpret_cast(cipherText.get()), cipherTextLength); + + return encryptedData; + + } catch (std::exception& exception) { + QSimpleCrypto::QAead::error.setError(1, exception.what()); + return QByteArray(); + } catch (...) { + QSimpleCrypto::QAead::error.setError(2, "Unknown error!"); + return QByteArray(); + } + + return QByteArray(); +} + +/// +/// \brief QSimpleCrypto::QAEAD::decryptAesCcm - Function decrypts data with Ccm algorithm. +/// \param data - Data that will be decrypted. +/// \param key - AES key. +/// \param iv - Initialization vector. +/// \param tag - Authorization tag. +/// \param aad - Additional authenticated data. Must be nullptr, if not used. +/// \param cipher - Can be used with OpenSSL EVP_CIPHER (ccm) - 128, 192, 256. Example: EVP_aes_256_ccm(). +/// \return Returns decrypted data or "", if error happened. +/// +QByteArray QSimpleCrypto::QAead::decryptAesCcm(QByteArray data, QByteArray key, QByteArray iv, QByteArray* tag, QByteArray aad, const EVP_CIPHER* cipher) +{ + try { + /* Initialize EVP_CIPHER_CTX */ + std::unique_ptr decryptionCipher { EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free }; + if (decryptionCipher.get() == nullptr) { + throw std::runtime_error("Couldn't initialize \'decryptionCipher\'. EVP_CIPHER_CTX_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Set data length */ + int cipherTextLength = data.size(); + int plainTextLength = 0; + + /* Initialize plainText. Here decrypted data will be stored */ + std::unique_ptr plainText { new unsigned char[cipherTextLength]() }; + if (plainText == nullptr) { + throw std::runtime_error("Couldn't allocate memory for 'plaintext'."); + } + + /* Initialize decryption operation. */ + if (!EVP_DecryptInit_ex(decryptionCipher.get(), cipher, nullptr, reinterpret_cast(key.data()), reinterpret_cast(iv.data()))) { + throw std::runtime_error("Couldn't initialize decryption operation. EVP_DecryptInit_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Set IV length. Not necessary if this is 12 bytes (96 bits) */ + if (!EVP_CIPHER_CTX_ctrl(decryptionCipher.get(), EVP_CTRL_CCM_SET_IVLEN, iv.length(), nullptr)) { + throw std::runtime_error("Couldn't set IV length. EVP_CIPHER_CTX_ctrl(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Set expected tag value. Works in OpenSSL 1.0.1d and later */ + if (!EVP_CIPHER_CTX_ctrl(decryptionCipher.get(), EVP_CTRL_CCM_SET_TAG, tag->length(), reinterpret_cast(tag->data()))) { + throw std::runtime_error("Coldn't set tag. EVP_CIPHER_CTX_ctrl(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Check if aad need to be used */ + if (aad.length() > 0) { + /* Provide the total ciphertext length */ + if (!EVP_DecryptUpdate(decryptionCipher.get(), nullptr, &plainTextLength, nullptr, cipherTextLength)) { + throw std::runtime_error("Couldn't provide total plaintext length. EVP_DecryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Provide any AAD data. This can be called zero or more times as required */ + if (!EVP_DecryptUpdate(decryptionCipher.get(), nullptr, &plainTextLength, reinterpret_cast(aad.data()), aad.length())) { + throw std::runtime_error("Couldn't provide aad data. EVP_DecryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + } + + /* + * Provide the message to be decrypted, and obtain the plaintext output. + * EVP_DecryptUpdate can be called multiple times if necessary + */ + if (!EVP_DecryptUpdate(decryptionCipher.get(), plainText.get(), &plainTextLength, reinterpret_cast(data.data()), cipherTextLength)) { + throw std::runtime_error("Couldn't provide message to be decrypted. EVP_DecryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* + * Finalize the decryption. A positive return value indicates success, + * anything else is a failure - the plaintext is not trustworthy. + */ + if (!EVP_DecryptFinal_ex(decryptionCipher.get(), plainText.get(), &cipherTextLength)) { + throw std::runtime_error("Couldn't finalize decryption. EVP_DecryptFinal_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Finilize data to be readable with qt */ + QByteArray decryptedData = QByteArray(reinterpret_cast(plainText.get()), plainTextLength); + + return decryptedData; + + } catch (std::exception& exception) { + QSimpleCrypto::QAead::error.setError(1, exception.what()); + return QByteArray(); + } catch (...) { + QSimpleCrypto::QAead::error.setError(2, "Unknown error!"); + return QByteArray(); + } + + return QByteArray(); +} diff --git a/client/3rd/QSimpleCrypto/sources/QBlockCipher.cpp b/client/3rd/QSimpleCrypto/sources/QBlockCipher.cpp new file mode 100644 index 000000000..c01b9a2f8 --- /dev/null +++ b/client/3rd/QSimpleCrypto/sources/QBlockCipher.cpp @@ -0,0 +1,184 @@ +/** + * Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution +**/ + +#include "include/QBlockCipher.h" + +QSimpleCrypto::QBlockCipher::QBlockCipher() +{ +} + +/// +/// \brief QSimpleCrypto::QBlockCipher::generateRandomBytes - Function generates random bytes by size. +/// \param size - Size of generated bytes. +/// \return Returns random bytes. +/// +QByteArray QSimpleCrypto::QBlockCipher::generateRandomBytes(const int& size) +{ + unsigned char arr[sizeof(size)]; + RAND_bytes(arr, sizeof(size)); + + QByteArray buffer = QByteArray(reinterpret_cast(arr), size); + return buffer; +} + +/// +/// \brief QSimpleCrypto::QBlockCipher::encryptAesBlockCipher - Function encrypts data with Aes Block Cipher algorithm. +/// \param data - Data that will be encrypted. +/// \param key - AES key. +/// \param iv - Initialization vector. +/// \param password - Encryption password. +/// \param salt - Random delta. +/// \param rounds - Transformation rounds. +/// \param chiper - Can be used with OpenSSL EVP_CIPHER (ecb, cbc, cfb, ofb, ctr) - 128, 192, 256. Example: EVP_aes_256_cbc(). +/// \param md - Hash algroitm (OpenSSL EVP_MD). Example: EVP_sha512(). +/// \return Returns decrypted data or "", if error happened. +/// +QByteArray QSimpleCrypto::QBlockCipher::encryptAesBlockCipher(QByteArray data, QByteArray key, + QByteArray iv, + const int& rounds, const EVP_CIPHER* cipher, const EVP_MD* md) +{ + try { + /* Initialize EVP_CIPHER_CTX */ + std::unique_ptr encryptionCipher { EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free }; + if (encryptionCipher == nullptr) { + throw std::runtime_error("Couldn't initialize \'encryptionCipher\'. EVP_CIPHER_CTX_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Reinterpret values for multi use */ + unsigned char* m_key = reinterpret_cast(key.data()); + unsigned char* m_iv = reinterpret_cast(iv.data()); + + /* Set data length */ + int cipherTextLength(data.size() + AES_BLOCK_SIZE); + int finalLength = 0; + + /* Initialize cipcherText. Here encrypted data will be stored */ + std::unique_ptr cipherText { new unsigned char[cipherTextLength]() }; + if (cipherText == nullptr) { + throw std::runtime_error("Couldn't allocate memory for 'cipherText'."); + } + + // Bug here +// /* Start encryption with password based encryption routine */ +// if (!EVP_BytesToKey(cipher, md, reinterpret_cast(salt.data()), reinterpret_cast(password.data()), password.length(), rounds, m_key, m_iv)) { +// throw std::runtime_error("Couldn't start encryption routine. EVP_BytesToKey(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); +// } + + /* Initialize encryption operation. */ + if (!EVP_EncryptInit_ex(encryptionCipher.get(), cipher, nullptr, m_key, m_iv)) { + throw std::runtime_error("Couldn't initialize encryption operation. EVP_EncryptInit_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* + * Provide the message to be encrypted, and obtain the encrypted output. + * EVP_EncryptUpdate can be called multiple times if necessary + */ + if (!EVP_EncryptUpdate(encryptionCipher.get(), cipherText.get(), &cipherTextLength, reinterpret_cast(data.data()), data.size())) { + throw std::runtime_error("Couldn't provide message to be encrypted. EVP_EncryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Finalize the encryption. Normally ciphertext bytes may be written at this stage */ + if (!EVP_EncryptFinal(encryptionCipher.get(), cipherText.get() + cipherTextLength, &finalLength)) { + throw std::runtime_error("Couldn't finalize encryption. EVP_EncryptFinal(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Finilize data to be readable with qt */ + QByteArray encryptedData = QByteArray(reinterpret_cast(cipherText.get()), cipherTextLength + finalLength); + + return encryptedData; + + } catch (std::exception& exception) { + QSimpleCrypto::QBlockCipher::error.setError(1, exception.what()); + return QByteArray(); + } catch (...) { + QSimpleCrypto::QBlockCipher::error.setError(2, "Unknown error!"); + return QByteArray(); + } + + return QByteArray(); +} + +/// +/// \brief QSimpleCrypto::QBlockCipher::encryptAesBlockCipher - Function decrypts data with Aes Block Cipher algorithm. +/// \param data - Data that will be decrypted. +/// \param key - AES key. +/// \param iv - Initialization vector. +/// \param password - Decryption password. +/// \param salt - Random delta. +/// \param rounds - Transformation rounds. +/// \param chiper - Can be used with OpenSSL EVP_CIPHER (ecb, cbc, cfb, ofb, ctr) - 128, 192, 256. Example: EVP_aes_256_cbc(). +/// \param md - Hash algroitm (OpenSSL EVP_MD). Example: EVP_sha512(). +/// \return Returns decrypted data or "", if error happened. +/// +QByteArray QSimpleCrypto::QBlockCipher::decryptAesBlockCipher(QByteArray data, QByteArray key, + QByteArray iv, + const int& rounds, const EVP_CIPHER* cipher, const EVP_MD* md) +{ + try { + /* Initialize EVP_CIPHER_CTX */ + std::unique_ptr decryptionCipher { EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free }; + if (decryptionCipher == nullptr) { + throw std::runtime_error("Couldn't initialize \'decryptionCipher\'. EVP_CIPHER_CTX_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Reinterpret values for multi use */ + unsigned char* m_key = reinterpret_cast(key.data()); + unsigned char* m_iv = reinterpret_cast(iv.data()); + + /* Set data length */ + int plainTextLength(data.size()); + int finalLength = 0; + + /* Initialize plainText. Here decrypted data will be stored */ + std::unique_ptr plainText { new unsigned char[plainTextLength + AES_BLOCK_SIZE]() }; + if (plainText == nullptr) { + throw std::runtime_error("Couldn't allocate memory for \'plainText\'. EVP_CIPHER_CTX_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + // Bug here +// /* Start encryption with password based encryption routine */ +// if (!EVP_BytesToKey(cipher, md, reinterpret_cast(salt.data()), reinterpret_cast(password.data()), password.length(), rounds, m_key, m_iv)) { +// throw std::runtime_error("Couldn't start decryption routine. EVP_BytesToKey(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); +// } + + /* Initialize decryption operation. */ + if (!EVP_DecryptInit_ex(decryptionCipher.get(), cipher, nullptr, m_key, m_iv)) { + throw std::runtime_error("Couldn't initialize decryption operation. EVP_DecryptInit_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* + * Provide the message to be decrypted, and obtain the plaintext output. + * EVP_DecryptUpdate can be called multiple times if necessary + */ + if (!EVP_DecryptUpdate(decryptionCipher.get(), plainText.get(), &plainTextLength, reinterpret_cast(data.data()), data.size())) { + throw std::runtime_error("Couldn't provide message to be decrypted. EVP_DecryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* + * Finalize the decryption. A positive return value indicates success, + * anything else is a failure - the plaintext is not trustworthy. + */ + if (!EVP_DecryptFinal(decryptionCipher.get(), plainText.get() + plainTextLength, &finalLength)) { + throw std::runtime_error("Couldn't finalize decryption. EVP_DecryptFinal. Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Finilize data to be readable with qt */ + QByteArray decryptedData = QByteArray(reinterpret_cast(plainText.get()), plainTextLength + finalLength); + + return decryptedData; + + } catch (std::exception& exception) { + QSimpleCrypto::QBlockCipher::error.setError(1, exception.what()); + return QByteArray(exception.what()); + } catch (...) { + QSimpleCrypto::QBlockCipher::error.setError(2, "Unknown error!"); + return QByteArray(); + } + + return QByteArray(); +} diff --git a/client/3rd/QSimpleCrypto/sources/QCryptoError.cpp b/client/3rd/QSimpleCrypto/sources/QCryptoError.cpp new file mode 100644 index 000000000..234f55d73 --- /dev/null +++ b/client/3rd/QSimpleCrypto/sources/QCryptoError.cpp @@ -0,0 +1,6 @@ +#include "include/QCryptoError.h" + +QSimpleCrypto::QCryptoError::QCryptoError(QObject* parent) + : QObject(parent) +{ +} diff --git a/client/3rd/QSimpleCrypto/sources/QRsa.cpp b/client/3rd/QSimpleCrypto/sources/QRsa.cpp new file mode 100644 index 000000000..544d67464 --- /dev/null +++ b/client/3rd/QSimpleCrypto/sources/QRsa.cpp @@ -0,0 +1,274 @@ +/** + * Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution +**/ + +#include "include/QRsa.h" + +QSimpleCrypto::QRsa::QRsa() +{ +} + +/// +/// \brief QSimpleCrypto::QRSA::generateRsaKeys - Function generate Rsa Keys and returns them in OpenSSL structure. +/// \param bits - RSA key size. +/// \param rsaBigNumber - The exponent is an odd number, typically 3, 17 or 65537. +/// \return Returns 'OpenSSL RSA structure' or 'nullptr', if error happened. Returned value must be cleaned up with 'RSA_free()' to avoid memory leak. +/// +RSA* QSimpleCrypto::QRsa::generateRsaKeys(const int& bits, const int& rsaBigNumber) +{ + try { + /* Initialize big number */ + std::unique_ptr bigNumber { BN_new(), BN_free }; + if (bigNumber == nullptr) { + throw std::runtime_error("Couldn't initialize \'bigNumber\'. BN_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + return nullptr; + } + + /* Set big number */ + if (!BN_set_word(bigNumber.get(), rsaBigNumber)) { + throw std::runtime_error("Couldn't set bigNumber. BN_set_word(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Initialize RSA */ + RSA* rsa = nullptr; + if (!(rsa = RSA_new())) { + throw std::runtime_error("Couldn't initialize x509. X509_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Generate key pair and store it in RSA */ + if (!RSA_generate_key_ex(rsa, bits, bigNumber.get(), nullptr)) { + throw std::runtime_error("Couldn't generate RSA. RSA_generate_key_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + return rsa; + } catch (std::exception& exception) { + QSimpleCrypto::QRsa::error.setError(1, exception.what()); + return nullptr; + } catch (...) { + QSimpleCrypto::QRsa::error.setError(2, "Unknown error!"); + return nullptr; + } +} + +/// +/// \brief QSimpleCrypto::QRSA::savePublicKey - Saves to file RSA public key. +/// \param rsa - OpenSSL RSA structure. +/// \param publicKeyFileName - Public key file name. +/// +void QSimpleCrypto::QRsa::savePublicKey(RSA* rsa, const QByteArray& publicKeyFileName) +{ + try { + /* Initialize BIO */ + std::unique_ptr bioPublicKey { BIO_new_file(publicKeyFileName.data(), "w+"), BIO_free_all }; + if (bioPublicKey == nullptr) { + throw std::runtime_error("Couldn't initialize \'bioPublicKey\'. BIO_new_file(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Write public key on file */ + if (!PEM_write_bio_RSA_PUBKEY(bioPublicKey.get(), rsa)) { + throw std::runtime_error("Couldn't save public key. PEM_write_bio_RSAPublicKey(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + } catch (std::exception& exception) { + QSimpleCrypto::QRsa::error.setError(1, exception.what()); + return; + } catch (...) { + QSimpleCrypto::QRsa::error.setError(2, "Unknown error!"); + return; + } +} + +/// +/// \brief QSimpleCrypto::QRSA::savePrivateKey - Saves to file RSA private key. +/// \param rsa - OpenSSL RSA structure. +/// \param privateKeyFileName - Private key file name. +/// \param password - Private key password. +/// \param cipher - Can be used with 'OpenSSL EVP_CIPHER' (ecb, cbc, cfb, ofb, ctr) - 128, 192, 256. Example: EVP_aes_256_cbc(). +/// +void QSimpleCrypto::QRsa::savePrivateKey(RSA* rsa, const QByteArray& privateKeyFileName, QByteArray password, const EVP_CIPHER* cipher) +{ + try { + /* Initialize BIO */ + std::unique_ptr bioPrivateKey { BIO_new_file(privateKeyFileName.data(), "w+"), BIO_free_all }; + if (bioPrivateKey == nullptr) { + throw std::runtime_error("Couldn't initialize bioPrivateKey. BIO_new_file(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Write private key to file */ + if (!PEM_write_bio_RSAPrivateKey(bioPrivateKey.get(), rsa, cipher, reinterpret_cast(password.data()), password.size(), nullptr, nullptr)) { + throw std::runtime_error("Couldn't save private key. PEM_write_bio_RSAPrivateKey(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + } catch (std::exception& exception) { + QSimpleCrypto::QRsa::error.setError(1, exception.what()); + return; + } catch (...) { + QSimpleCrypto::QRsa::error.setError(2, "Unknown error!"); + return; + } +} + +/// +/// \brief QSimpleCrypto::QRSA::getPublicKeyFromFile - Gets RSA public key from a file. +/// \param filePath - File path to public key file. +/// \return Returns 'OpenSSL EVP_PKEY structure' or 'nullptr', if error happened. Returned value must be cleaned up with 'EVP_PKEY_free()' to avoid memory leak. +/// +EVP_PKEY* QSimpleCrypto::QRsa::getPublicKeyFromFile(const QByteArray& filePath) +{ + try { + /* Initialize BIO */ + std::unique_ptr bioPublicKey { BIO_new_file(filePath.data(), "r"), BIO_free_all }; + if (bioPublicKey == nullptr) { + throw std::runtime_error("Couldn't initialize bioPublicKey. BIO_new_file(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Initialize EVP_PKEY */ + EVP_PKEY* keyStore = nullptr; + if (!(keyStore = EVP_PKEY_new())) { + throw std::runtime_error("Couldn't initialize keyStore. EVP_PKEY_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Write private key to file */ + if (!PEM_read_bio_PUBKEY(bioPublicKey.get(), &keyStore, nullptr, nullptr)) { + throw std::runtime_error("Couldn't read private key. PEM_read_bio_PrivateKey(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + return keyStore; + + } catch (std::exception& exception) { + QSimpleCrypto::QRsa::error.setError(1, exception.what()); + return nullptr; + } catch (...) { + QSimpleCrypto::QRsa::error.setError(2, "Unknown error!"); + return nullptr; + } +} + +/// +/// \brief QSimpleCrypto::QRSA::getPrivateKeyFromFile - Gets RSA private key from a file. +/// \param filePath - File path to private key file. +/// \param password - Private key password. +/// \return - Returns 'OpenSSL EVP_PKEY structure' or 'nullptr', if error happened. Returned value must be cleaned up with 'EVP_PKEY_free()' to avoid memory leak. +/// +EVP_PKEY* QSimpleCrypto::QRsa::getPrivateKeyFromFile(const QByteArray& filePath, const QByteArray& password) +{ + try { + /* Initialize BIO */ + std::unique_ptr bioPrivateKey { BIO_new_file(filePath.data(), "r"), BIO_free_all }; + if (bioPrivateKey == nullptr) { + throw std::runtime_error("Couldn't initialize bioPrivateKey. BIO_new_file(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Initialize EVP_PKEY */ + EVP_PKEY* keyStore = nullptr; + if (!(keyStore = EVP_PKEY_new())) { + throw std::runtime_error("Couldn't initialize keyStore. EVP_PKEY_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Write private key to file */ + if (!PEM_read_bio_PrivateKey(bioPrivateKey.get(), &keyStore, nullptr, (void*)password.data())) { + throw std::runtime_error("Couldn't read private key. PEM_read_bio_PrivateKey(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + return keyStore; + + } catch (std::exception& exception) { + QSimpleCrypto::QRsa::error.setError(1, exception.what()); + return nullptr; + } catch (...) { + QSimpleCrypto::QRsa::error.setError(2, "Unknown error!"); + return nullptr; + } +} + +/// +/// \brief QSimpleCrypto::QRSA::encrypt - Encrypt data with RSA algorithm. +/// \param plaintext - Text that must be encrypted. +/// \param rsa - OpenSSL RSA structure. +/// \param encryptType - Public or private encrypt type. (PUBLIC_ENCRYPT, PRIVATE_ENCRYPT). +/// \param padding - OpenSSL RSA padding can be used with: 'RSA_PKCS1_PADDING', 'RSA_NO_PADDING' and etc. +/// \return Returns encrypted data or "", if error happened. +/// +QByteArray QSimpleCrypto::QRsa::encrypt(QByteArray plainText, RSA* rsa, const int& encryptType, const int& padding) +{ + try { + /* Initialize array. Here encrypted data will be saved */ + std::unique_ptr cipherText { new unsigned char[RSA_size(rsa)]() }; + if (cipherText == nullptr) { + throw std::runtime_error("Couldn't allocate memory for 'cipherText'."); + } + + /* Result of encryption operation */ + short int result = 0; + + /* Execute encryption operation */ + if (encryptType == PublicDecrypt) { + result = RSA_public_encrypt(plainText.size(), reinterpret_cast(plainText.data()), cipherText.get(), rsa, padding); + } else if (encryptType == PrivateDecrypt) { + result = RSA_private_encrypt(plainText.size(), reinterpret_cast(plainText.data()), cipherText.get(), rsa, padding); + } + + /* Check for result */ + if (result <= -1) { + throw std::runtime_error("Couldn't encrypt data. Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Get encrypted data */ + const QByteArray& encryptedData = QByteArray(reinterpret_cast(cipherText.get()), RSA_size(rsa)); + + return encryptedData; + } catch (std::exception& exception) { + QSimpleCrypto::QRsa::error.setError(1, exception.what()); + return ""; + } catch (...) { + QSimpleCrypto::QRsa::error.setError(2, "Unknown error!"); + return ""; + } +} + +/// +/// \brief QSimpleCrypto::QRSA::decrypt - Decrypt data with RSA algorithm. +/// \param cipherText - Text that must be decrypted. +/// \param rsa - OpenSSL RSA structure. +/// \param decryptType - Public or private type. (PUBLIC_DECRYPT, PRIVATE_DECRYPT). +/// \param padding - RSA padding can be used with: 'RSA_PKCS1_PADDING', 'RSA_NO_PADDING' and etc. +/// \return - Returns decrypted data or "", if error happened. +/// +QByteArray QSimpleCrypto::QRsa::decrypt(QByteArray cipherText, RSA* rsa, const int& decryptType, const int& padding) +{ + try { + /* Initialize array. Here decrypted data will be saved */ + std::unique_ptr plainText { new unsigned char[cipherText.size()]() }; + if (plainText == nullptr) { + throw std::runtime_error("Couldn't allocate memory for 'plainText'."); + } + + /* Result of decryption operation */ + short int result = 0; + + /* Execute decryption operation */ + if (decryptType == PublicDecrypt) { + result = RSA_public_decrypt(RSA_size(rsa), reinterpret_cast(cipherText.data()), plainText.get(), rsa, padding); + } else if (decryptType == PrivateDecrypt) { + result = RSA_private_decrypt(RSA_size(rsa), reinterpret_cast(cipherText.data()), plainText.get(), rsa, padding); + } + + /* Check for result */ + if (result <= -1) { + throw std::runtime_error("Couldn't decrypt data. Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Get decrypted data */ + const QByteArray& decryptedData = QByteArray(reinterpret_cast(plainText.get())); + + return decryptedData; + } catch (std::exception& exception) { + QSimpleCrypto::QRsa::error.setError(1, exception.what()); + return ""; + } catch (...) { + QSimpleCrypto::QRsa::error.setError(2, "Unknown error!"); + return ""; + } +} diff --git a/client/3rd/QSimpleCrypto/sources/QX509.cpp b/client/3rd/QSimpleCrypto/sources/QX509.cpp new file mode 100644 index 000000000..8666347db --- /dev/null +++ b/client/3rd/QSimpleCrypto/sources/QX509.cpp @@ -0,0 +1,234 @@ +/** + * Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution +**/ + +#include "include/QX509.h" + +QSimpleCrypto::QX509::QX509() +{ +} + +/// +/// \brief QSimpleCrypto::QX509::loadCertificateFromFile - Function load X509 from file and returns OpenSSL structure. +/// \param fileName - File path to certificate. +/// \return Returns OpenSSL X509 structure or nullptr, if error happened. Returned value must be cleaned up with 'X509_free' to avoid memory leak. +/// +X509* QSimpleCrypto::QX509::loadCertificateFromFile(const QByteArray& fileName) +{ + try { + /* Initialize X509 */ + X509* x509 = nullptr; + if (!(x509 = X509_new())) { + throw std::runtime_error("Couldn't initialize X509. X509_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Initialize BIO */ + std::unique_ptr certFile { BIO_new_file(fileName.data(), "r+"), BIO_free_all }; + if (certFile == nullptr) { + throw std::runtime_error("Couldn't initialize certFile. BIO_new_file(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Read file */ + if (!PEM_read_bio_X509(certFile.get(), &x509, nullptr, nullptr)) { + throw std::runtime_error("Couldn't read certificate file from disk. PEM_read_bio_X509(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + return x509; + } catch (std::exception& exception) { + QSimpleCrypto::QX509::error.setError(1, exception.what()); + return nullptr; + } catch (...) { + QSimpleCrypto::QX509::error.setError(2, "Unknown error!"); + return nullptr; + } +} + +/// +/// \brief QSimpleCrypto::QX509::signCertificate - Function signs X509 certificate and returns signed X509 OpenSSL structure. +/// \param endCertificate - Certificate that will be signed +/// \param caCertificate - CA certificate that will sign end certificate +/// \param caPrivateKey - CA certificate private key +/// \param fileName - With that name certificate will be saved. Leave "", if don't need to save it +/// \return Returns OpenSSL X509 structure or nullptr, if error happened. +/// +X509* QSimpleCrypto::QX509::signCertificate(X509* endCertificate, X509* caCertificate, EVP_PKEY* caPrivateKey, const QByteArray& fileName) +{ + try { + /* Set issuer to CA's subject. */ + if (!X509_set_issuer_name(endCertificate, X509_get_subject_name(caCertificate))) { + throw std::runtime_error("Couldn't set issuer name for X509. X509_set_issuer_name(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Sign the certificate with key. */ + if (!X509_sign(endCertificate, caPrivateKey, EVP_sha256())) { + throw std::runtime_error("Couldn't sign X509. X509_sign(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Write certificate file on disk. If needed */ + if (!fileName.isEmpty()) { + /* Initialize BIO */ + std::unique_ptr certFile { BIO_new_file(fileName.data(), "w+"), BIO_free_all }; + if (certFile == nullptr) { + throw std::runtime_error("Couldn't initialize certFile. BIO_new_file(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Write file on disk */ + if (!PEM_write_bio_X509(certFile.get(), endCertificate)) { + throw std::runtime_error("Couldn't write certificate file on disk. PEM_write_bio_X509(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + } + + return endCertificate; + } catch (std::exception& exception) { + QSimpleCrypto::QX509::error.setError(1, exception.what()); + return nullptr; + } catch (...) { + QSimpleCrypto::QX509::error.setError(2, "Unknown error!"); + return nullptr; + } +} + +/// +/// \brief QSimpleCrypto::QX509::verifyCertificate - Function verifies X509 certificate and returns verified X509 OpenSSL structure. +/// \param x509 - OpenSSL X509. That certificate will be verified. +/// \param store - Trusted certificate must be added to X509_Store with 'addCertificateToStore(X509_STORE* ctx, X509* x509)'. +/// \return Returns OpenSSL X509 structure or nullptr, if error happened +/// +X509* QSimpleCrypto::QX509::verifyCertificate(X509* x509, X509_STORE* store) +{ + try { + /* Initialize X509_STORE_CTX */ + std::unique_ptr ctx { X509_STORE_CTX_new(), X509_STORE_CTX_free }; + if (ctx == nullptr) { + throw std::runtime_error("Couldn't initialize keyStore. EVP_PKEY_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Set up CTX for a subsequent verification operation */ + if (!X509_STORE_CTX_init(ctx.get(), store, x509, nullptr)) { + throw std::runtime_error("Couldn't initialize X509_STORE_CTX. X509_STORE_CTX_init(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Verify X509 */ + if (!X509_verify_cert(ctx.get())) { + throw std::runtime_error("Couldn't verify cert. X509_verify_cert(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + return x509; + } catch (std::exception& exception) { + QSimpleCrypto::QX509::error.setError(1, exception.what()); + return nullptr; + } catch (...) { + QSimpleCrypto::QX509::error.setError(2, "Unknown error!"); + return nullptr; + } +} + +/// +/// \brief QSimpleCrypto::QX509::generateSelfSignedCertificate - Function generatesand returns self signed X509. +/// \param rsa - OpenSSL RSA. +/// \param additionalData - Certificate information. +/// \param certificateFileName - With that name certificate will be saved. Leave "", if don't need to save it. +/// \param md - OpenSSL EVP_MD structure. Example: EVP_sha512(). +/// \param serialNumber - X509 certificate serial number. +/// \param version - X509 certificate version. +/// \param notBefore - X509 start date. +/// \param notAfter - X509 end date. +/// \return Returns OpenSSL X509 structure or nullptr, if error happened. Returned value must be cleaned up with 'X509_free' to avoid memory leak. +/// +X509* QSimpleCrypto::QX509::generateSelfSignedCertificate(const RSA* rsa, const QMap& additionalData, + const QByteArray& certificateFileName, const EVP_MD* md, + const long& serialNumber, const long& version, + const long& notBefore, const long& notAfter) +{ + try { + /* Initialize X509 */ + X509* x509 = nullptr; + if (!(x509 = X509_new())) { + throw std::runtime_error("Couldn't initialize X509. X509_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Initialize EVP_PKEY */ + std::unique_ptr keyStore { EVP_PKEY_new(), EVP_PKEY_free }; + if (keyStore == nullptr) { + throw std::runtime_error("Couldn't initialize keyStore. EVP_PKEY_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Sign rsa key */ + if (!EVP_PKEY_assign_RSA(keyStore.get(), rsa)) { + throw std::runtime_error("Couldn't assign rsa. EVP_PKEY_assign_RSA(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Set certificate serial number. */ + if (!ASN1_INTEGER_set(X509_get_serialNumber(x509), serialNumber)) { + throw std::runtime_error("Couldn't set serial number. ASN1_INTEGER_set(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Set certificate version */ + if (!X509_set_version(x509, version)) { + throw std::runtime_error("Couldn't set version. X509_set_version(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Set certificate creation and expiration date */ + X509_gmtime_adj(X509_get_notBefore(x509), notBefore); + X509_gmtime_adj(X509_get_notAfter(x509), notAfter); + + /* Set certificate public key */ + if (!X509_set_pubkey(x509, keyStore.get())) { + throw std::runtime_error("Couldn't set public key. X509_set_pubkey(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Initialize X509_NAME */ + X509_NAME* x509Name = X509_get_subject_name(x509); + if (x509Name == nullptr) { + throw std::runtime_error("Couldn't initialize X509_NAME. X509_NAME(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Add additional data to certificate */ + QMapIterator certificateInformationList(additionalData); + while (certificateInformationList.hasNext()) { + /* Read next item in list */ + certificateInformationList.next(); + + /* Set additional data */ + if (!X509_NAME_add_entry_by_txt(x509Name, certificateInformationList.key().data(), MBSTRING_UTF8, reinterpret_cast(certificateInformationList.value().data()), -1, -1, 0)) { + throw std::runtime_error("Couldn't set additional information. X509_NAME_add_entry_by_txt(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + } + + /* Set certificate info */ + if (!X509_set_issuer_name(x509, x509Name)) { + throw std::runtime_error("Couldn't set issuer name. X509_set_issuer_name(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Sign certificate */ + if (!X509_sign(x509, keyStore.get(), md)) { + throw std::runtime_error("Couldn't sign X509. X509_sign(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Write certificate file on disk. If needed */ + if (!certificateFileName.isEmpty()) { + /* Initialize BIO */ + std::unique_ptr certFile { BIO_new_file(certificateFileName.data(), "w+"), BIO_free_all }; + if (certFile == nullptr) { + throw std::runtime_error("Couldn't initialize certFile. BIO_new_file(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Write file on disk */ + if (!PEM_write_bio_X509(certFile.get(), x509)) { + throw std::runtime_error("Couldn't write certificate file on disk. PEM_write_bio_X509(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + } + + return x509; + } catch (std::exception& exception) { + QSimpleCrypto::QX509::error.setError(1, exception.what()); + return nullptr; + } catch (...) { + QSimpleCrypto::QX509::error.setError(2, "Unknown error!"); + return nullptr; + } +} diff --git a/client/3rd/QSimpleCrypto/sources/QX509Store.cpp b/client/3rd/QSimpleCrypto/sources/QX509Store.cpp new file mode 100644 index 000000000..bbbec1a84 --- /dev/null +++ b/client/3rd/QSimpleCrypto/sources/QX509Store.cpp @@ -0,0 +1,176 @@ +/** + * Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution +**/ + +#include "include/QX509Store.h" + +QSimpleCrypto::QX509Store::QX509Store() +{ +} + +/// +/// \brief QSimpleCrypto::QX509::addCertificateToStore +/// \param store - OpenSSL X509_STORE. +/// \param x509 - OpenSSL X509. +/// \return Returns 'true' on success and 'false', if error happened. +/// +bool QSimpleCrypto::QX509Store::addCertificateToStore(X509_STORE* store, X509* x509) +{ + if (!X509_STORE_add_cert(store, x509)) { + QSimpleCrypto::QX509Store::error.setError(1, "Couldn't add certificate to X509_STORE. X509_STORE_add_cert(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + return false; + } + + return true; +} + +/// +/// \brief QSimpleCrypto::QX509Store::addLookup +/// \param store - OpenSSL X509_STORE. +/// \param method - OpenSSL X509_LOOKUP_METHOD. Example: X509_LOOKUP_file. +/// \return Returns 'true' on success and 'false', if error happened. +/// +bool QSimpleCrypto::QX509Store::addLookup(X509_STORE* store, X509_LOOKUP_METHOD* method) +{ + if (!X509_STORE_add_lookup(store, method)) { + QSimpleCrypto::QX509Store::error.setError(1, "Couldn't add lookup to X509_STORE. X509_STORE_add_lookup(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + return false; + } + + return true; +} + +/// +/// \brief QSimpleCrypto::QX509Store::setCertificateDepth +/// \param store - OpenSSL X509_STORE. +/// \param depth - That is the maximum number of untrusted CA certificates that can appear in a chain. Example: 0. +/// \return Returns 'true' on success and 'false', if error happened. +/// +bool QSimpleCrypto::QX509Store::setDepth(X509_STORE* store, const int& depth) +{ + if (!X509_STORE_set_depth(store, depth)) { + QSimpleCrypto::QX509Store::error.setError(1, "Couldn't set depth for X509_STORE. X509_STORE_set_depth(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + return false; + } + + return true; +} + +/// +/// \brief QSimpleCrypto::QX509Store::setFlag +/// \param store - OpenSSL X509_STORE. +/// \param flag - The verification flags consists of zero or more of the following flags ored together. Example: X509_V_FLAG_CRL_CHECK. +/// \return Returns 'true' on success and 'false', if error happened. +/// +bool QSimpleCrypto::QX509Store::setFlag(X509_STORE* store, const unsigned long& flag) +{ + if (!X509_STORE_set_flags(store, flag)) { + QSimpleCrypto::QX509Store::error.setError(1, "Couldn't set flag for X509_STORE. X509_STORE_set_flags(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + return false; + } + + return true; +} + +/// +/// \brief QSimpleCrypto::QX509Store::setFlag +/// \param store - OpenSSL X509_STORE. +/// \param purpose - Verification purpose in param to purpose. Example: X509_PURPOSE_ANY. +/// \return Returns 'true' on success and 'false', if error happened. +/// +bool QSimpleCrypto::QX509Store::setPurpose(X509_STORE* store, const int& purpose) +{ + if (!X509_STORE_set_purpose(store, purpose)) { + QSimpleCrypto::QX509Store::error.setError(1, "Couldn't set purpose for X509_STORE. X509_STORE_set_purpose(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + return false; + } + + return true; +} + +/// +/// \brief QSimpleCrypto::QX509Store::setTrust +/// \param store - OpenSSL X509_STORE. +/// \param trust - Trust Level. Example: X509_TRUST_SSL_SERVER. +/// \return Returns 'true' on success and 'false', if error happened. +/// +bool QSimpleCrypto::QX509Store::setTrust(X509_STORE* store, const int& trust) +{ + if (!X509_STORE_set_trust(store, trust)) { + QSimpleCrypto::QX509Store::error.setError(1, "Couldn't set trust for X509_STORE. X509_STORE_set_trust(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + return false; + } + + return true; +} + +/// +/// \brief QSimpleCrypto::QX509Store::setDefaultPaths +/// \param store - OpenSSL X509_STORE. +/// \return Returns 'true' on success and 'false', if error happened. +/// +bool QSimpleCrypto::QX509Store::setDefaultPaths(X509_STORE* store) +{ + if (!X509_STORE_set_default_paths(store)) { + QSimpleCrypto::QX509Store::error.setError(1, "Couldn't set default paths for X509_STORE. X509_STORE_set_default_paths(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + return false; + } + + return true; +} + +/// +/// \brief QSimpleCrypto::QX509Store::loadLocations +/// \param store - OpenSSL X509_STORE. +/// \param fileName - File name. Example: "caCertificate.pem". +/// \param dirPath - Path to file. Example: "path/To/File". +/// \return Returns 'true' on success and 'false', if error happened. +/// +bool QSimpleCrypto::QX509Store::loadLocations(X509_STORE* store, const QByteArray& fileName, const QByteArray& dirPath) +{ + if (!X509_STORE_load_locations(store, fileName, dirPath)) { + QSimpleCrypto::QX509Store::error.setError(1, "Couldn't load locations for X509_STORE. X509_STORE_load_locations(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + return false; + } + + return true; +} + +/// +/// \brief QSimpleCrypto::QX509Store::loadLocations +/// \param store - OpenSSL X509_STORE. +/// \param file - Qt QFile that will be loaded. +/// \return Returns 'true' on success and 'false', if error happened. +/// +bool QSimpleCrypto::QX509Store::loadLocations(X509_STORE* store, const QFile& file) +{ + /* Initialize QFileInfo to read information about file */ + QFileInfo info(file); + + if (!X509_STORE_load_locations(store, info.fileName().toLocal8Bit(), info.absoluteDir().path().toLocal8Bit())) { + QSimpleCrypto::QX509Store::error.setError(1, "Couldn't load locations for X509_STORE. X509_STORE_load_locations(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + return false; + } + + return true; +} + +/// +/// \brief QSimpleCrypto::QX509Store::loadLocations +/// \param store - OpenSSL X509_STORE. +/// \param fileInfo - Qt QFileInfo. +/// \return Returns 'true' on success and 'false', if error happened. +/// +bool QSimpleCrypto::QX509Store::loadLocations(X509_STORE* store, const QFileInfo& fileInfo) +{ + if (!X509_STORE_load_locations(store, fileInfo.fileName().toLocal8Bit(), fileInfo.absoluteDir().path().toLocal8Bit())) { + QSimpleCrypto::QX509Store::error.setError(1, "Couldn't load locations for X509_STORE. X509_STORE_load_locations(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + return false; + } + + return true; +} diff --git a/client/client.pro b/client/client.pro index 9d2180f75..023f0e184 100644 --- a/client/client.pro +++ b/client/client.pro @@ -16,7 +16,9 @@ include("3rd/QtSsh/src/botan/botan.pri") !android:!ios:include("3rd/SingleApplication/singleapplication.pri") include ("3rd/SortFilterProxyModel/SortFilterProxyModel.pri") include("3rd/qzxing/src/QZXing-components.pri") +include("3rd/QSimpleCrypto/QSimpleCrypto.pri") +INCLUDEPATH += $$PWD/3rd/QSimpleCrypto/include INCLUDEPATH += $$PWD/3rd/OpenSSL/include DEPENDPATH += $$PWD/3rd/OpenSSL/include @@ -37,7 +39,6 @@ HEADERS += \ core/servercontroller.h \ debug.h \ defines.h \ - encryption_helper.h \ managementserver.h \ platforms/ios/MobileUtils.h \ platforms/linux/leakdetector.h \ @@ -96,7 +97,6 @@ SOURCES += \ core/server_defs.cpp \ core/servercontroller.cpp \ debug.cpp \ - encryption_helper.cpp \ main.cpp \ managementserver.cpp \ platforms/ios/MobileUtils.cpp \ @@ -169,7 +169,6 @@ win32 { -lshlwapi \ -liphlpapi \ -lws2_32 \ - -liphlpapi \ -lgdi32 diff --git a/client/encryption_helper.cpp b/client/encryption_helper.cpp deleted file mode 100644 index 6c1bffda8..000000000 --- a/client/encryption_helper.cpp +++ /dev/null @@ -1,143 +0,0 @@ -#include "encryption_helper.h" - -#include -#include -#include - -#include "openssl/evp.h" - -int gcm_encrypt(const char *plaintext, int plaintext_len, - const char *key, const char *iv, int iv_len, - char *ciphertext) -{ - return gcm_encrypt((uchar*)plaintext, plaintext_len, - (uchar*)key, (uchar*)iv, iv_len, - (uchar*)ciphertext); -} - -int gcm_decrypt(const char *ciphertext, int ciphertext_len, - const char *key, - const char *iv, int iv_len, - char *plaintext) -{ - return gcm_decrypt((uchar*)ciphertext, ciphertext_len, - (uchar*)key, (uchar*)iv, iv_len, - (uchar*)plaintext); -} - -void handleErrors() { - qDebug() << "handleErrors"; -} - -int generate_key_and_iv(unsigned char *iv, unsigned char *key) { -// unsigned char key[32]; -// unsigned char iv[16]; -// EVP_BytesToKey(EVP_aes_256_gcm(), EVP_md5(), -// NULL, -// key_file_buf, key_size, 1, // const unsigned char *data, int datal, int count, -// key, iv); - return 0; -} - -int gcm_encrypt(const unsigned char *plaintext, int plaintext_len, - const unsigned char *key, - const unsigned char *iv, int iv_len, - unsigned char *ciphertext) -{ - EVP_CIPHER_CTX *ctx; - int len; - int ciphertext_len; - - /* Create and initialise the context */ - if(!(ctx = EVP_CIPHER_CTX_new())) - handleErrors(); - - /* Initialise the encryption operation. */ - if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) - handleErrors(); - - /* - * Set IV length if default 12 bytes (96 bits) is not appropriate - */ - if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL)) - handleErrors(); - - /* Initialise key and IV */ - if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) - handleErrors(); - - /* - * Provide the message to be encrypted, and obtain the encrypted output. - * EVP_EncryptUpdate can be called multiple times if necessary - */ - if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) - handleErrors(); - ciphertext_len = len; - - /* - * Finalise the encryption. Normally ciphertext bytes may be written at - * this stage, but this does not occur in GCM mode - */ - if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) - handleErrors(); - ciphertext_len += len; - - /* Clean up */ - EVP_CIPHER_CTX_free(ctx); - - return ciphertext_len; -} - -int gcm_decrypt(const unsigned char *ciphertext, int ciphertext_len, - const unsigned char *key, - const unsigned char *iv, int iv_len, - unsigned char *plaintext) -{ - EVP_CIPHER_CTX *ctx; - int len; - int plaintext_len; - int ret; - - /* Create and initialise the context */ - if(!(ctx = EVP_CIPHER_CTX_new())) - handleErrors(); - - /* Initialise the decryption operation. */ - if(!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) - handleErrors(); - - /* Set IV length. Not necessary if this is 12 bytes (96 bits) */ - if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL)) - handleErrors(); - - /* Initialise key and IV */ - if(!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) - handleErrors(); - - /* - * Provide the message to be decrypted, and obtain the plaintext output. - * EVP_DecryptUpdate can be called multiple times if necessary - */ - if(!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len)) - handleErrors(); - plaintext_len = len; - - /* - * Finalise the decryption. A positive return value indicates success, - * anything else is a failure - the plaintext is not trustworthy. - */ - ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len); - - /* Clean up */ - EVP_CIPHER_CTX_free(ctx); - - if(ret > 0) { - /* Success */ - plaintext_len += len; - return plaintext_len; - } else { - /* Verify failed */ - return -1; - } -} - diff --git a/client/encryption_helper.h b/client/encryption_helper.h deleted file mode 100644 index ba9214087..000000000 --- a/client/encryption_helper.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef ENCRYPTION_HELPER_H -#define ENCRYPTION_HELPER_H - -#include -#include - - - -int gcm_encrypt(const char *plaintext, int plaintext_len, - const char *key, - const char *iv, int iv_len, - char *ciphertext); - -int gcm_decrypt(const char *ciphertext, int ciphertext_len, - const char *key, - const char *iv, int iv_len, - char *plaintext); - - -int gcm_encrypt(const unsigned char *plaintext, int plaintext_len, - const unsigned char *key, - const unsigned char *iv, int iv_len, - unsigned char *ciphertext); - -int gcm_decrypt(const unsigned char *ciphertext, int ciphertext_len, - const unsigned char *key, - const unsigned char *iv, int iv_len, - unsigned char *plaintext); - - -#endif // ENCRYPTION_HELPER_H diff --git a/client/secure_qsettings.cpp b/client/secure_qsettings.cpp index 0b2f138ea..46d490adc 100644 --- a/client/secure_qsettings.cpp +++ b/client/secure_qsettings.cpp @@ -1,35 +1,37 @@ #include "secure_qsettings.h" -#include "encryption_helper.h" #include "platforms/ios/MobileUtils.h" #include #include +#include "utils.h" +#include +#include "QAead.h" +#include "QBlockCipher.h" SecureQSettings::SecureQSettings(const QString &organization, const QString &application, QObject *parent) : QObject{parent}, - m_setting(organization, application, parent), + m_settings(organization, application, parent), encryptedKeys({"Servers/serversList"}) { + qDebug() << "SecureQSettings::SecureQSettings CTOR"; // load keys from system key storage #ifdef Q_OS_IOS - key = QByteArray::fromBase64(MobileUtils::readFromKeychain(settingsKeyTag).toUtf8()); - iv = QByteArray::fromBase64(MobileUtils::readFromKeychain(settingsIvTag).toUtf8()); + m_key = QByteArray::fromBase64(MobileUtils::readFromKeychain(settingsKeyTag).toUtf8()); + m_iv = QByteArray::fromBase64(MobileUtils::readFromKeychain(settingsIvTag).toUtf8()); #endif - key = "12345qwerty00000"; - iv = "000000000000000"; - bool encrypted = m_setting.value("Conf/encrypted").toBool(); + bool encrypted = m_settings.value("Conf/encrypted").toBool(); - // convert settings to encrypted + // convert settings to encrypted for if updated to >= 2.1.0 if (encryptionRequired() && ! encrypted) { - for (const QString &key : m_setting.allKeys()) { + for (const QString &key : m_settings.allKeys()) { if (encryptedKeys.contains(key)) { const QVariant &val = value(key); setValue(key, val); } } - m_setting.setValue("Conf/encrypted", true); - m_setting.sync(); + m_settings.setValue("Conf/encrypted", true); + m_settings.sync(); } } @@ -39,18 +41,36 @@ QVariant SecureQSettings::value(const QString &key, const QVariant &defaultValue return m_cache.value(key); } + if (!m_settings.contains(key)) return defaultValue; + QVariant retVal; - if (encryptionRequired() && encryptedKeys.contains(key)) { - if (!m_setting.contains(key)) return defaultValue; - QByteArray encryptedValue = m_setting.value(key).toByteArray(); - QByteArray decryptedValue = decryptText(encryptedValue); + // check if value is not encrypted, v. < 2.0.x + retVal = m_settings.value(key); + if (retVal.isValid()) { + if (retVal.userType() == QVariant::ByteArray && + retVal.toByteArray().mid(0, magicString.size()) == magicString) { - QDataStream ds(&decryptedValue, QIODevice::ReadOnly); - ds >> retVal; + if (m_key.isEmpty() || m_iv.isEmpty()) { + qCritical() << "SecureQSettings::setValue Decryption requested, but key is empty"; + return {}; + } + + QByteArray encryptedValue = retVal.toByteArray().mid(magicString.size()); + + QByteArray decryptedValue = decryptText(encryptedValue); + QDataStream ds(&decryptedValue, QIODevice::ReadOnly); + + ds >> retVal; + + if (!retVal.isValid()) { + qWarning() << "SecureQSettings::value settings decryption failed"; + } + } } else { - retVal = m_setting.value(key, defaultValue); + qWarning() << "SecureQSettings::value invalid QVariant value"; + retVal = QVariant(); } m_cache.insert(key, retVal); @@ -61,17 +81,24 @@ QVariant SecureQSettings::value(const QString &key, const QVariant &defaultValue void SecureQSettings::setValue(const QString &key, const QVariant &value) { if (encryptionRequired() && encryptedKeys.contains(key)) { - QByteArray decryptedValue; - { - QDataStream ds(&decryptedValue, QIODevice::WriteOnly); - ds << value; + if (!m_key.isEmpty() && !m_iv.isEmpty()) { + QByteArray decryptedValue; + { + QDataStream ds(&decryptedValue, QIODevice::WriteOnly); + ds << value; + } + + QByteArray encryptedValue = encryptText(decryptedValue); + m_settings.setValue(key, magicString + encryptedValue); + } + else { + qCritical() << "SecureQSettings::setValue Encryption required, but key is empty"; + return; } - QByteArray encryptedValue = encryptText(decryptedValue); - m_setting.setValue(key, encryptedValue); } else { - m_setting.setValue(key, value); + m_settings.setValue(key, value); } m_cache.insert(key, value); @@ -80,7 +107,7 @@ void SecureQSettings::setValue(const QString &key, const QVariant &value) void SecureQSettings::remove(const QString &key) { - m_setting.remove(key); + m_settings.remove(key); m_cache.remove(key); sync(); @@ -88,13 +115,13 @@ void SecureQSettings::remove(const QString &key) void SecureQSettings::sync() { - m_setting.sync(); + m_settings.sync(); } QByteArray SecureQSettings::backupAppConfig() const { QMap cfg; - for (const QString &key : m_setting.allKeys()) { + for (const QString &key : m_settings.allKeys()) { cfg.insert(key, value(key)); } @@ -125,20 +152,16 @@ void SecureQSettings::restoreAppConfig(const QByteArray &base64Cfg) } -QByteArray SecureQSettings::encryptText(const QByteArray& value) const { - char cipherText[UINT16_MAX]; - int cipherTextSize = gcm_encrypt(value.constData(), value.size(), - key.constData(), iv.constData(), iv_len, cipherText); - - return QByteArray::fromRawData((const char *)cipherText, cipherTextSize); +QByteArray SecureQSettings::encryptText(const QByteArray& value) const +{ + QSimpleCrypto::QBlockCipher cipher; + return cipher.encryptAesBlockCipher(value, m_key, m_iv); } -QByteArray SecureQSettings::decryptText(const QByteArray& ba) const { - char decryptPlainText[UINT16_MAX]; - gcm_decrypt(ba.data(), ba.size(), - key.constData(), iv.constData(), iv_len, decryptPlainText); - - return QByteArray::fromRawData(decryptPlainText, ba.size()); +QByteArray SecureQSettings::decryptText(const QByteArray& ba) const +{ + QSimpleCrypto::QBlockCipher cipher; + return cipher.decryptAesBlockCipher(ba, m_key, m_iv); } bool SecureQSettings::encryptionRequired() const diff --git a/client/secure_qsettings.h b/client/secure_qsettings.h index 3fcd4ed7c..ae2a19b72 100644 --- a/client/secure_qsettings.h +++ b/client/secure_qsettings.h @@ -7,6 +7,7 @@ constexpr const char* settingsKeyTag = "settingsKeyTag"; constexpr const char* settingsIvTag = "settingsIvTag"; + class SecureQSettings : public QObject { public: @@ -26,15 +27,17 @@ public: bool encryptionRequired() const; private: - QSettings m_setting; + QSettings m_settings; mutable QMap m_cache; QStringList encryptedKeys; // encode only key listed here - QByteArray key; - QByteArray iv; - int iv_len {16}; + QByteArray m_key; + QByteArray m_iv; + + const QByteArray magicString { "EncData" }; // Magic keyword used for mark encrypted QByteArray + }; #endif // SECUREQSETTINGS_H diff --git a/client/settings.cpp b/client/settings.cpp index c8069f70f..21deb0bd1 100644 --- a/client/settings.cpp +++ b/client/settings.cpp @@ -8,7 +8,6 @@ const char Settings::cloudFlareNs1[] = "1.1.1.1"; const char Settings::cloudFlareNs2[] = "1.0.0.1"; -//SecureFormat Settings::m_secureFormat; Settings::Settings(QObject* parent) : QObject(parent), diff --git a/client/settings.h b/client/settings.h index 39c9919c0..18337f0d7 100644 --- a/client/settings.h +++ b/client/settings.h @@ -11,7 +11,6 @@ #include "core/defs.h" #include "containers/containers_defs.h" -#include "encryption_helper.h" #include "secure_qsettings.h" using namespace amnezia;