RSA Signing and Verifying

133 views
Skip to first unread message

Pierre Chanquion

unread,
Oct 1, 2014, 12:44:38 PM10/1/14
to cryptop...@googlegroups.com

I have been using crypto++'s RSA cryptographic methods for a project. Encryption, decryption, signing and verifying all worked well until about two days ago, when I updated xcode and its libraries. Since then signing and verification has completely stopped working returning the error: PK_Signer: key too short for this signature scheme. I am using the recommended 3072 byte key size and all my methods are essentially copies of the RSA examples. 

// -----------------------------------------------

// Save Buffered Transformation to File


void Crypto::RSAKey::Save(const string& filename,  CryptoPP::BufferedTransformation& bt){


    FileSink file(filename.c_str());


       


    bt.CopyTo(file);


    file.MessageEnd();


}




// -----------------------------------------------


// Load Buffered Transformation from file


void Crypto::RSAKey::Load(const string& filename, BufferedTransformation& bt){


    CryptoPP::FileSource file(filename.c_str(), true);


       


    file.TransferTo(bt);


    bt.MessageEnd();


}




// -----------------------------------------------

// Save Public Key to File


RC Crypto::RSAKey::SavePublicKey(const string& fp, RSA::PublicKey& key){


        try {


                CryptoPP::ByteQueue queue;


                key.Save(queue);


               


                Save(fp, queue);


        } catch (CryptoPP::Exception e) {


                LOG(ERROR) << "Error: Failed to Save Public Key to File(" << fp << "): " << e.what() << std::endl;


                return RC::ERR_CRYPTOPP;


        }


        return RC::SUCCESS;


}




// -----------------------------------------------

// Save Private Key to File


RC Crypto::RSAKey::SavePrivateKey(const string& fp, RSA::PrivateKey& key){


        try {


                CryptoPP::ByteQueue queue;


                key.Save(queue);


               


                Save(fp, queue);


        } catch (CryptoPP::Exception e) {


                LOG(ERROR) << "Error: Failed to Save Private Key to File(" << fp << "): " << e.what() << std::endl;


                return RC::ERR_CRYPTOPP;


        }


        return RC::SUCCESS;


}




// -----------------------------------------------

// Load Public Key from file


RC Crypto::RSAKey::LoadPublicKey(const string& fp, RSA::PublicKey& key, bool validate){


        AutoSeededRandomPool rnd;


        try {


                CryptoPP::ByteQueue queue;


                Load(fp, queue);


               


                key.Load(queue);


               


                if(validate)


                        key.Validate(rnd, 3);




        } catch (CryptoPP::Exception e) {


                LOG(ERROR) << "Error: Failed to Load Public Key from File(" << fp << "): " << e.what() << std::endl;


                return RC::ERR_CRYPTOPP;


        }


        return RC::SUCCESS;


}




// -----------------------------------------------

// Load Private Key from File


RC Crypto::RSAKey::LoadPrivateKey(const string& fp, RSA::PrivateKey& key, bool validate){


        AutoSeededRandomPool rnd;


        try {


                CryptoPP::ByteQueue queue;


                Load(fp, queue);


               


                key.Load(queue);




                if(validate)


                        key.Validate(rnd, 3);


               


        } catch (CryptoPP::Exception e) {


                LOG(ERROR) << "Error: Failed to Load Private Key from File(" << fp << "): " << e.what() << std::endl;


                return RC::ERR_CRYPTOPP;


        }


        return RC::SUCCESS;


}




// -----------------------------------------------

// Generate Public+Private Keys and save to file


RC Crypto::RSAKey::generateKeysAndSave(const string &prifp, const string &pubfp){


       


        AutoSeededRandomPool rnd;


        RSA::PrivateKey          pri;


        RC                       r;


       


        pri.GenerateRandomWithKeySize(rnd, KEYSIZE);


       


        RSA::PublicKey pub(pri);


       


        r = SavePrivateKey(prifp, pri);


        if(r != RC::SUCCESS){


                return r;


        }


        r = SavePublicKey(pubfp, pub);


        if(r != RC::SUCCESS){


                return r;


        }


       


        return RC::SUCCESS;


}


// -----------------------------------------------

// Sign Message

RC
Crypto::RSAEncryptor::sign(){

      try {

          AutoSeededRandomPool rng;

              StringSource(msg, true, new SignerFilter(rng, *snr, new StringSink(sig), false));

      }

      catch (CryptoPP::Exception e) {

        LOG(ERROR) << "Error: Unable to sign message. " << e.what() << " - error type("<<e.GetErrorType()<<")" << std::endl;

           return RC::ERR_CRYPTOPP;

       }

      return RC::SUCCESS;

}


// -----------------------------------------------

// Encrypt message

