InvertableRSAFunction Сбой при шифровании ключей Диффи-Хеллмана как константного байта *

Прежде чем мы начнем здесь, у меня есть сервер и клиент. Я хочу отправить зашифрованную строку клиенту, которая содержит открытый статический ключ сервера Диффи-Хеллмана и открытый эфемерный ключ. Для этого я использую закрытый RSA-ключ сервера для отправки зашифрованной строки, а клиент расшифровывает с помощью открытого RSA-ключа сервера.

Теперь причина, почему мне нужно сделать это таким образом, заключается в том, что сервер является единственным с парой открытого / закрытого ключа. Это нормально, поскольку шифрование одной парой ключей по-прежнему отсекает одну сторону атаки MITM против Диффи-Хеллмана, и для моих требований это нормально.

Преобразование статического и эфемерного ключей в шестнадцатеричную строку и отправка ее через сокет вызывает у меня проблему со стадией шифрования секретного ключа.

мой сервер делает:

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

Код, который в настоящее время не закомментирован в разделе Диффи-Хеллмана, был получен из ВОТ. Проблема с закомментированным кодом заключается в том, что когда клиент получает строку в шестнадцатеричном формате, он теряет данные и не может договориться о совместном секрете. Но это проходит через сокет.

Пример этого может быть показан:

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

Что касается этого экземпляра, я попытался на стороне клиента сделать следующее:

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

Но я все равно получаю тот же результат.

Кто-нибудь знает, как я могу зашифровать это с помощью закрытого ключа сервера и правильно отправить его через сокет?

0

Решение

Я на самом деле решил все свои проблемы, просто зашифровав все кодировку 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);
}
}
1

Другие решения

Что касается отсутствующих данных после HexEncoding, это, скорее всего, вызвано nn(spubA), так как sizeof() возвращает размер указателя на spubA вместо размера вашей строки. Чтобы получить длину строки, вы можете использовать spubA.length() использовать функцию или просто использовать лучший способ сделать это с помощью CryptoPP, IMHO, как вы делаете с клиентом просто без указания размера:

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

Что касается остальной части вашего кода, похоже, что вы пытаетесь выполнить свой собственный учебник RSA, поскольку вы начинаете с преобразования буфера в целое число, пожалуйста, не готовьте свой собственный RSA! Обречен на провал, учебник RSA слаб!

Поэтому используйте возможности CryptoPP и выполняйте шифрование RSA, используя хорошую схему заполнения, такую ​​как OAEP, используя шифратор и фильтр, как показано в вики CryptoPP:

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 попытается разложить модуль на множители, что не может быть сделано без знания хотя бы открытого и частного экспонент.

Теперь я должен признаться, что я не проверял шифрование / дешифрование с использованием закрытого ключа и RSA OAEP, если мой последний фрагмент кода не работает (возможно,
RSAES_OAEP_SHA_Decryptor не будет в порядке с закрытым ключом, простые числа которого не определены … Я печатаю вслепую, без компилятора), тогда вам придется создавать свой собственный RSA, как вы, похоже, пытаетесь сейчас. Если вам нужна дополнительная помощь, пожалуйста, прокомментируйте ниже, и завтра я попробую запустить мой компилятор и посмотреть, как он работает.

Но имейте в виду, что учебник по RSA очень слабый, поэтому вам следует дополнять данные с помощью OAEP.

0

По вопросам рекламы [email protected]