Search code examples
c++socketsrsadigital-signaturecrypto++

Trouble Verifying Message RSA Signature Scheme Over Sockets


Im trying to send signed messaged from my server over a socket to a client. I am having trouble verifying the messages. I have tried the filtered and non filtered way based off of the code examples provided on the wiki. I have tried nearly everything I could find on Google but i'm stummped.

How can I do this signature verification scheme over sockets? I left everything I have been trying commented out just to show what I have been trying to do.

   SERVER:

   try
   {
      AutoSeededRandomPool rng;
      stringstream ss;
      string signature;

//      byte* signature = new byte[tdata->signer.MaxSignatureLength()];
//      if( NULL == signature )
//      {
//         throw Exception(Exception::OTHER_ERROR, "Invalid Signature");
//      }
//
//      size_t length = tdata->signer.SignMessage( rng, (const byte*) sendBuf.c_str(),
//          sendBuf.length(), signature );
      //string signature;
//    byte* message = (byte*) sendBuf.c_str();
//    SecByteBlock signature(tdata->signer.MaxSignatureLength(sendBuf.size()));
//
//    size_t signatureLen = tdata->signer.SignMessageWithRecovery(rng, message,
//             sendBuf.size(), NULL, 0, signature);
//
//    cout << "Signature Length: " << signatureLen << endl;
//    ss << signatureLen;
//    string len = ss.str();
//    string send;
//    send = (char*)signature.data();
//    send += " " + len;
      StringSource(sendBuf, true,
               new SignerFilter(rng, tdata->signer, new StringSink(signature),
                        true // putMessage
                        )// SignerFilter
                        );// StringSource

//    cout << "Signature: " << std::hex << signature << endl;
//    // Encode the message as an Integer
//    m = Integer((const byte *) sendBuf.c_str(), sendBuf.size());
//
//    //Encrypt
//    c = tdata->privateKey.CalculateInverse(rng, m);
//
//    //Turn the encrypted value into a string
//    ss << c;
//    sendBuf = ss.str();
//    ss.str("");
//    ss.clear();
//    cout << "Cipher Sent: " << sendBuf << endl;

      tdata->sockSource.Send((byte*)signature.c_str(), sizeof(signature));

And here is the client

   CLIENT:

   string signature, recovered;
   stringstream ss("");
   AutoSeededRandomPool rng;
   byte byteBuf[ 1000 ];

   try
   {
      // Retrieve message from socket
      cout << "Waiting for reply from server..." << endl;
      sockServer.Receive(byteBuf, sizeof(byteBuf));

      ss << byteBuf;
      string signature = ss.str();
      ss.str("");
      ss.clear();

//    byte sig[2048];
//    bool result = verifier.VerifyMessage( (const byte*)message.c_str(),
//        message.length(), sig, 2048 );
//
//    if( true == result )
//    {
//        cout << "Message Verified" << endl;
//    }
//    else
//    {
//        cout << "Message Verification Failed" << endl;
//    }
//    cout << endl << std::hex << "Cipher Received: " << byteBuf << endl;
//
//    SecByteBlock recovered(
//             verifier.MaxRecoverableLengthFromSignatureLength(length));
//
//    DecodingResult result = verifier.RecoverMessage(recovered, NULL, 0,
//             byteBuf, length);
//
//    if ( !result.isValidCoding )
//    {
//       throw Exception(Exception::OTHER_ERROR, "Invalid Signature");
//    }
//
//    ////////////////////////////////////////////////
//    // Use recovered message
//    size_t recoveredLen = result.messageLength;
//
//    assert(
//             0
//                      == memcmp(byteBuf, (const byte* )recovered,
//                               std::min(sizeof(byteBuf), recoveredLen)));

//     Convert message to a string
//    StringSource ss1(byteBuf, sizeof(byteBuf), true,
//             new StringSink(temp));
//
//    ss << byteBuf;
//    signature = ss.str();
//    ss.str("");
//    ss.clear();
//
//    cout << "Signature received: " << std::hex << signature << endl;
//
      StringSource(signature, true,
               new SignatureVerificationFilter(verifier,
                        new StringSink(recovered),
                        SignatureVerificationFilter::THROW_EXCEPTION
                                 | SignatureVerificationFilter::PUT_MESSAGE) // SignatureVerificationFilter
                                 );// StringSource

      cout << "Verified signature on message" << endl;
      return recovered;
//    return recovered;

//    //Convert the string to an Integer so we can calculate the inverse
//    c = Integer(recBuf.c_str());
//    r = serverKey.ApplyFunction(c);
//    cout << "r: " << r << endl;
//
//    // Recover the original message
//    size_t req = r.MinEncodedSize();
//    recovered.resize(req);
//    r.Encode((byte *) recovered.data(), recovered.size());
//    cout << "Recovered: " << recovered << endl;

   }
   catch ( Exception& e )
   {
      cerr << "caught Exception..." << endl;
      cerr << e.what() << endl;
      sockServer.ShutDown(SHUT_RDWR);
      return "";
   }

Solution

  • string signature;
    
    // ...
    
    tdata->sockSource.Send((byte*)signature.c_str(), sizeof(signature));
    

    A std::string is a relatively small class. My std::strings are 32 bytes long. So, my sizeof(signature) is 32.

    Your sizeof(signature) is probably the same. And, as you know sizeof is a compile-time constant. It's going to be 32, or 16, or whatever, whether or not the string contains a few bytes, or a few megabytes.

    What you should be doing is using signature.size() to determine the number of bytes to write.

    Additionally, it's not clear what socket API library you're using, but with most APIs you are not guaranteed to successfully send the requested number of bytes. The request to send a given number of bytes will typically return how many bytes were written, which could be less, in which case you are required to try again. The same thing is true for reading from a socket. You have to know, in advance, how many bytes you expect to receive, and if you read fewer bytes, you have to keep reading.

    It's likely that you must check the return value from Send() and Receive(), and take the appropriate action.