RC
Crypto::RSAEncryptor::encrypt(){

RC r = RC::SUCCESS;

    try {

          // Sign

        if ((r = sign()) != RC::SUCCESS)
                              return r;

              cout << "PRE ENCRYPT" <<endl;

        // Encrypt

       
AutoSeededRandomPool rng;

        StringSource ss(msg, true, new PK_EncryptorFilter(rng, *enc, new StringSink(cphr)));

        // Convert to Hex format
                 if(hex_out){

                 string c = "";

                 StringSource ss2(cphr, true, new CryptoPP::HexEncoder(new StringSink(c)));

                 cphr = c;

              }

      } catch (CryptoPP::Exception e) {

              LOG(ERROR) << "Error: Unable to encrypt message. " << e.what()<< " - error type("<<e.GetErrorType()<<")" << std::endl;

         return RC::ERR_CRYPTOPP;

       }

     

        return r;

}


// -----------------------------------------------

// Decrypt

RC
Crypto::RSADecryptor::decrypt(){

RC r = RC::SUCCESS;

    try {

          // Convert cphr from hex to octal
                      if(hex_in){

                    CryptoPP::HexDecoder decoder;

                  string                           dec;

                  decoder.Attach(new StringSink(dec));

                   decoder.Put((byte*)cphr.data(), cphr.size());

                  decoder.MessageEnd();

                  cphr = dec;

            }

              // Decrypt
             
AutoSeededRandomPool rng;

              StringSource ss(cphr, true, new PK_DecryptorFilter(rng, *dec, new StringSink(msg)));

           // Verify              
                       if ((r = verify()) != RC::SUCCESS)

                    return r;

    } catch (CryptoPP::Exception e) {

              LOG(ERROR) << "Error: Unable to decrypt message." << std::endl;

        return RC::ERR_CRYPTOPP;

       }

     

        return r;

}


// -----------------------------------------------

// Verify

RC
Crypto::RSADecryptor::verify(){

  try {

          StringSource ss(msg+sig, true, new SignatureVerificationFilter(*ver, NULL, SignatureVerificationFilter::THROW_EXCEPTION));

     } catch (CryptoPP::Exception e) {

              LOG(ERROR) << "Error: Unable to verify message."<< std::endl;

          return RC::ERR_CRYPTOPP;

       }

       return RC::SUCCESS;

}


Encryption and Decryption works fine with the generated keys, but signing and verification are both problematic. As the code was working fine before, I am at a loss as to what is wrong... Anyone got any ideas. 

Pierre Chanquion

unread,
Oct 2, 2014, 7:19:35 AM10/2/14
to cryptop...@googlegroups.com
I forgot to mention that I am running on Mavericks and Xcode 6.0.1 with iOS 8 SDK and all the new trimmings with swift etc. 

                LOG(ERROR) << "Error: Failed to Load Public Key from File(" << fp <span style="color: #660;" class="style

...

Jean-Pierre Münch

unread,
Oct 9, 2014, 3:38:46 AM10/9/14
to cryptop...@googlegroups.com
I think i found your problem: The message you want to sign is simply too long.
Try hashing it (f.ex. with SHA3_512) before signing it.
Also note that the maximal message size for signature is about KEYSIZE-SomeSmallConstantLike256.
Please also note: If you really want to use these cryptographic operations in a serious manner, I'd strongly recommend not to use AutoSeededRandomPool.
You should rather use AutoSeededX917C<CIPHER> with AES/Twofish/Serpent or something like that.

BR

JPM

                LOG(ERROR) << "Error: Failed to Load Public Key from File(" << fp <span style="color: #660;" class="style

...

Jeffrey Walton

unread,
Dec 1, 2014, 7:24:12 PM12/1/14
to cryptop...@googlegroups.com

On Wednesday, October 1, 2014 12:44:38 PM UTC-4, Pierre Chanquion wrote:

I have been using crypto++'s RSA cryptographic methods for a project. Encryption, decryption, signing and verifying all worked well until about two days ago, when I updated xcode and its libraries. Since then signing and verification has completely stopped working returning the error: PK_Signer: key too short for this signature scheme. I am using the recommended 3072 byte key size and all my methods are essentially copies of the RSA examples. 
...
 
Encryption and Decryption works fine with the generated keys, but signing and verification are both problematic. As the code was working fine before, I am at a loss as to what is wrong... Anyone got any ideas. 
 
Both of these look problematic to me, but I'm not sure I have the whole picture...
 
****
 
Sign:
  StringSource(msg, true, new SignerFilter(rng, *snr, new StringSink(sig), false));
 
(1) Name your StringSource declaration, and don't use an anonymous declaration. I've seen problems with GCC generating code that causes destructors to run too soon when using anonymous declarations.
 
The '*snr" is a red flag. Its a pointer, and it should be destroyed when the SignerFilter destructor runs. I'm inclined to believe you need something like:
 
  StringSource ss(msg, true, new SignerFilter(rng, new Redirector(*snr), new StringSink(sig), false));
 
This way, `snr` will not be accidentally destroyed too early.
 
It appears `snr` is a class member of Crypto::RSADecryptor. Let `snr` be reclaimed when the destructors for Crypto::RSADecryptor run.
 
*****
 
Encrypt:

   StringSource ss(msg, true, new PK_EncryptorFilter(rng, *enc, new StringSink(cphr)));
 
Same potential issue with `dec`:
 
  StringSource ss(msg, true, new PK_EncryptorFilter(rng, new Redirector(*enc), new StringSink(cphr)));
 
Reply all
Reply to author
Forward
0 new messages