Merge pull request #63 from QuasarApp/openssl3
Some checks failed
buildbot/AndroidBuilder_v8Qt6 Build finished.
buildbot/LinuxCMakeBuilderQt6 Build finished.
buildbot/DocsGenerator Build finished.
buildbot/IOSCMakeBuilder Build finished.
buildbot/WindowsCMakeBuilder Build finished.

Openssl3
This commit is contained in:
Andrei Yankovich 2023-07-21 21:07:27 +03:00 committed by GitHub
commit b10f6c2a83
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 29 additions and 1263 deletions

3
.gitmodules vendored
View File

@ -4,3 +4,6 @@
[submodule "submodules/QuasarAppLib"]
path = submodules/QuasarAppLib
url = https://github.com/QuasarApp/QuasarAppLib.git
[submodule "submodules/easyssl"]
path = submodules/easyssl
url = https://github.com/QuasarApp/easyssl.git

View File

@ -5,7 +5,7 @@
# of this license document, but changing it is not allowed.
#
cmake_minimum_required(VERSION 3.10)
cmake_minimum_required(VERSION 3.18)
project(Heart)
if(TARGET ${PROJECT_NAME})
@ -51,6 +51,14 @@ find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Network Sql Concurrent REQUIR
add_subdirectory(submodules/QuasarAppLib)
add_subdirectory(submodules/crc)
if (HEART_SSL)
option(EASYSSL_TESTS "disable tests of the easyssl submodule " OFF)
option(EASYSSL_STATIC_SSL "disable tests of the easyssl submodule " ${HEART_STATIC_SSL})
add_subdirectory(submodules/easyssl)
endif()
add_subdirectory(src)
if (HEART_TESTS)

View File

@ -11,7 +11,6 @@
#include "abstractnodetest.h"
#include <shedullertest.h>
#include <bigdatatest.h>
#include <ecdsaauthtest.h>
#include <upgradedatabasetest.h>
#define TestCase(name, testClass) \
@ -34,10 +33,6 @@ private slots:
TestCase(bigDataTest, BigDataTest);
TestCase(shedullerTest, ShedullerTest);
#ifdef USE_HEART_SSL
TestCase(ecdsaAuthTest, ECDSAAuthTest);
#endif
TestCase(upgradeDataBaseTest, UpgradeDataBaseTest)
// END TEST CASES

View File

@ -1,100 +0,0 @@
/*
* Copyright (C) 2022-2023 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/
#include "ecdsaauthtest.h"
#include <QtTest>
#include <hcryptoFeatures/authecdsa.h>
#include <thread>
#ifdef USE_HEART_SSL
/*
* test class
*/
class ECDSA: public QH::AuthECDSA {
public:
ECDSA(const QByteArray &publicKey, const QByteArray &privKey) {
setPublicKey(publicKey);
_priv = privKey;
}
// AsyncKeysAuth interface
protected:
QByteArray getPrivateKey() const override {
return _priv;
};
private:
QByteArray _priv;
};
ECDSAAuthTest::ECDSAAuthTest() {
}
ECDSAAuthTest::~ECDSAAuthTest() {
}
void ECDSAAuthTest::test() {
// create a publick and private keys array.
QByteArray pub, priv;
QString userID;
// make public and private keys.
QVERIFY(QH::AuthECDSA::makeKeys(pub, priv));
// make user id
QString userIDOfPubKey = QCryptographicHash::hash(pub,
QCryptographicHash::Sha256).
toBase64(QByteArray::Base64UrlEncoding);
// check createed keys. should be larget then 0.
QVERIFY(pub.length() && priv.length());
// create test auth object using ecdsa algorithm
ECDSA edsa(pub, priv);
// The terst object should be invalid because it is not prepared.
QVERIFY(!edsa.isValid());
// the authetication should be failed bacause ecdsa class is invalid.
QVERIFY(!edsa.auth(600, &userID));
QVERIFY(userID.isEmpty());
// prepare an authentication object.
QVERIFY(edsa.prepare());
// the prepared object should be valid.
QVERIFY(edsa.isValid());
// authentication should be finished successful because auth object contains prepared valid signature.
QVERIFY(edsa.auth(600, &userID));
QVERIFY(userID == userIDOfPubKey);
// forget user id before new auth
userID.clear();
// authentication should be failed because the time range is depricated.
QVERIFY(!edsa.auth(0, &userID));
QVERIFY(userID.isEmpty());
// change subsribe time and try login.
edsa.setUnixTime(time(0) + 1);
std::this_thread::sleep_for(std::chrono::seconds(1));
// should be failed because signature is different of the time.
QVERIFY(!edsa.auth(600, &userID));
QVERIFY(userID.isEmpty());
}
#endif

View File

@ -1,27 +0,0 @@
/*
* Copyright (C) 2022-2023 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/
#ifndef ECDSAAUTHTEST_H
#define ECDSAAUTHTEST_H
#include "test.h"
#include "testutils.h"
#ifdef USE_HEART_SSL
class ECDSAAuthTest: public Test, protected TestUtils
{
public:
ECDSAAuthTest();
~ECDSAAuthTest();
void test();
};
#endif
#endif // ECDSAAUTHTEST_H

View File

@ -5,7 +5,7 @@
# of this license document, but changing it is not allowed.
#
cmake_minimum_required(VERSION 3.10)
cmake_minimum_required(VERSION 3.18)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
@ -30,11 +30,7 @@ if (HEART_VALIDATE_PACKS)
endif()
set(SLL_DEFINE "WITHOUT_SSL")
if (HEART_SSL)
list(APPEND CMAKE_FIND_ROOT_PATH "$ENV{OPENSSL_ROOT_DIR}")
find_package(OpenSSL 1.1.1 REQUIRED)
set(SLL_DEFINE "USE_HEART_SSL")
endif()
@ -45,8 +41,6 @@ file(GLOB SOURCE_CPP
"public/*.cpp" "public/*.h" "public/*.qrc"
"public/packages/*.cpp" "public/packages/*.h" "public/packages/*.qrc"
"private/*.cpp" "private/*.h" "private/*.qrc"
"public/hcrypto/*.cpp" "public/hcrypto/*.h" "public/hcrypto/*.qrc"
"public/hcryptoFeatures/*.cpp" "public/hcryptoFeatures/*.h" "public/hcryptoFeatures/*.qrc"
)
set(PUBLIC_INCUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
@ -56,33 +50,9 @@ set(PRIVATE_INCUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/private")
add_library(${PROJECT_NAME} ${SOURCE_CPP})
target_link_libraries(${PROJECT_NAME} PUBLIC Qt::Core Qt::Network Qt::Sql Qt::Concurrent QuasarApp crc)
target_link_libraries(${PROJECT_NAME} PUBLIC Qt::Core Qt::Network Qt::Sql Qt::Concurrent QuasarApp crc )
if (HEART_SSL)
if (HEART_STATIC_SSL)
message("Use static ssl")
target_link_libraries(${PROJECT_NAME} PUBLIC libcrypto.a libssl.a)
else()
message("Use shared ssl ")
target_link_libraries(${PROJECT_NAME} PUBLIC OpenSSL::Crypto OpenSSL::SSL)
if (ANDROID)
set(OPENSSL_ROOT_PATH "$ENV{OPENSSL_ROOT_DIR}")
set(ANDROID_EXTRA_LIBS
${OPENSSL_ROOT_PATH}/lib/libcrypto_1_1.so
${OPENSSL_ROOT_PATH}/lib/libssl_1_1.so
CACHE INTERNAL "")
message(ANDROID_EXTRA_LIBS = ${ANDROID_EXTRA_LIBS})
endif()
endif()
message("Use the OpenSSL libraries: ${OPENSSL_LIBRARIES}")
target_link_libraries(${PROJECT_NAME} PUBLIC easyssl)
endif()
target_include_directories(${PROJECT_NAME} PUBLIC ${PUBLIC_INCUDE_DIR})

View File

@ -8,8 +8,7 @@
#ifndef NETWORKPROTOCOL_H
#define NETWORKPROTOCOL_H
#include "package.h"
#include "abstractnode.h"
#include "heart_global.h"
inline void initResources() { Q_INIT_RESOURCE(ProtockolResusces); }

View File

@ -17,12 +17,9 @@
#ifdef USE_HEART_SSL
#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/bio.h>
#include <openssl/x509.h>
#include <sslsocket.h>
#include <easyssl/x509.h>
#include <easyssl/rsassl.h>
#include <QSslConfiguration>
#include <QSslCertificate>
@ -329,166 +326,16 @@ QSslConfiguration AbstractNode::getSslConfig() const {
return _ssl;
}
bool AbstractNode::generateRSAforSSL(EVP_PKEY *pkey) const {
if (!pkey) {
return false;
}
//#if OPENSSL_VERSION_MAJOR >= 3
// EVP_PKEY_CTX *pctx =
// EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
// unsigned int primes = 3;
// unsigned int bits = 4096;
// OSSL_PARAM params[3];
// pkey = EVP_RSA_gen(4096);
// EVP_PKEY_keygen_init(pctx);
// params[0] = OSSL_PARAM_construct_uint("bits", &bits);
// params[1] = OSSL_PARAM_construct_uint("primes", &primes);
// params[2] = OSSL_PARAM_construct_end();
// EVP_PKEY_CTX_set_params(pctx, params);
// EVP_PKEY_generate(pctx, &pkey);
// EVP_PKEY_CTX_free(pctx);
//#else
BIGNUM * bn = BN_new();
int rc = BN_set_word(bn, RSA_F4);
if (rc != 1) {
BN_free(bn);
return false;
}
RSA * rsa = RSA_new();
if (!RSA_generate_key_ex(rsa, 2048, bn, nullptr)) {
return false;
}
q_check_ptr(rsa);
if (EVP_PKEY_assign_RSA(pkey, rsa) <= 0)
return false;
//#endif
return true;
}
bool AbstractNode::generateSslDataPrivate(const SslSrtData &data, QSslCertificate& r_srt, QSslKey& r_key) {
EVP_PKEY *pkey = EVP_PKEY_new();
if (!generateRSAforSSL(pkey)) {
return false;
}
X509 * x509 = nullptr;
X509_NAME * name = nullptr;
BIO * bp_public = nullptr, * bp_private = nullptr;
const char *buffer = nullptr;
int size;
x509 = X509_new();
q_check_ptr(x509);
ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);
X509_gmtime_adj(X509_get_notBefore(x509), 0); // not before current time
X509_gmtime_adj(X509_get_notAfter(x509), data.endTime); // not after a year from this point
X509_set_pubkey(x509, pkey);
name = X509_get_subject_name(x509);
q_check_ptr(name);
unsigned char *C = reinterpret_cast<unsigned char *>(data.country.toLatin1().data());
X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, C, -1, -1, 0);
unsigned char *O = reinterpret_cast<unsigned char *>(data.organization.toLatin1().data());
X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, O, -1, -1, 0);
unsigned char *CN = reinterpret_cast<unsigned char *>(data.commonName.toLatin1().data());
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, CN, -1, -1, 0);
X509_set_issuer_name(x509, name);
X509_sign(x509, pkey, EVP_sha256());
bp_private = BIO_new(BIO_s_mem());
q_check_ptr(bp_private);
if(PEM_write_bio_PrivateKey(bp_private, pkey, nullptr, nullptr, 0, nullptr, nullptr) != 1) {
EVP_PKEY_free(pkey);
X509_free(x509);
BIO_free_all(bp_private);
qCritical("PEM_write_bio_PrivateKey");
return false;
}
bp_public = BIO_new(BIO_s_mem());
q_check_ptr(bp_public);
if(PEM_write_bio_X509(bp_public, x509) != 1){
EVP_PKEY_free(pkey);
X509_free(x509);
BIO_free_all(bp_public);
BIO_free_all(bp_private);
qCritical("PEM_write_bio_PrivateKey");
return false;
}
size = static_cast<int>(BIO_get_mem_data(bp_public, &buffer));
q_check_ptr(buffer);
r_srt = QSslCertificate(QByteArray(buffer, size));
if(r_srt.isNull()) {
EVP_PKEY_free(pkey);
X509_free(x509);
BIO_free_all(bp_public);
BIO_free_all(bp_private);
qCritical("Failed to generate a random client certificate");
return false;
}
size = static_cast<int>(BIO_get_mem_data(bp_private, &buffer));
q_check_ptr(buffer);
r_key = QSslKey(QByteArray(buffer, size), QSsl::Rsa);
if(r_key.isNull()) {
EVP_PKEY_free(pkey);
X509_free(x509);
BIO_free_all(bp_public);
BIO_free_all(bp_private);
qCritical("Failed to generate a random private key");
return false;
}
EVP_PKEY_free(pkey); // this will also free the rsa key
X509_free(x509);
BIO_free_all(bp_public);
BIO_free_all(bp_private);
return true;
}
QSslConfiguration AbstractNode::selfSignedSslConfiguration(const SslSrtData & sslData) {
QSslConfiguration AbstractNode::selfSignedSslConfiguration(const EasySSL::SslSrtData &sslData) {
QSslConfiguration res = QSslConfiguration::defaultConfiguration();
QSslKey pkey;
QSslCertificate crt;
if (!generateSslDataPrivate(sslData, crt, pkey)) {
QuasarAppUtils::Params::log("fail to create ssl certificate. node svitch to InitFromSystem mode",
QuasarAppUtils::Warning);
return res;
}
res.setPrivateKey(pkey);
res.setLocalCertificate(crt);
EasySSL::X509 generator(QSharedPointer<EasySSL::RSASSL>::create());
EasySSL::SelfSignedSertificate certificate = generator.create(sslData);
res.setPrivateKey(certificate.key);
res.setLocalCertificate(certificate.crt);
res.setPeerVerifyMode(QSslSocket::VerifyNone);
return res;
@ -538,7 +385,7 @@ void AbstractNode::setIgnoreSslErrors(const QList<QSslError> &newIgnoreSslErrors
_ignoreSslErrors = newIgnoreSslErrors;
};
bool AbstractNode::useSelfSignedSslConfiguration(const SslSrtData &crtData) {
bool AbstractNode::useSelfSignedSslConfiguration(const EasySSL::SslSrtData &crtData) {
if (isListening()) {
return false;

View File

@ -13,8 +13,8 @@
#include "ping.h"
#ifdef USE_HEART_SSL
#include <openssl/evp.h>
#include <QSslConfiguration>
#include <easyssl/icertificate.h>
#endif
#include <QAbstractSocket>
@ -77,19 +77,6 @@ enum class AddNodeError {
RegisterSocketFailed
};
#ifdef USE_HEART_SSL
/**
* @brief The SslSrtData struct This structure contains base information for generate self signed ssl certefication.
* If you want change selfSigned certificate then use method AbstractNode::useSelfSignedSslConfiguration.
*/
struct SslSrtData {
QString country = "BY";
QString organization = "QuasarApp";
QString commonName = "";
long long endTime = 31536000L; //1 year
};
#endif
#define CRITICAL_ERROOR -50
#define LOGICK_ERROOR -20
#define REQUEST_ERROR -5
@ -456,28 +443,12 @@ protected:
*/
void setIgnoreSslErrors(const QList<QSslError> &newIgnoreSslErrors);
/**
* @brief generateRSAforSSL This method generate ssl rsa pair keys for using in selfsigned cetificate.
* By default generate RSA 2048, if you want change algorithm or keys size then override this method.
* @param pkey This is openssl pointer to RSA pair key.
* @return True if keys generated successful.
*/
virtual bool generateRSAforSSL(EVP_PKEY* pkey) const;
/**
* @brief generateSslDataPrivate This method generate a ssl certificate and a ssl keys using The SslSrtData structure.
* @param data The data for generate a selfSigned certificate.
* @param r_srt This is return value of a certivicate.
* @param r_key - This is return value of private ssl key.
* @return True if generate the selfSigned certificate finished succesful.
*/
virtual bool generateSslDataPrivate(const SslSrtData& data, QSslCertificate& r_srt, QSslKey& r_key);
/**
* @brief selfSignedSslConfiguration This method create a new ssl configuration with selfsigned certificates.
* @param data This is data for generate selfsigned certification for more information see SslSrtData structure.
* @return The new selfsigned ssl configuration.
*/
virtual QSslConfiguration selfSignedSslConfiguration( const SslSrtData& data = {});
virtual QSslConfiguration selfSignedSslConfiguration( const EasySSL::SslSrtData& data = {});
#endif
/**
@ -562,7 +533,7 @@ protected:
* @param crtData - This is data for generation a new self signed certification.
* @return result of change node ssl configuration.
*/
bool useSelfSignedSslConfiguration(const SslSrtData& crtData);
bool useSelfSignedSslConfiguration(const EasySSL::SslSrtData& crtData);
/**
* @brief useSystemSslConfiguration This method reconfigure current node to use sslConfig.

View File

@ -1,253 +0,0 @@
//#
//# Copyright (C) 2021-2023 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include "ecdsassl11.h"
#ifdef USE_HEART_SSL
#include <openssl/ecdsa.h> // for ECDSA_do_sign, ECDSA_do_verify
#include <openssl/obj_mac.h> // for NID_secp192k1
#include <openssl/evp.h>
#include <openssl/err.h>
#include <QCryptographicHash>
#include <QDataStream>
#include <QIODevice>
#include <QVector>
#include <quasarapp.h>
namespace QH {
ECDSASSL11::ECDSASSL11() {
}
void printlastOpenSSlError() {
int error = ERR_get_error();
char buffer[256];
ERR_error_string(error, buffer);
QuasarAppUtils::Params::log(QString("openssl: %0").arg(buffer),
QuasarAppUtils::Error);
}
QByteArray bignumToArray(const BIGNUM* num) {
int length = BN_bn2mpi(num, nullptr);
QVector<unsigned char> data(length);
BN_bn2mpi(num, data.data());
QByteArray result;
result.insert(0, reinterpret_cast<char*>(data.data()), data.length());
return result;
}
BIGNUM* bignumFromArray(const QByteArray& array) {
auto d = reinterpret_cast<const unsigned char*>(array.data());
BIGNUM* result = BN_mpi2bn(d,
array.length(), nullptr);
if (!result) {
printlastOpenSSlError();
}
return result;
}
QByteArray extractPrivateKey(EC_KEY* ec_key) {
const BIGNUM* ec_priv = EC_KEY_get0_private_key(ec_key);
return bignumToArray(ec_priv);
}
QByteArray extractPublicKey(EC_KEY* key, EC_GROUP* group) {
QByteArray data;
point_conversion_form_t form = EC_GROUP_get_point_conversion_form(group);
unsigned char* pub_key_buffer;
size_t length = EC_KEY_key2buf(key, form, &pub_key_buffer, nullptr);
if (length <= 0) {
printlastOpenSSlError();
return {};
}
data.insert(0, reinterpret_cast<const char*>(pub_key_buffer), length);
OPENSSL_free(pub_key_buffer);
return data;
}
bool ECDSASSL11::makeKeys(QByteArray &pubKey, QByteArray &privKey) {
EC_KEY *eckey= nullptr;
EC_GROUP *ecgroup = nullptr;
if (!prepareKeyAdnGroupObjects(&eckey, &ecgroup)) {
return false;
}
if (!EC_KEY_generate_key(eckey)) {
printlastOpenSSlError();
EC_GROUP_free(ecgroup);
EC_KEY_free(eckey);
return false;
}
pubKey = extractPublicKey(eckey, ecgroup);
privKey = extractPrivateKey(eckey);
return pubKey.length() && privKey.length();
}
QByteArray ECDSASSL11::signMessage(const QByteArray &inputData,
const QByteArray &key) const {
EC_KEY *eckey= nullptr;
EC_GROUP *ecgroup = nullptr;
if (!prepareKeyAdnGroupObjects(&eckey, &ecgroup)) {
return {};
}
auto hash = QCryptographicHash::hash(inputData,
QCryptographicHash::Sha256);
BIGNUM* priv = bignumFromArray(key);
if (!EC_KEY_set_private_key(eckey, priv)) {
printlastOpenSSlError();
EC_GROUP_free(ecgroup);
EC_KEY_free(eckey);
return {};
};
ECDSA_SIG *signature = ECDSA_do_sign(reinterpret_cast<const unsigned char*>(hash.data()),
hash.length(), eckey);
BN_free(priv);
EC_KEY_free(eckey);
EC_GROUP_free(ecgroup);
if (!signature) {
printlastOpenSSlError();
return {};
}
const BIGNUM * R, *S;
ECDSA_SIG_get0(signature, &R, &S);
QByteArray result;
QDataStream stream(&result, QIODevice::WriteOnly);
stream << bignumToArray(R);
stream << bignumToArray(S);
ECDSA_SIG_free(signature);
return result;
}
bool ECDSASSL11::checkSign(const QByteArray &inputData,
const QByteArray &signature,
const QByteArray &key) const {
// extract signature from raw array
BIGNUM * R, *S;
QDataStream stream(signature);
QByteArray rR,rS;
stream >> rR;
stream >> rS;
R = bignumFromArray(rR);
S = bignumFromArray(rS);
ECDSA_SIG *sig = ECDSA_SIG_new();
ECDSA_SIG_set0(sig, R, S);
auto hash = QCryptographicHash::hash(inputData,
QCryptographicHash::Sha256);
EC_KEY *eckey= nullptr;
EC_GROUP *ecgroup = nullptr;
if (!prepareKeyAdnGroupObjects(&eckey, &ecgroup)) {
ECDSA_SIG_free(sig);
return {};
}
// extract key from raw array;
EC_POINT* ec_point = EC_POINT_new(ecgroup);
EC_POINT_oct2point(ecgroup, ec_point,
reinterpret_cast<const unsigned char*>(key.data()),
key.length(), nullptr);
EC_KEY_set_public_key(eckey, ec_point);
int verify_status = ECDSA_do_verify(reinterpret_cast<const unsigned char*>(hash.data()),
hash.length(), sig, eckey);
ECDSA_SIG_free(sig);
EC_POINT_free(ec_point);
return verify_status == 1;
}
QByteArray ECDSASSL11::decript(const QByteArray &, const QByteArray &) {
return {};
}
QByteArray ECDSASSL11::encript(const QByteArray &, const QByteArray &) {
return {};
}
bool ECDSASSL11::prepareKeyAdnGroupObjects(EC_KEY **eckey, EC_GROUP **ecgroup) {
// input data should be valid pointers to pointers of key and group objects.
if (!(eckey && ecgroup))
return false;
// input pointers should be nullptr;
if ((*eckey) || (*ecgroup))
return false;
auto free = [eckey, ecgroup] () {
if (*ecgroup)
EC_GROUP_free(*ecgroup);
if (*eckey)
EC_KEY_free(*eckey);
};
*eckey = EC_KEY_new();
if (!*eckey) {
printlastOpenSSlError();
free();
return false;
}
*ecgroup = EC_GROUP_new_by_curve_name(NID_secp256k1);
if (!*ecgroup) {
printlastOpenSSlError();
free();
return false;
}
if (!EC_KEY_set_group(*eckey, *ecgroup)) {
printlastOpenSSlError();
free();
return false;
}
return true;
}
}
#endif

View File

@ -1,64 +0,0 @@
//#
//# Copyright (C) 2021-2023 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#ifndef QH_ECDSA_SSL_1_1_H
#define QH_ECDSA_SSL_1_1_H
#include "heart_global.h"
#ifdef USE_HEART_SSL
#include "icrypto.h"
#include <openssl/ec.h> // for EC_GROUP_new_by_curve_name, EC_GROUP_free, EC_KEY_new, EC_KEY_set_group, EC_KEY_generate_key,EC_KEY_free
namespace QH {
/**
* @brief The ECDSASSL11 class is ecdsa implementation of the Async authentication. This implementation based on Openssl library.
* @note This class compatibility only with ssl 1.1 and ssl 3.0 (depricated fundtions).
*/
class HEARTSHARED_EXPORT ECDSASSL11: public QH::ICrypto
{
public:
ECDSASSL11();
/**
* @brief makeKeys This static method generate the public and private keys of the ECDSA.
* @param pubKey This is result public key.
* @param privKey This is result private key.
* @return true if keys generated successful.
*/
static bool makeKeys(QByteArray &pubKey, QByteArray &privKey);
protected:
QByteArray signMessage(const QByteArray &inputData, const QByteArray &key) const override;
bool checkSign(const QByteArray &inputData, const QByteArray &signature, const QByteArray &key) const override;
/**
* @brief decript This method has empty implementation.
* @return empty array.
*/
QByteArray decript(const QByteArray &message, const QByteArray &key) override;
/**
* @brief encript This method has empty implementation.
* @return empty array.
*/
QByteArray encript(const QByteArray &message, const QByteArray &key) override;
private:
static bool prepareKeyAdnGroupObjects(EC_KEY **eckey, EC_GROUP **ecgroup);
};
}
#endif
#endif // QH_ECDSA_SSL_1_1_H

