Используйте Crypto++ RSA::PublicKey для расшифровки зашифрованного текста.

У меня есть алгоритм n, d, e для RSA. Однако я хочу использовать private_key для шифрования некоторой строки, генерировать USER_CERTIFICATION и использовать public_key для пользователей, чтобы расшифровать ее и получить строку. Я знаю, что если я это сделаю, любой может легко расшифровать строку, но безопасность не меня совсем не беспокоит, мне просто нужно, чтобы никто, кроме меня, не мог сгенерировать USER_CERTIFICATION

Я использую CryptoPP, код для кодирования работает нормально:

Integer _n(...), _e(...), _d(...);
AutoSeededRandomPool rng;
RSA::PrivateKey k;
k.Initialize(_n, _e, _d);
RSAES_PKCS1v15_Encryptor enc(k);
std::string cipher;
StringSource ss1( plain, true,
    new PK_EncryptorFilter( rng, enc,
        new StringSink( cipher )) // PK_EncryptorFilter
    ); // StringSource

но код расшифровки выдает исключение: "класс CryptoPP::InvertibleRSAFunction: отсутствует обязательный параметр "Prime1""

Integer _n(...), _e(...);

AutoSeededRandomPool rng;
RSA::PublicKey k;
k.Initialize(_n, _e);
RSAES_PKCS1v15_Decryptor dec(k);
std::string plain;
StringSource ss1( cipher, true,
    new PK_DecryptorFilter( rng, dec,
        new StringSink( plain ))
    ); // StringSource

Возможно ли это сделать с КриптоПП?


person aj3423    schedule 14.06.2016    source источник


Ответы (2)


Я хочу использовать private_key для шифрования некоторой строки

Обычно, когда вы запрашиваете шифрование закрытым ключом, вам нужна схема вероятностной подписи с восстановлением (PSSR). Между прочим, зашифровать закрытым ключом не допустимое криптографическое преобразование :)

cryptlib.h header описывается как Абстрактные базовые классы, обеспечивающие единый интерфейс. в эту библиотеку. Все подписанты и верификаторы Crypto++ придерживаются интерфейса PK_SignatureScheme. Подписывающие дополнительно реализуют PK_Signer, а верификаторы дополнительно реализуют PK_Verifier.

Объекты Crypto++ RSA будут выглядеть так:

RSASS<PSSR, SHA256>::Signer signer;
RSASS<PSSR, SHA256>::Verifier verifier;

Объекты Crypto++ Рабина будут выглядеть так:

RabinSS<PSSR, SHA256>::Signer signer;
RabinSS<PSSR, SHA256>::Verifier verifier;

Объекты Crypto++ Rabin-Williams будут выглядеть так:

RWSS<PSSR, SHA256>::Signer signer;
RWSS<PSSR, SHA256>::Verifier verifier;

объекты согласованы, и вы можете менять их местами.

Кстати, вы должны изучить Rabin-Williams, чтобы увидеть, соответствует ли он вашим потребностям. См. также подписи RSA и подписи Рабина-Вильямса: современное состояние Бернштейна.


Я использую КриптоПП, код для кодирования работает нормально...

Утилизируйте это. Экспонента, которую вы используете, хорошо известна, поэтому нет никакой реальной безопасности в том, что вы делаете. Есть способы улучшить безопасность, но похоже, что вместо этого вам нужен PSSR.

Вот два примера использования PSSR RSA из вики:

А вот код подписавшего для вероятностной схемы подписи RSA с восстановлением с некоторыми вашими данными. . Обратите внимание, что вам нужен настоящий RandomNumberGenerator, поскольку подпись рандомизирована.

Integer n(...), e(...), d(...);
RSA::PrivateKey key(n,e,d);
RSASS<PSSR, SHA256>::Signer signer(key);

////////////////////////////////////////////////
// Sign and Encode
SecByteBlock signature(signer.MaxSignatureLength(messageLen));

AutoSeededRandomPool rng;
size_t signatureLen = signer.SignMessageWithRecovery(rng, message, messageLen, NULL, 0, signature);

// Resize now we know the true size of the signature
signature.resize(signatureLen);

А вот код проверки для вероятностной схемы подписи RSA с восстановлением с некоторыми вашими данными. . Обратите внимание, что вам не нужен RandomNumberGenerator, поэтому вы можете использовать NullRNG(), если он где-то нужен.

Integer n(...), e(...);
RSA::PublicKey key(n,e);
RSASS<PSSR, SHA256>::Verifier verifier(key);

////////////////////////////////////////////////
// Verify and Recover
SecByteBlock recovered(
    verifier.MaxRecoverableLengthFromSignatureLength(signatureLen)
);

DecodingResult result = verifier.RecoverMessage(recovered, NULL, 0, signature, signatureLen);

