0

ここで始める前に、サーバーとクライアントがあります。サーバーの Diffie-Hellman 公開静的キーと公開一時キーを含む暗号化された文字列をクライアントに送信したいと考えています。そのために、サーバーの秘密 RSA キーを使用して暗号化された文字列を送信し、クライアントはサーバーの公開 RSA キーで復号化します。

このようにする必要がある理由は、サーバーが公開/秘密キーのペアを持つ唯一のサーバーであるためです。1 つのキー ペアで暗号化すると、Diffie-Hellman に対する MITM 攻撃の一方が遮断されるため、これで問題ありません。私の要件では、問題ありません。

静的キーと一時キーを 16 進数でエンコードされた文字列に変換してソケット経由で送信すると、秘密キーの暗号化段階で問題が発生します。

私のサーバーはやっています:

DH2 dhA(dh);
   SecByteBlock sprivA(dhA.StaticPrivateKeyLength()), spubA(
            dhA.StaticPublicKeyLength());
   SecByteBlock eprivA(dhA.EphemeralPrivateKeyLength()), epubA(
            dhA.EphemeralPublicKeyLength());

   dhA.GenerateStaticKeyPair(rnd, sprivA, spubA);
   dhA.GenerateEphemeralKeyPair(rnd, eprivA, epubA);

   string sendBuf, recvBuf;
   string saEncoded, eaEncoded, encoding;

   cout << "spubA: " << (char*) spubA.data() << endl << "epubA: "
            << (char*) epubA.data() << endl;

   SecByteBlock nil;
   nil.CleanNew(HMAC< SHA256 >::DEFAULT_KEYLENGTH);

   HMAC< SHA256 > hmac;
   hmac.SetKey(nil.data(), nil.size());

   HashFilter filter(hmac, new HexEncoder(new StringSink(encoding)));

   filter.Put(spubA.data(), spubA.size());
   filter.MessageEnd();

   saEncoded = encoding;
   encoding = "";

   filter.Put(epubA.data(), epubA.size());
   filter.MessageEnd();

   eaEncoded = encoding;
   encoding = "";

//   StringSource saSource(spubA, sizeof(spubA), true,
//          new HexEncoder(new StringSink(saEncoded)));
//
//   StringSource eaSource(epubA, sizeof(epubA), true,
//          new HexEncoder(new StringSink(eaEncoded)));
//
   sendBuf = saEncoded + " " + eaEncoded;

   cout << "Send Buffer: " << sendBuf << endl;
   SendMsg(sendBuf, tdata);

SendMsg()暗号化プロセスが含まれています。

この時点で失敗します。