View File

@ -1,14 +0,0 @@
/*
* Copyright (C) 2018-2023 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/
#include "icrypto.h"
namespace QH {
}

View File

@ -1,65 +0,0 @@
/*
* Copyright (C) 2021-2023 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/
#ifndef I_CRYPTO_H
#define I_CRYPTO_H
#include "heart_global.h"
#include <QByteArray>
namespace QH {
/**
* @brief The ICrypto class This is base interface that provide encription functionality.
*/
class HEARTSHARED_EXPORT ICrypto
{
protected:
/**
* @brief decript This method decript @a message using @a key.
* @param message This is encripted message that should be decripted.
* @param key This is key that will be used for decription for the @a message.
* @return decripted message or empty string if method not supported or decripted failed.
* @see IAsyncEncription::encript
*/
virtual QByteArray decript(const QByteArray& message, const QByteArray& key) = 0;
/**
* @brief decript This method encript @a message using @a key.
* @param message This is a message that should be decripted.
* @param key This is key that will be used for encription for the @a message.
* @return decripted message or empty string if method not supported or decripted failed.
* @see IAsyncEncription::encript
*/
virtual QByteArray encript(const QByteArray& message, const QByteArray& key) = 0;
/**
* @brief signMessage This method should be sign the @a message using the @a key.
* @param message This is input data that should be signed.
* @param key This is a privete key for encription the @a message.
* @return signature data array.
* @see AsyncKeysAuth::descrupt
*/
virtual QByteArray signMessage(const QByteArray& message, const QByteArray& key) const = 0;
/**
* @brief checkSign This method should be check signature of the @a message using the @a key.
* @param message This is input data that should be decripted.
* @param signature This is signature that will be checked for the @a message.
* @param key This is a public key for encription the @a inpputData.
* @return decripted data array.
* @see AsyncKeysAuth::encrypt
*/
virtual bool checkSign(const QByteArray& message,
const QByteArray& signature,
const QByteArray& key) const = 0;
};
}
#endif // I_CRYPTO_H

View File

@ -1,231 +0,0 @@
/*
* Copyright (C) 2021-2023 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/
#ifndef ASYNCKEYSAUTH_H
#define ASYNCKEYSAUTH_H
#include <QCryptographicHash>
#include <time.h>
#include <QString>
namespace QH {
/**
* @brief The AsyncKeysAuth class is temaplate class for works with authorization of a pair of asynchronous keys
* This class contains base implementation for the authentication using async encription. The base encription alhorithm defined on the template argument **CryptoImplementation**.
* You can use any crypto alhorithm.
*
* ## Exampel of use:
*
* @code{cpp}
* #include <hcrypto.h>
*
* using ECDSAAuth = AsyncKeysAuth<ECDSA>;
*
* @endcode
*
*
* ### How to it works:
*
* * -----
*
* ** Client Part **
*
* * Client make a pair keys (public and private) = PUB and PRIV
* * Client get current unix time = U
* * Client make a data for signing = S
* S = SHA256{U + PUB}
* * Client make a signature SIG
* SIG = PRIV.signMessage(S)
* * Client prepare a auth request for server = R:
* R = {U,SIG,PUB}
* * Cleint send R to server
*
* * -----
*
* ** Server Part **
*
* * Server receive R from client.
* * Server compare U time with current unix time.
* * If the diferrence more then allowed value then server reject an auth
* * Server make S value as a client
* * Server check SIG value and comapre it with S value
* * If message sign is valid then server accept an auth else reject.
* * After accept server create new user with ID = sha256(PUB) or
* if user alredy exits make them as a logined user.
*
* @tparam CryptoImplementation This is internal implementaion of base encription functions.
* @see iCrypto class.
*
*/
template<class CryptoImplementation>
class AsyncKeysAuth: public CryptoImplementation
{
public:
AsyncKeysAuth() {
}
~AsyncKeysAuth() {
}
/**
* @brief auth This method make authentication and return true if the authentication finished successful else false.
* @brief retLoginedUserId This is logined user id in Base64UrlEncoding
* @return true if the authentication finished successful else false.
*/
bool auth(int allowedTimeRangeSec, QString* retLoginedUserId) const {
int diff = time(0) - _unixTime;
if (diff < 0) {
return false;
}
if (diff >= allowedTimeRangeSec) {
return false;
}
QByteArray data = _publicKey;
data.insert(0, reinterpret_cast<const char*>(&_unixTime),
sizeof(_unixTime));
bool result = checkSign(data, _signature, _publicKey);
if (result && retLoginedUserId) {
*retLoginedUserId = getUserId();
}
return result;
}
/**
* @brief prepare This method will generate signature for autentication of client. Please inboke this method before send request to server.
* @return true if signature generated sucessuful.
*/
bool prepare() {
_unixTime = time(0);
QByteArray data = _publicKey;
data.insert(0, reinterpret_cast<const char*>(&_unixTime),
sizeof(_unixTime));
setSignature(signMessage(data, getPrivateKey()));
return isValid();
}
/**
* @brief unixTime This method return unix time that client added for authentication.
* @return unix time that client added for authentication.
* @see AsyncKeysAuth::setUnixTime
*/
unsigned int unixTime() const {
return _unixTime;
}
/**
* @brief setUnixTime This method sets new value of the unixTime propertye.
* @param newUnixTime This is new unix time value. Unix time sets in secunds from 1970 year
*/
void setUnixTime(unsigned int newUnixTime) {
_unixTime = newUnixTime;
}
/**
* @brief signature This method return signature array.
* @return signature array.
* @see AsyncKeysAuth::setSignature
*/
const QByteArray &signature() const {
return _signature;
}
/**
* @brief isValid this method check this ibject to valid.
* @return return true if object contains valid signature else false.
* @note Invoke the AsyncKeysAuth::prepare method before check valid of object. All object that not be preparred is invalid.
*/
bool isValid() const {
return _publicKey.size() && _signature.size() && _unixTime;
}
/**
* @brief getUserId This method return user id that generated from the public key.
* @note This function works slow, because this object does not contain ID of user. The user ID will be generated every invoke of this function
* @return user ID.
*/
QString getUserId() const {
return QCryptographicHash::hash(_publicKey,
QCryptographicHash::Sha256).
toBase64(QByteArray::Base64UrlEncoding);
}
/**
* @brief publicKey This method return public key that client added for authentication.
* @note The @a publicKey will be used forcreate user id.
* @return public key that client added for authentication.
* @see AsyncKeysAuth::setPublicKey
*/
const QByteArray &publicKey() const {
return _publicKey;
}
/**
* @brief setPublicKey This method sets new public key for authentication.
* @param newPublicKey Thiy is new key.
* @see AsyncKeysAuth::publicKey
*/
void setPublicKey(const QByteArray &newPublicKey) {
_publicKey = newPublicKey;
}
protected:
QByteArray decript(const QByteArray &message, const QByteArray &key) override {
return CryptoImplementation::decript(message, key);
};
QByteArray encript(const QByteArray &message, const QByteArray &key) override {
return CryptoImplementation::encript(message, key);
};
QByteArray signMessage(const QByteArray &message, const QByteArray &key) const override {
return CryptoImplementation::signMessage(message, key);
};
bool checkSign(const QByteArray &message, const QByteArray &signature, const QByteArray &key) const override {
return CryptoImplementation::checkSign(message, signature, key);
};
/**
* @brief getPrivateKey This method should be return private key for the public key that saved in this object.
* @return private key for the public key that saved in this object.
*/
virtual QByteArray getPrivateKey() const = 0;
/**
* @brief setSignature Tihis is internal method for sets new signature value.
* @param newSignature new signature value.
* @note used in the
*/
void setSignature(const QByteArray &newSignature) {
_signature = newSignature;
}
unsigned int _unixTime = 0;
QByteArray _signature;
QByteArray _publicKey;
};
}
#endif // ASYNCKEYSAUTH_H

View File

@ -1,31 +0,0 @@
//#
//# Copyright (C) 2021-2023 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#ifndef AUTHECDSA_H
#define AUTHECDSA_H
#include "heart_global.h"
#ifdef USE_HEART_SSL
#include "hcrypto/ecdsassl11.h"
#include "asynckeysauth.h"
namespace QH {
/**
* @brief The AuthECDSA class is ecdsa implementation of the Async authentication. This implementation based on Openssl library.
*/
typedef AsyncKeysAuth<ECDSASSL11> AuthECDSA;
}
#endif
#endif // AUTHECDSA_H

View File

@ -1,22 +0,0 @@
/*
* Copyright (C) 2021-2023 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/
#ifndef ECDSASIGNER_H
#define ECDSASIGNER_H
#include "signer.h"
#include "hcrypto/ecdsassl11.h"
namespace QH {
/**
* @brief The ECDSASigner class is ecdsa implementation of the Signer class. This implementation based on Openssl library.
*/
typedef Signer<ECDSASSL11> ECDSASigner;
}
#endif // ECDSASIGNER_H

View File

@ -1,47 +0,0 @@
/*
* Copyright (C) 2021-2023 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/
#include "isignerdelegate.h"
namespace QH {
ISignerDelegate::ISignerDelegate() {
}
const QByteArray &ISignerDelegate::getSignature() const {
return sign;
}
void ISignerDelegate::setSignature(const QByteArray &newSignature) {
sign = newSignature;
}
const QByteArray &ISignerDelegate::getHash() const {
return hash;
}
void ISignerDelegate::setHash(const QByteArray &newHash) {
hash = newHash;
}
QDataStream &ISignerDelegate::fromStream(QDataStream &stream) {
stream >> hash;
stream >> sign;
return stream;
}
QDataStream &ISignerDelegate::toStream(QDataStream &stream) const {
stream << hash;
stream << sign;
return stream;
}
}

View File

@ -1,83 +0,0 @@
/*
* Copyright (C) 2021-2023 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/
#ifndef ISIGNERDELEGATE_H
#define ISIGNERDELEGATE_H
#include <streambase.h>
namespace QH {
/**
* @brief The ISignerDelegate class This is base class of signer delegate.
* The sisgner class will be invoke all delegate methods for control the input object that need to sign.
* @note This class contasin sign and hash fild and override the >> and << operators for QDataStream,
* so if you want to convert your object to bytes array don not forget invoke the ISignerDelegate::fromStream and ISignerDelegate::toStream methods.
* @see Signer
*/
class ISignerDelegate: public StreamBase
{
public:
ISignerDelegate();
/**
* @brief getSignature This method return constant reference to the signature array.
* @return constant reference to the signature array.
*/
virtual const QByteArray &getSignature() const;
/**
* @brief setSignature This method sets the new signature of this object.
* @param newSignature new signature value.
*/
virtual void setSignature(const QByteArray &newSignature);
/**
* @brief getHash This method return constant reference to the hash array.
* @return constant reference to the signature array.
*/
virtual const QByteArray &getHash() const;
/**
* @brief setHash This method sets the new hash sum of this object.
* @param newSignature new signature value.
*/
virtual void setHash(const QByteArray &newHash);
/**
* @brief getPrivateKey This method should be return private key for the public key that saved in this object.
* @return private key for the public key that saved in this object.
*/
virtual const QByteArray& getPrivateKey() const = 0;
/**
* @brief getPublicKey This method should be return public key for the private key that encrypted this object.
* @return public key for the private key that ecrypt this object.
*/
virtual const QByteArray& getPublicKey() const = 0;
/**
* @brief getMessage This method should be return message that you want to sign.
* @return message that you want to sign.
*/
virtual const QByteArray getMessage() const = 0;
// StreamBase interface
protected:
QDataStream &fromStream(QDataStream &stream) override;
QDataStream &toStream(QDataStream &stream) const override;
private:
QByteArray hash;
QByteArray sign;
};
}
#endif // ISIGNERDELEGATE_H

