2016-12-03 13 views
0

여기에서 시작하기 전에 서버와 클라이언트가 있습니다. 서버의 Diffie-Hellman 공용 정적 키와 공용 임시 키가 들어있는 암호화 된 문자열을 클라이언트에 보내려고합니다. 그렇게하기 위해 서버의 개인 RSA 키를 사용하여 암호화 된 문자열을 보내고 클라이언트는 서버의 공개 RSA 키를 사용하여 암호를 해독합니다.InvertableRSAFunction이 Diffie-Hellman 키를 const 바이트로 암호화하지 못함 *

이제는 서버가 공개/개인 키 쌍이있는 유일한 서버이기 때문에이 방법을 사용해야하는 이유가 있습니다. Diffie-Hellman에 대한 MITM 공격의 한 쪽을 여전히 하나의 키 쌍으로 암호화하므로 괜찮습니다. 제 요구 사항에 대해서는 괜찮습니다.

정적 및 임시 키를 16 진수로 인코딩 된 문자열로 변환하여 소켓을 통해 보내면 개인 키 암호화 단계에서 문제가 발생합니다.

내 서버하고있다 : SendMsg() 암호화 프로세스를 포함

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

.

이는이 시점에서 실패

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 

현재 디피 - 헬만 secition에서 주석되지 않은 코드 HERE로부터 얻었다. 주석 처리 된 코드의 문제점은 클라이언트가 16 진수로 인코딩 된 문자열을 수신하면 데이터가 손실되어 공유 암호에 동의 할 수 없다는 것입니다. 그러나 소켓을 통과합니다.

이의 예를 표시 할 수 있습니다 :

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

하지만 여전히 같은 결과를 얻을 :

이 인스턴스와 관련하여
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�>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 

, 나는 다음을 수행하기 위해 클라이언트 측에서 시도 .

아무도 내가 이것을 서버의 개인 키로 어떻게 암호화하고 소켓을 통해 올바르게 보낼 수 있는지 알고 있습니까?

+0

정말로 문제를 격리해야합니다. 로컬 파일에서 작업하는 것이 좋습니다. 그런 다음 소켓을 통해 고정 버퍼로 이동하십시오 (''A ''문자열과 같이). 그 후 무작위 데이터 (' '\ 0' '을 포함하는 데이터와 같은)를 가진 고정 된 크기의 버퍼로 이동하십시오. 마지막으로 실제 서명이있는 실제 파일로 이동하십시오. 고정 버퍼에 문제가 발생하면 소켓 보내기/받기 질문을하십시오. – jww

답변

0

글쎄, HexEncoding 후 누락 된 데이터에 대해서는 sizeof()이 문자열 크기 대신 포인터의 크기를 spubA으로 반환하기 때문에 이것이 가장 확실한 이유는 nn(spubA)입니다. 문자열의 길이를 구하려면 당신은 spubA.length() 기능을 사용하거나 단순히 크기를 지정하지 않고 당신이 클라이언트와 마찬가지로, IMHO, CryptoPP을 사용하여이 작업을 수행하는 가장 좋은 방법을 사용할 수있다 : 지금의 나머지 부분에 대한

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

당신의 코드, 그것은 자신의 교과서 RSA를 수행하려는 것처럼 보입니다. 버퍼를 정수로 변환하기 시작하기 때문에 자신의 RSA를 요리하지 마십시오! RSA 교과서가 약하다는 것은 실패 할 운명입니다!

그래서 CryptoPP 능력을 활용하고 CryptoPP의 위키에 도시 한 바와 같은 암호기 및 필터를 사용하여 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; 

을 :하지만 단순히 사용, 해독하려면 초기화가 계수를 시도하고 factorise 때문에, 당신은 개인 키를 사용하여 암호화 한 경우 암호를 해독하기 위해 개인 키를 사용하여 초기화를 사용하지 않는 최소한 대중과 사적인 지 식자를 모른 채 할 수는 없습니다. 내 최신 코드가 (실패하면 이제

, 나는이 암호화/개인 키와 RSA의 OAEP를 사용하여 해독 테스트되지 않았 음을 고백해야, 어쩌면 RSAES_OAEP_SHA_Decryptor는 그 소수 '그런가 개인 키 괜찮되지 않습니다 t는 정의 ... 나는 컴파일러없이 맹목적으로 타이핑하고있다.) 그러면 지금 시도하고있는 것처럼 당신은 자신의 RSA를 양조해야 할 것이다. 더 많은 도움이 필요하시면 아래에 의견을 남기고 내일 컴파일러를 생성하고 어떻게 작동하는지 확인해 보겠습니다.

그러나 RSA 교과서는 매우 약하며 OAEP를 사용하여 데이터를 덧붙여 야합니다.

+0

나는'RSAES_OAEP_SHA_Decryptor'에 개인 키를 사용하려고 시도했지만 이전에는 작동하지 않았다. 그것은 잠시 뒤로 돌아와서 내가 왜 작동하지 않는지와 RAA RSA로 전환 한 상황을 정확히 모릅니다. 나는 하나의 공개/개인 키 쌍만 가지고 있기 때문에 RSA를하는 방법을 사용하고 있습니다. –

1

실제로 Base64를 모든 것을 인코딩하여 모든 문제를 해결했습니다. 또한 모든 수신 후 수신을 추가하고 모든 수신 후에 수신을 추가하여 서버와 클라이언트를 함께 동기화하여 타이밍 문제를 방지했습니다. 그 모든 'HexEncoding'난센스가 필요하지 않습니다. 이 문자열을 문자열로 변환하여 원하는대로 입력하고,이 함수로 보내면됩니다.

string RecoverMsg(struct ThreadData * tdata) 
{ 
    try 
    { 
     Integer c = 0, r = 0, m = 0; 
     size_t req = 0, bytes = 0; 
     AutoSeededRandomPool rng; 
     string recovered = "", ack = "", decodedCipher = ""; 
     byte byteBuf[ 2000 ]; 
     memset(byteBuf, 0, sizeof(byteBuf)); 

     // Retrieve message from socket 
     cout << "Waiting to receive a message from client " << tdata->tid << endl; 

     bytes = tdata->sockSource.Receive(byteBuf, sizeof(byteBuf)); 
     cout << "Bytes Read: " << bytes << endl; 

     cout << "Encoded Cipher Received: " << byteBuf << endl; 

     decodedCipher; 
     StringSource(byteBuf, sizeof(byteBuf), true, 
       new Base64Decoder(new StringSink(decodedCipher))); 

     c = Integer(decodedCipher.c_str()); 

     // Decrypt 
     r = tdata->privateKey.CalculateInverse(rng, c); 
     cout << "r: " << r << endl; 

     // Round trip the message 
     req = r.MinEncodedSize(); 
     recovered.resize(req); 
     r.Encode((byte *) recovered.data(), recovered.size()); 

     cout << "Recovered: " << recovered << endl; 

     ack = "ACK"; 
     bytes = tdata->sockSource.Send((const byte*) ack.c_str(), ack.size()); 

     return recovered; 
    } 
    catch (Exception& e) 
    { 
     cerr << "caught Exception..." << endl; 
     cerr << e.what() << endl; 
     tdata->sockSource.ShutDown(SHUT_RDWR); 
    } 
} 

void SendMsg(string sendBuf, struct ThreadData * tdata) 
{ 
    try 
    { 
     AutoSeededRandomPool rng; 
     stringstream ss(""); 
     string cipher = "", encodedCipher = ""; 
     Integer m = 0, c = 0, r = 0; 
     size_t bytes = 0; 
     byte ack[ 10 ]; 
     memset(ack, 0, sizeof(ack)); 

     // Treat the message as a big endian array 
     m = Integer((const byte *) sendBuf.c_str(), sendBuf.size()); 
     cout << "m: " << m << endl; 

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

     ss << c; 
     cipher = ss.str(); 
     ss.str(""); 
     ss.clear(); 

     // Base64 encode the cipher 
     encodedCipher; 
     StringSource(cipher, cipher.size(), 
       new Base64Encoder(new StringSink(encodedCipher))); 

     cout << "Encoded Cipher Sent: " << encodedCipher << endl; 

     // Send the cipher 
     bytes = tdata->sockSource.Send((const byte*) encodedCipher.c_str(), 
       encodedCipher.size()); 
     cout << "Bytes Written: " << bytes << endl; 

     bytes = tdata->sockSource.Receive(ack, sizeof(ack)); 
    } 
    catch (Exception& e) 
    { 
     cerr << "caught Exception..." << endl; 
     cerr << e.what() << endl; 
     tdata->sockSource.ShutDown(SHUT_RDWR); 
    } 
}