【问题标题】:Trouble Verifying Message RSA Signature Scheme Over Sockets无法通过套接字验证消息 RSA 签名方案
【发布时间】:2016-12-04 02:58:03
【问题描述】:

我正在尝试通过套接字从我的服务器向客户端发送签名消息。我无法验证消息。我已经根据 wiki 上提供的代码示例尝试了过滤和非过滤方式。我已经尝试了几乎所有可以在 Google 上找到的东西,但我被难住了。

如何通过套接字执行此签名验证方案?我把我一直在尝试的所有内容都注释掉了,只是为了展示我一直在尝试做的事情。

   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));

这里是客户端

   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 "";
   }

【问题讨论】:

  • 您应该先在本地文件上练习,然后再使用套接字。也许 Google Protocol Buffers 会有助于抽象出套接字细节。它们也可以工作,因此您不必担心清除代码中的低级错误。

标签: c++ sockets rsa digital-signature crypto++


【解决方案1】:
string signature;

// ...

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

std::string 是一个相对较小的类。我的std::strings 有 32 个字节长。所以,我的sizeof(signature) 是 32。

您的sizeof(signature) 可能是一样的。而且,如您所知,sizeof 是一个编译时常量。它将是 32 或 16 或其他任何值,无论字符串是否包含几个字节或几兆字节。

您应该做的是使用signature.size() 来确定要写入的字节数。

此外,尚不清楚您使用的是哪个套接字 API 库,但对于大多数 API,您不能保证成功发送请求的字节数。发送给定字节数的请求通常会返回写入的字节数,可能会更少,在这种情况下,您需要重试。从套接字读取也是如此。您必须提前知道您希望接收多少字节,如果您读取的字节少,则必须继续阅读。

您可能必须检查来自Send()Receive() 的返回值,并采取适当的措施。

【讨论】:

  • 感谢您注意到我的字符串大小问题。我一直在爬楼梯和切换东西,以至于我在途中的某个地方错过了那个细节。我正在使用 Crypto++ 套接字 API。除了签名验证,我没有其他任何问题。我也在做 RSA 加密和解密,效果很好。我为发送方进行签名的原因是因为我试图阻止 MITM Diffie-Hellman 攻击,但我只有一个公钥/私钥对。我只能切断一侧的攻击,但没关系。
  • 我还修复了大小问题。仍然没有使用流水线过滤器方法进行验证。这不应该工作吗?
  • 看起来您也没有清除 byteBuf 缓冲区。它可能包含随机垃圾。 Receive() 正在将字节转储到其中,并且没有明确地 '\0 终止。请注意,std::strings 可以包含空字节,并且从普通缓冲区初始化字符串或字符串流只会收集直到第一个 '\0' 的所有内容。事实上,整个字符串流没有任何用处。您需要确切地知道Receive()d 有多少字节。期间。
  • 你先生,是男人!好吧,我的消息现在验证了,但为什么没有恢复?我真的一无所获。嗯。
  • "...不清楚您使用的是什么套接字 API 库,但对于大多数 API,您不能保证成功发送请求的字节数..." - 我是按照这些思路思考的。也许谷歌Protocol Buffers会帮助他抽象出细节。
猜你喜欢
  • 2020-06-28
  • 1970-01-01
  • 2017-07-30
  • 1970-01-01
  • 2019-11-24
  • 2014-02-20
  • 2018-08-18
  • 2021-01-12
  • 2016-01-15
相关资源
最近更新 更多