View File

@ -1,91 +0,0 @@
/*
* Copyright (C) 2021-2023 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/
#ifndef SIGNER_H
#define SIGNER_H
#include <QByteArray>
#include <QCryptographicHash>
#include <QSharedPointer>
#include "isignerdelegate.h"
#include "qaservice.h"
namespace QH {
/**
* @brief The Signer class can sign and check the signature of the any childs classes of the ISignerDelegate class.
*
* **Exmaple of use**
*
* @code{cpp}
* #include <hcriptoFeatures/isignerdelegate.h>
* #include <hcriptoFeatures/ecdsasigner.h>
*
* class MyDelegate: public ISignerDelegate {
* // override all methods
* };
*
* int main () {
* MyDelegate delegate;
*
* // sign your object
* QH::ECDSASigner::sign(&delegate);
*
* // check signature of the object
* QH::ECDSASigner::check(&delegate);
* }
*
*
* @endcode
*
* @note the MyDelegate class should be contains a public for check signature and a private for sign object keys
* @tparam CryptoImplementation This is internal implementaion of base encription functions.
* @see iCrypto class.
*/
template<class CryptoImplementation>
class Signer: protected QuasarAppUtils::Service<Signer<CryptoImplementation>>,
protected CryptoImplementation
{
public:
Signer() {};
~Signer() {};
/**
* @brief sign This is main method for signing of this object.
* @return true if the object signed sucessful
*/
static bool sign(ISignerDelegate* obj) {
if (auto signer = Signer<CryptoImplementation>::autoInstance()) {
auto sign = signer->signMessage(obj->getMessage(), obj->getPrivateKey());
if (sign.size()) {
obj->setSignature(sign);
return true;
}
}
return false;
};
/**
* @brief check This method check signature of this object.
* @return true if the objec signed
*/
static bool check(const ISignerDelegate* obj) {
if (auto signer = Signer<CryptoImplementation>::autoInstance()) {
return signer->checkSign(obj->getMessage(), obj->signature(), obj->getPublicKey());
}
return false;
};
};
}
#endif // SIGNER_H

@ -1 +1 @@
Subproject commit fb8c76feb66f108adc8b6ed0aef0aaa7600477c9
Subproject commit 53a67709ff90b544036cb90edbfe8cb1ded6dc0b

1
submodules/easyssl Submodule

@ -0,0 +1 @@
Subproject commit 83cea813075c1837c0dafc3036596c9667a5d213