if (!result.isValidCoding) {
    throw Exception(Exception::OTHER_ERROR, "Invalid Signature");
}

////////////////////////////////////////////////
// Use recovered message
//  MaxSignatureLength is likely larger than messageLength
recovered.resize(result.messageLength);

... но код расшифровки выдает исключение: "класс CryptoPP::InvertibleRSAFunction: отсутствует обязательный параметр "Prime1""

Да, зашифровать закрытым ключом не допустимое криптографическое преобразование. Я почти уверен, что расшифровать с помощью открытого ключа также недействительно :)


Я не буду приводить код для шифрования и дешифрования, так как не верю, что он вам нужен. Но вы можете найти его в разделе Схемы шифрования RSA на вики Crypto++.

person jww    schedule 14.06.2016
comment
SignatureWithRecovery работает, но не может обрабатывать сообщения размером более 128 байт. Разделение длинного сообщения на множество фрагментов по 128 байт кажется не очень хорошей идеей. Теперь я использую a_exp_b_mod_c(message, d, n) для самостоятельного кодирования. - person aj3423; 16.06.2016
comment
@aj3423 - Просто чтобы не было сюрпризов... ваше сообщение все еще слишком велико. a_exp_b_mod_c молча обрезает его. Если вы выполните обратное преобразование, то вы получите обратно усеченное сообщение. Просмотрите Raw RSA и изучите восстановленное сообщение (соответствующий раздел Шифрование с закрытым ключом). Чтобы избежать усечения: можно ли увеличить размер модуля или использовать сообщение меньшего размера? - person jww; 16.06.2016
comment
@aj3423 - Также убедитесь, что вы действительно хотите отказаться от рандомизации подписи. В цитируемой статье Бернштейна говорится о том, почему вы хотите рандомизировать подпись в разделе 5. Атаки на нерандомизированные подписи существуют с 1979 года. - person jww; 16.06.2016
comment
Да, мне приходится разбивать сообщения на части по 244 байта для заполнения pkcs1v15, я думаю, что 244 байта все же лучше, чем 128 байт. Я попробую ApplyFunction + CalculateInverse позже, спасибо. - person aj3423; 16.06.2016
comment
@aj3423 - Звучит хорошо. Вы также можете выполнить поиск в Google Scholar: pss-r большое сообщение чтобы увидеть, какие альтернативы вам подходят. - person jww; 16.06.2016
comment
@aj3423 - Как у вас дела с экспериментами по восстановлению? - person jww; 17.06.2016
comment
Возможно, я все равно не могу использовать ApplyFunction, потому что для инициализации RSA::PrivateKey требуются все три аргумента n,e,d. Я не могу передавать клиентам e и d. Я понятия не имею, почему RSA::PrivateKey требует инициализации трех из них, я думаю, что теоретически все должно быть в порядке только с двумя из них. - person aj3423; 17.06.2016
comment
@jww вы не правы, шифрование с помощью закрытого ключа является полностью законной операцией, это основа математики, лежащая в основе RSA. Если бы это было не так, вы бы не смогли использовать RSA для подписи. - person Jiri Otoupal イり オトウパー; 02.09.2020

Итак, вы хотите подписать сообщение своим закрытым ключом? В этой ссылке есть пример, возможно, это поможет (код и ссылка ниже). Также обратите внимание, что не всякая подпись является шифрованием. Например, ECDSA, используемый Биткойном, использует операцию подписи, которая принимает случайное число в качестве одного входа, шифрование не выполняется как часть подписи.

https://www.cryptopp.com/wiki/User_Guide:_rsa.h

void Sign()
{
string strContents = "A message to be signed";
//FileSource("tobesigned.dat", true, new StringSink(strContents));

AutoSeededRandomPool rng;

//Read private key
CryptoPP::ByteQueue bytes;
FileSource file("privkey.txt", true, new Base64Decoder);
file.TransferTo(bytes);
bytes.MessageEnd();
RSA::PrivateKey privateKey;
privateKey.Load(bytes);

//Sign message
RSASSA_PKCS1v15_SHA_Signer privkey(privateKey);
SecByteBlock sbbSignature(privkey.SignatureLength());
privkey.SignMessage(
   rng,
   (byte const*) strContents.data(),
   strContents.size(),
   sbbSignature);

   //Save result
   FileSink sink("signed.dat");
   sink.Put((byte const*) strContents.data(), strContents.size());
   FileSink sinksig("sig.dat");
   sinksig.Put(sbbSignature, sbbSignature.size());
}
person Erik Alapää    schedule 14.06.2016
comment
@jwwДа, но мне кажется, что он хочет сделать классический вычисление-хэш-сообщения-›зашифровать-хэш-с-закрытым-ключом. Затем получатель может проверить подлинность сообщения с помощью открытого ключа отправителя, если этот ключ проверен CA и ему доверяют. - person Erik Alapää; 15.06.2016