void SendMsg( string sendBuf, struct ThreadData * tdata )
{
   AutoSeededRandomPool rng;
   Integer m, c, r;
   stringstream ss;

   try
   {
      // Encode the message as an Integer
      m = Integer((const byte *) sendBuf.c_str(), sendBuf.size());

      //Encrypt
      c = tdata->privateKey.CalculateInverse(rng, m);  //HERE!

エラーメッセージあり:

InvertibleRSAFunction: computational error during private key operation

Diffie-Hellman セクションで現在コメントアウトされていないコードは、HEREから入手しました。コメント化されたコードの問題は、クライアントが 16 進数でエンコードされた文字列を受信すると、データが失われ、共有シークレットに同意できないことです。しかし、それはソケットを通過します。

この例を次に示します。

Server:
    spubA: &a�|՜D2�tu�cJ����B�R�8�*i�x?N���p��Q�����K��+O �"��P:k�d|3�����6Z
    epubA: 4v������M�E�`l�K��[dN�|Q^r�-ż�����A~D�&gt;4$�9���"v�*:Y��s�O���J��ow�M�߬�C�9n�;���Z�D�6lp�V��oowZ��WSv��",��A3��XL��8��
    Send Buffer: 2661DC7CD59C4432AF747584634AF69BE60298429C52C738 3476CBCCFAA3B0A14DBE45E3606CC84B171DAC1CCE5B644E

Client:
    Recovered: 2661DC7CD59C4432AF747584634AF69BE60298429C52C738 3476CBCCFAA3B0A14DBE45E3606CC84B171DAC1CCE5B644E
    SA: 2661DC7CD59C4432AF747584634AF69BE60298429C52C738
    EA: 3476CBCCFAA3B0A14DBE45E3606CC84B171DAC1CCE5B644E
    Decoded SA: &a�|՜D2�tu�cJ����B�R�8
    Decoded EA: 4v������M�E�`l�K��[dN

このインスタンスに関して、クライアント側で次のことを試みました。

// Get spubA and epubA from server
      recovered = recoverMsg(serverKey, sockServer);

      //Calculate shared secret.
      string sa, ea;
      ss.str(recovered);
      ss >> sa >> ea;
      ss.str("");
      ss.clear();

      cout << "SA: " << sa << endl << "EA: " << ea << endl;

      string decodedSA, decodedEA;
      StringSource decodeSA(sa, true,
               new HexDecoder(new StringSink(decodedSA)));
      StringSource decodeEA(ea, true,
               new HexDecoder(new StringSink(decodedEA)));

      cout << "Decoded SA: " << decodedSA << endl;
      cout << "Decoded EA: " << decodedEA << endl;

      SecByteBlock spubA((const byte*) decodedSA.data(), decodedSA.size());

      if ( spubA.size() < dhB.StaticPublicKeyLength() ) spubA.CleanGrow(
               dhB.StaticPublicKeyLength());
      else spubA.resize(dhB.StaticPublicKeyLength());

      SecByteBlock epubA((const byte*) decodedEA.data(), decodedEA.size());

      if ( epubA.size() < dhB.EphemeralPublicKeyLength() ) epubA.CleanGrow(
               dhB.EphemeralPublicKeyLength());
      else epubA.resize(dhB.EphemeralPublicKeyLength());

しかし、それでも同じ結果が得られます。

これをサーバーの秘密鍵で暗号化し、ソケットを介して正しく送信する方法を知っている人はいますか?

4

2 に答える 2

0

さて、HexEncoding 後の欠落データに関しては、文字列のサイズではなくへのポインタのサイズを返すnn(spubA)ため、これは が原因であることが最も確実です。文字列の長さを取得するには、関数を使用するか、サイズを指定せずにクライアントで行うように、単にCryptoPP、IMHOを使用してそれを行うための最良の方法を使用できます。sizeof()spubAspubA.length()

StringSource saSource(spubA, true,
      new HexEncoder(new StringSink(saEncoded)));

コードの残りの部分については、独自の教科書 RSA を実行しようとしているようです。バッファを整数に変換することから始めているため、独自の RSA をクックしないでください。失敗する運命にある、RSA の教科書は弱い!

そのため、CryptoPP の機能を活用し、CryptoPP の wiki に示されているように、エンクリプターとフィルターを使用して OAEP などの適切なパディング スキームを使用して RSA 暗号化を実行します。

RSAES_OAEP_SHA_Encryptor enc(key);
StringSource(inputString, true,
    new PK_EncryptorFilter(rng, enc,
        new HexEncoder(
            new StringSink(output), false)));

cout << output << endl;

ここで注意しなければならない点は、正しいキーを使用することです。秘密キーを使用して暗号化する必要があるため、次のようにキーを初期化する必要があります。

RSA::PublicKey key;
key.Initialize(privateKey.GetModulus(), privateKey.GetPrivateExponent();

それだけです。すでに動作するはずです。復号化するには、単純に次を使用します。

RSA::PrivateKey clientkey;
clientkey.SetModulus(publicKey.GetModulus());
clientkey.SetPrivateExponent(publicKey.GetPublicExponent());

RSAES_OAEP_SHA_Decryptor d(privateKey);
StringSource(decodedInput, true,
    new PK_DecryptorFilter(rng, d,
        new HexEncoder(
            new StringSink(output), false //lowercase
        )));

cout << output << endl;

ただし、ただし、秘密鍵で暗号化した場合は、秘密鍵で Initialize を使用して復号化しないでください。Initialize は Modulus を因数分解しようとしますが、少なくとも公開指数と秘密指数を知らなければ実行できません。

ここで、最新のコード スニペットが失敗した場合に、秘密鍵と RSA OAEP を使用して暗号化/復号化するテストを行っていないことを告白しなければなりません (素数が定義されていない秘密鍵では RSAES_OAEP_SHA_Decryptor が正常に機能しない可能性があります...私はコンパイラなしでやみくもに入力しています)、今試しているように見えるので、独自のRSAを作成する必要があります。さらにヘルプが必要な場合は、以下にコメントしてください。明日、コンパイラを生成して、それがどのように機能するかを確認します。

ただし、RSA の教科書は非常に脆弱であるため、OAEP を使用してデータをパディングする必要があることに注意してください。

于 2016-12-04T20:41:44.923 に答える