Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Qt + CryptoPP : Asymmetric encryption Problem: the string is either too long or too short for the public key
Forum Updated to NodeBB v4.3 + New Features

Qt + CryptoPP : Asymmetric encryption Problem: the string is either too long or too short for the public key

Scheduled Pinned Locked Moved Unsolved General and Desktop
5 Posts 2 Posters 646 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • Q Offline
    Q Offline
    QtCoder87
    wrote on last edited by
    #1

    I have a Problem with CryptoPP. I generated a Private Key of size 4096 Bit = 512 Bytes.

    Now when I send over TCP I encrypt the Message everything under 512 will be filled with 0. If the message is bigger than 512 Bytes it will be splitted and sent to chunks.

    I fill up because if it is below 512 the Receiver throws an Exception that the text does not match with the key. I tried with 480 Bytes Chunks

    But if I send a message file over 6MB in 512 Bytes it will throw a Message that 512 Bytes exceeds the the key size

    I tried to send in 510 Bytes. In this case both sides threw an error that 510 exceeds the size of public key and the over said 510 does not match with key
    Anyone sees a solution or a Asymmetric Encryption giving you the choice to encrypt smaller messages than the FIXED Messages?

    buffer2k48 is 512. The name was because it was a 2048 bit key before.

    Encryption: (Server Generates Key)

    void KSecureDesktopQT::generateRSAKeys()
    {
        this->privateKey = std::make_unique<CryptoPP::InvertibleRSAFunction>();
        this->privateKey->GenerateRandomWithKeySize(rng, 4096);
        this->publicKey = std::make_unique<CryptoPP::RSAFunction>(*this->privateKey);
    }
    

    If the Client wants to send a File he starts making a request over DTLS

    void KChatDialog::sendfile()
    {
    	//this->generateKeyPair();
    	this->temp_file_path_for_request = QFileDialog::getOpenFileName(nullptr, "Select Files", QString(), "*.*");
    	if (this->temp_file_path_for_request.isEmpty())
    		return;
    	QFile file(this->temp_file_path_for_request);
    	nlohmann::json request;
    	request["action"] = static_cast<uint16_t>(ActionTypes::FileSendRequest);
    	request["from"] = this->user;
    	request["cookie"] = this->cookie;
    	request["path"] = this->temp_file_path_for_request.toStdU16String();
    	request["size"] = file.size();
    	auto r = request.dump();
    	this->s->writeDtlsDatagram(r.c_str());
    	//this->sendFilesFoo(this->targets, str.toStdU16String());
    }
    

    The Server receives the Request, the User can choose to deny the file

    void KSecureDesktopQT::receiveFiles(const QHostAddress& address, uint16_t port, const nlohmann::json& data) {
        auto from = QString::fromStdString(data["from"].get<std::string>());
        auto size = data["size"].get<uint64_t>();
        auto pvec = data["path"];
        std::u16string str = u"";
        for (nlohmann::json::iterator iter = pvec.begin(); iter != pvec.end(); ++iter) {
            char16_t c = iter.value().get<uint16_t>();
            str += c;                                 
        }
        auto caption = QString::fromStdU32String(this->language["MainForm"]["FileReceiveRequest"]["caption"]);
        auto sfrom = QString::fromStdU32String(this->language["MainForm"]["FileReceiveRequest"]["from"]);
        auto spath = QString::fromStdU32String(this->language["MainForm"]["FileReceiveRequest"]["path"]);
        auto ssize = QString::fromStdU32String(this->language["MainForm"]["FileReceiveRequest"]["size"]);
        auto body = sfrom + ':' + from + '\n' + ssize + ':' + QString::number(size) + '\n' + spath + ':' + QString::fromStdU16String(str);
        //auto res = QMessageBox::question(nullptr, caption, body, QMessageBox::StandardButton::Yes, QMessageBox::StandardButton::No);
        std::promise<bool> transfer;
        auto fut = transfer.get_future();
            emit this->askForReceiveFileAllowance(caption, body,(transfer));
            fut.wait();
        if (fut.get() == false) {
            this->denyFileRequest(address, port, from.toStdString(), this->user);
            return;
        }
        std::promise<QString> target;
        auto futuris = target.get_future();
        emit this->saveFileSignal(QString("Receiving"), target);
        futuris.wait();
        auto path_str = futuris.get();
        //auto targetpath = QFileDialog::getSaveFileName(nullptr, "Receiving", QString(), QString("*.*"));
        if (path_str.isEmpty()) {
            this->denyFileRequest(address, port, from.toStdString(), this->user);
            return;
        }
        
        this->acceptFileRequest(address,port,from.toStdString(),this->user, path_str,str,size);
    }
    

    The Filepath is U16String since Windows is using wchar and with Unicode wchar_t (windows) is char16_t.

    If the server accepts it goes to this Function

    void KSecureDesktopQT::acceptFileRequest(const QHostAddress& address, uint16_t port, std::string& source, std::string& receiver, const QString& target, const std::u16string& original, uint64_t filesize)
    {
        nlohmann::json response;
        response["action"] = static_cast<uint16_t>(ActionTypes::FileRequestAccept);
        response["source"] = source;
        response["from"] = receiver;
        response["path"] = original;
        response["port"] = (*this->tbl)["communication"]["chat"].value_or<uint16_t>(899);
        std::string strPubKey;
        CryptoPP::Base64Encoder pubkey(new CryptoPP::StringSink(strPubKey));
        this->publicKey->DEREncode(pubkey);
        pubkey.MessageEnd();
        response["key"] = strPubKey;
        FileInformation fi;
        fi.from = QString::fromStdString(source);
        fi.size = filesize;
        fi.source = QString::fromStdU16String(original);
        fi.target = target;
        std::promise<KTransferProgress*> prom;
        auto cont = prom.get_future();
        emit this->openTransferDialog(fi, prom);
        cont.wait();
        KTransferProgress* dlg_ptr = cont.get();
        auto str = response.dump();
        this->server->sendEncryptedDatagram(address, port, QString::fromStdString(str));
        //this->chatSocket.writeDatagram(str.c_str(), str.size(), address, port);
        //sockpp::tcp_acceptor acc((*this->tbl)["communication"]["chat"].value_or<uint16_t>(899));
    
        
    
        sockpp::tcp_acceptor acc((*this->tbl)["communication"]["chat"]["port"].value_or<uint16_t>(899));
        sockpp::inet_address peer;
        auto sock = acc.accept(&peer);
        sock.read_timeout(std::chrono::seconds(30));
        std::vector<uint8_t> bytes;
        char* buffer = new char[buffer2k48];
        int64_t len = 0;
        CryptoPP::RSAES_PKCS1v15_Decryptor dec(*this->privateKey);
        try {
            do {
                memset(buffer, 0, buffer2k48);
                len = sock.read(buffer, buffer2k48);
                std::string encrypted(buffer, len);
                std::string plain;
                CryptoPP::StringSource ss1(encrypted, true, new CryptoPP::PK_DecryptorFilter(this->rng, dec, new CryptoPP::StringSink(plain)));
                if (len > 0)
                    bytes.insert(bytes.end(), plain.begin(), plain.end());
                dlg_ptr->update(len);
            } while (len > 0);
        }
        catch (const CryptoPP::Exception& ex) {
            std::string e = ex.what();
            int i = 0;
        }
        //std::string encrypted(bytes.begin(), bytes.end());
        
        QSaveFile file(target);
        file.open(QIODevice::WriteOnly);
        file.write(reinterpret_cast<char*>(&bytes.at(0)),bytes.size());
        if (file.commit()) {
            emit this->informationSignal(1, "Transfer Completed", "Transfer successfully completed");
            //QMessageBox::information(nullptr, "Transfer completed", "Transfer successfully completed");
            return;
        }
        emit this->informationSignal(2, "Transfer failed", "transfer failed");
        //QMessageBox::warning(nullptr, "Transfer incomplete", "Transfer failed");
    }
    

    and the Client receives message that the file was accepted:

    void KChatDialog::acceptedFileRequest(const nlohmann::json& json)
    {
    	std::unique_ptr<CryptoPP::RSAFunction> pubkey = std::make_unique<CryptoPP::RSAFunction>();
    	std::string spubkey = json["key"].get<std::string>();
    	CryptoPP::StringSource src(spubkey, true, new CryptoPP::Base64Decoder);
    	CryptoPP::ByteQueue bytes;
    	src.TransferTo(bytes);
    	pubkey->Load(bytes);
    	QFile file(this->temp_file_path_for_request);
    	file.open(QIODevice::ReadOnly);
    	auto fdata = file.readAll();
    	std::string raw(fdata.begin(), fdata.end());
    	//std::string encrypted;
    	CryptoPP::RSAES_PKCS1v15_Encryptor enc(*pubkey);
    	//
    	auto addr = this->s->peerAddress();
    	auto ip = quint32IPv4ToString(addr.toIPv4Address());
    	auto port = json["port"].get<uint16_t>();
    	sockpp::tcp_connector conn;
    	conn.connect(sockpp::inet_address(ip.toStdString(), port));
    	const char* const data = raw.c_str();
    	uint32_t indexer = buffer2k48;
    	uint64_t alreadyWritten = 0;
    	//auto* ptr = data;
    	bool quitafter = false;
    	for (uint64_t i = 0, end = raw.size(); i < end; ) {
    		uint64_t diff = raw.size() - alreadyWritten;
    		auto plain = [&](){
    			if (diff > buffer2k48)
    				return raw.substr(alreadyWritten, buffer2k48);
    			return raw.substr(i, diff);
    		}();
    		std::string encrypted;
    		
    		if ((end - alreadyWritten) < buffer2k48) {
    			fillToLimit(plain);
    			quitafter = true;
    		}
    			//indexer = end - alreadyWritten;
    		CryptoPP::StringSource ss1(plain.c_str(), true, new CryptoPP::PK_EncryptorFilter(this->rng, enc, new CryptoPP::StringSink(encrypted)));
    		auto len = conn.write(encrypted);
    		if (len < 1 || quitafter == true)
    		{
    			//ERROR
    			break;
    		}
    		alreadyWritten += len;
    		//ptr += len;
    		i += len;
    	}
    	file.close();
    	conn.close();
    }
    
    1 Reply Last reply
    0
    • hskoglundH Offline
      hskoglundH Offline
      hskoglund
      wrote on last edited by
      #2

      Hi, don't see the source code for function fillToLimit()?
      Also, instead of sending the file through port 899, could you simplify your example, for example use a CryptoPP::FileSink instead to transfer a file?

      Q 1 Reply Last reply
      1
      • hskoglundH hskoglund

        Hi, don't see the source code for function fillToLimit()?
        Also, instead of sending the file through port 899, could you simplify your example, for example use a CryptoPP::FileSink instead to transfer a file?

        Q Offline
        Q Offline
        QtCoder87
        wrote on last edited by
        #3

        @hskoglund

        void fillToLimit(std::string& str, uint32_t futureSize = buffer2k48) {
        	
        	for (uint32_t i = 0, end = futureSize - str.size(); i < end; ++i) {
        		str += char(0);
        	}
        	
        }
        

        it fills the string with 0s.

        you can send a file through network with FileSink?
        I am not sending through tcp just for encrypting a file. Since the receiver is decrypting it again. I just want to encrypted data transfer with Public / Privatekey.

        1 Reply Last reply
        0
        • Q Offline
          Q Offline
          QtCoder87
          wrote on last edited by
          #4

          OK I will try to encrypt the File with AES and encrypt the key with RSA and send the encrypted AES Key to client.

          1 Reply Last reply
          0
          • hskoglundH Offline
            hskoglundH Offline
            hskoglund
            wrote on last edited by
            #5

            Hi, basically you're trying to solve 2 problems at the same time: encrypting a file and sending the encrypted file to another computer.
            What I mean, encrypting/decrypting in the same loop that you're receiving or transmitting is not a good idea. Better to do it in separate steps: 1) encrypt to a file 2) send the encrypted file on port 899 3) receive it on the server and save it as a file 4) decrypt it. (Steps 2 and 3 can then be done without involving CryptoPP).

            Also, the fillToLimit() function is very dangerous, although std::string is perfectly happy with embedded/extra null bytes, other parts of the string functions in c++ are not, for example: c_str() will not include them and a std::string constructor ((const char* s, size_t n) will not include them, for example in your KSecureDesktopQT::acceptFileRequest() function this constructor will disregard the efforts of fillToLimit():

            ...
            std::string encrypted(buffer, len);
            ...
            

            Consider changing fillToLimit() to add extra spaces instead of null bytes :-)

            1 Reply Last reply
            1

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved