/* * Note: In order to use this file, the OpenSSL dependency must be defined. * * How to generate a key pair (Windows): * set PATH=C:\Program Files\Git\usr\bin;%PATH% * ssh-keygen.exe -m pem -t rsa -P "" -f key.pem * ssh-keygen -f key.pem.pub -m 'PEM' -e > key.pub.pem * del key.pem.pub * ren key.pem key.private.pem * * Sign using openssl executable: * openssl dgst -sha256 -sign key.private.pem -out signature.dat data.zip * openssl enc -base64 -in signature.dat -out signature.txt * Result: signed data in BASE64 encoding. */ #pragma once #include #include class QtOpenSslRsaSign { public: static QByteArray sign( const QByteArray &data, const QByteArray &privateKey); static bool verifySign( const QByteArray &data, const QByteArray &publicKey, const QByteArray &signature); private: QtOpenSslRsaSign() = delete; }; // ----------------------- implementation ---------------------- #include #include inline RSA* createPrivateRSA(const QByteArray &key) { auto keybio = BIO_new_mem_buf(key.data(), key.size()); if (!keybio) return nullptr; return PEM_read_bio_RSAPrivateKey(keybio, nullptr, nullptr, nullptr); } inline bool RSASign( RSA* rsa, const QByteArray &msg, QByteArray &result) { EVP_MD_CTX* ctx = EVP_MD_CTX_create(); EVP_PKEY* priKey = EVP_PKEY_new(); EVP_PKEY_assign_RSA(priKey, rsa); if (EVP_DigestSignInit(ctx, nullptr, EVP_sha256(), nullptr, priKey) <=0) return false; if (EVP_DigestSignUpdate(ctx, msg.constData(), msg.size()) <= 0) return false; size_t resultLen = 0; if (EVP_DigestSignFinal(ctx, nullptr, &resultLen) <=0 || !resultLen) return false; result.resize(resultLen); if (EVP_DigestSignFinal(ctx, reinterpret_cast(result.data()), &resultLen) <= 0) { result.clear(); return false; } EVP_MD_CTX_free(ctx); return true; } inline RSA* createPublicRSA(const QByteArray &key) { auto keybio = BIO_new_mem_buf(key.data(), key.size()); if (!keybio) return nullptr; return PEM_read_bio_RSAPublicKey(keybio, nullptr, nullptr, nullptr); } inline bool RSAVerifySignature( RSA* rsa, const QByteArray &signature, const QByteArray &data) { auto pubKey = EVP_PKEY_new(); EVP_PKEY_assign_RSA(pubKey, rsa); auto ctx = EVP_MD_CTX_create(); if (EVP_DigestVerifyInit(ctx, nullptr, EVP_sha256(), nullptr, pubKey) <= 0) return false; if (EVP_DigestVerifyUpdate(ctx, data.data(), data.size()) <= 0) return false; int AuthStatus = EVP_DigestVerifyFinal(ctx, (unsigned char*)signature.data(), signature.size()); EVP_MD_CTX_free(ctx); return AuthStatus == 1; } inline QByteArray QtOpenSslRsaSign::sign( const QByteArray &data, const QByteArray &privateKey) { QByteArray result; if (auto rsa = createPrivateRSA(privateKey)) RSASign(rsa, data, result); return result; } inline bool QtOpenSslRsaSign::verifySign( const QByteArray &data, const QByteArray &publicKey, const QByteArray &signature) { bool result = false; if (auto rsa = createPublicRSA(publicKey)) result = RSAVerifySignature(rsa, signature, data); return result; }