#include #include #include #include #include "crypto++/rsa.h" #include "crypto++/elgamal.h" #include "crypto++/osrng.h" #include /** * Programa de prueba de Cryptopp para RSA y El Gamal * * https://www.cryptopp.com/wiki/RSA_Cryptography * * * Es necesario instalar los siguientes paquetes: * libcrypto++9 y libcrypto++-dev * */ using namespace CryptoPP; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); //return a.exec(); /////////////////////////////////////// // Pseudo Random Number Generator AutoSeededRandomPool rng; /////////////////////////////////////// // Generate Parameters InvertibleRSAFunction params; //QTime timer; QElapsedTimer timer; timer.start(); params.GenerateRandomWithKeySize(rng, 4096); int runtime = timer.elapsed(); //gets the runtime in ms qDebug(qPrintable("key generation: "+QString::number(runtime)+" ms")); /////////////////////////////////////// // Generated Parameters const Integer& n = params.GetModulus(); const Integer& p = params.GetPrime1(); const Integer& q = params.GetPrime2(); const Integer& d = params.GetPrivateExponent(); const Integer& e = params.GetPublicExponent(); /////////////////////////////////////// // Dump std::cout << "RSA Parameters:" << std::endl; std::cout << " n: " << n << std::endl; std::cout << " p: " << p << std::endl; std::cout << " q: " << q << std::endl; std::cout << " d: " << d << std::endl; std::cout << " e: " << e << std::endl; std::cout << std::endl; /////////////////////////////////////// // Create Keys RSA::PrivateKey privateKey(params); RSA::PublicKey publicKey(params); // también se puede hacer así: // RSA::PrivateKey privateKey; // privateKey.GenerateRandomWithKeySize(rng, 3072); // RSA::PublicKey publicKey(privateKey); std::string s; CryptoPP::FileSource file( "message.txt", true, new StringSink( s ) ); std::cout << s << std::endl; std::cout << s.size() << std::endl; //////////////////////////////////////////////// // Secret to protect //static const int SECRET_SIZE = 16; //SecByteBlock plaintext( SECRET_SIZE ); //memset( plaintext, 'A', SECRET_SIZE ); SecByteBlock plaintext( (const unsigned char *) s.data(), s.size() ); //////////////////////////////////////////////// // Encrypt RSAES_OAEP_SHA_Encryptor encryptor( publicKey ); // Now that there is a concrete object, we can validate assert( 0 != encryptor.FixedMaxPlaintextLength() ); qDebug("encryptor.FixedMaxPlaintextLength(): %zu", encryptor.FixedMaxPlaintextLength()); // vale la pena leer la siguiente pregunta: // https://stackoverflow.com/questions/2033809/im-using-crypto-for-rsa-encryption-my-plain-text-exceeds-fixedmaxplaintextle // // para RSA mas de 470 bytes hace que el asser que sigue falle assert( plaintext.size() <= encryptor.FixedMaxPlaintextLength() ); // Create cipher text space size_t ecl = encryptor.CiphertextLength( plaintext.size() ); assert( 0 != ecl ); SecByteBlock ciphertext( ecl ); timer.start(); encryptor.Encrypt( rng, plaintext, plaintext.size(), ciphertext ); runtime = timer.elapsed(); //gets the runtime in ms qDebug(qPrintable("RSA encryption time: "+QString::number(runtime)+" ms")); //////////////////////////////////////////////// // Decrypt RSAES_OAEP_SHA_Decryptor decryptor( privateKey ); // Now that there is a concrete object, we can check sizes assert( 0 != decryptor.FixedCiphertextLength() ); assert( ciphertext.size() <= decryptor.FixedCiphertextLength() ); // Create recovered text space size_t dpl = decryptor.MaxPlaintextLength( ciphertext.size() ); assert( 0 != dpl ); SecByteBlock recovered( dpl ); timer.start(); DecodingResult result = decryptor.Decrypt( rng, ciphertext, ciphertext.size(), recovered ); runtime = timer.elapsed(); //gets the runtime in ms qDebug(qPrintable("RSA decryption time: "+QString::number(runtime)+" ms")); // More sanity checks assert( result.isValidCoding ); assert( result.messageLength <= decryptor.MaxPlaintextLength( ciphertext.size() ) ); // At this point, we can set the size of the recovered // data. Until decryption occurs (successfully), we // only know its maximum size recovered.resize( result.messageLength ); // SecByteBlock is overloaded for proper results below assert( plaintext == recovered ); std::cout << "Recovered plain text" << std::endl; /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// // ejemplo de El Gamal // https://www.cryptopp.com/wiki/ElGamal std::cout << "Generating private key. This may take some time..." << std::endl; ElGamal::Decryptor gamalDecryptor; gamalDecryptor.AccessKey().GenerateRandomWithKeySize(rng, 2048); const ElGamalKeys::PrivateKey& gamalPrivateKey = gamalDecryptor.AccessKey(); ElGamal::Encryptor gamalEncryptor(gamalDecryptor); const PublicKey& gamalPublicKey = gamalEncryptor.AccessKey(); //////////////////////////////////////////////// // Secret to protect //static const int SECRET_SIZE = 16; //SecByteBlock plaintext( SECRET_SIZE ); //memset( plaintext, 'A', SECRET_SIZE ); //////////////////////////////////////////////// // Encrypt // Now that there is a concrete object, we can validate assert( 0 != gamalEncryptor.FixedMaxPlaintextLength() ); qDebug("gamalEncryptor.FixedMaxPlaintextLength(): %zu", gamalEncryptor.FixedMaxPlaintextLength()); // para ElGamal mas de 253 bytes hace que el asser que sigue falle assert( plaintext.size() <= gamalEncryptor.FixedMaxPlaintextLength() ); // Create cipher text space //size_t ecl = gamalEncryptor.CiphertextLength( plaintext.size() ); size_t ecl2 = gamalEncryptor.CiphertextLength( plaintext.size() ); assert( 0 != ecl2 ); SecByteBlock ciphertext2( ecl2 ); timer.start(); gamalEncryptor.Encrypt( rng, plaintext, plaintext.size(), ciphertext2 ); runtime = timer.elapsed(); //gets the runtime in ms qDebug(qPrintable("ElGamal encryption time: "+QString::number(runtime)+" ms")); //////////////////////////////////////////////// // Decrypt // Now that there is a concrete object, we can check sizes assert( 0 != gamalDecryptor.FixedCiphertextLength() ); assert( ciphertext2.size() <= gamalDecryptor.FixedCiphertextLength() ); // Create recovered text space //size_t dpl = gamalDecryptor.MaxPlaintextLength( ciphertext2.size() ); size_t dpl2 = gamalDecryptor.MaxPlaintextLength( ciphertext2.size() ); assert( 0 != dpl2 ); SecByteBlock recovered2( dpl2 ); timer.start(); //DecodingResult result = gamalDecryptor.Decrypt( rng, ciphertext, ciphertext.size(), recovered ); DecodingResult result2 = gamalDecryptor.Decrypt( rng, ciphertext2, ciphertext2.size(), recovered2 ); runtime = timer.elapsed(); //gets the runtime in ms qDebug(qPrintable("ElGamal decryption time: "+QString::number(runtime)+" ms")); // More sanity checks assert( result2.isValidCoding ); assert( result2.messageLength <= gamalDecryptor.MaxPlaintextLength( ciphertext2.size() ) ); // At this point, we can set the size of the recovered // data. Until decryption occurs (successfully), we // only know its maximum size recovered2.resize( result2.messageLength ); // SecByteBlock is overloaded for proper results below assert( plaintext == recovered2 ); // If the assert fires, we won't get this far. if(plaintext == recovered2) std::cout << "Recovered plain text" << std::endl; else std::cout << "Failed to recover plain text" << std::endl; qDebug("exit"); }