CryptoPP: RSA Signature Scheme causes a Segmentation Fault

349 views
Skip to first unread message

Michele

unread,
Jul 13, 2012, 5:56:58 AM7/13/12
to cryptop...@googlegroups.com
Hi,
I'm working on a simple project on KDevelop (linux Slackware virtual machine, on a Windows 7 host). I have to write a C++ code that : 1) creates a folder; 2) creates a number of text files in that folder; 3) Calculates a hash of each file with RIPEMD128; 4) Signs each hash with RSA ; 5)performs an integrity check if requested.
I'm using Cryptopp 5.6.1 for RIPEMD128 and RSA functions.
I realized and tested points 1) 2) and 3). I realized and tested point 4) following CryptoPP Signature Scheme Wiki: http://www.cryptopp.com/wiki/RSA_Signature_Schemes, and it works fine. Now i'm trying to integrate point 4) with the project and i realized the following "signing function":

CrypoPP::AutoSeededRandomPool RNG;

CryptoPP::RSA::PrivateKey RSAprivate;
CryptoPP::RSA::PublicKey RSApublic ( RSAprivate);

void Signature::SignHash(string Hash)
{
    string Digest = Hash;
    string Signature = "";

    CryptoPP::RSASS<Cryptopp::PSS,CryptoPP::SHA1>::Signer signer(RSAprivate);
    cout << "cotrol point 1";

    CryptoPP::StringSource( Digest,true , new CryptoPP::SignerFilter ( RNG , signer, new CryptoPP::StringSink ( Signature ) ) );
    cout << "control point 2";
}

If i launch the program it prints control point 1 and then it crashes in a Segmentation fault (bin/sh: line 1 3216 Segmentation fault            /root/<directory>/debug/. /src/<project>) !!
I'm a new user of C++ and Slackware and i don't know how to solve this problem ( I think that segmentation fault derives from a memory and/or a C++ contructor/destructor problem....... )

Anyone can help me to solve this fault?

Michele

unread,
Jul 13, 2012, 6:02:48 PM7/13/12
to cryptop...@googlegroups.com
I have not still found a solution, but i found a function called "Redirector" and modified the last instruction this way:

[...]

CryptoPP::StringSink SSink(Signature);   //object StringSink defined
cout << "control point1";

CryptoPP::SignerFilter SFilter(RNG, signer, new Redirector(SSink));      //object SignerFilter defined
cout << "cotrol point2";

CrytpoPP::StringSource(Digest, true, new Redirector( SFilter));        
cout "control point3";

}

It prints control point1 and control point2, then crashes in a Segmentation fault...... I really need to solve this.
Nobody have an idea?

Fraser Hutchison

unread,
Jul 13, 2012, 8:56:48 PM7/13/12
to Michele, cryptop...@googlegroups.com
Hi Michele,

I take it that before you call Signature::SignHash, you are generating your private and public keys?  Something like:

RSAprivate.GenerateRandomWithKeySize(RNG, 2048);
RSApublic = CryptoPP::RSA::PublicKey(RSAprivate);

Cheers,
Fraser.
--
You received this message because you are subscribed to the "Crypto++ Users" Google Group.
To unsubscribe, send an email to cryptopp-user...@googlegroups.com.
More information about Crypto++ and this group is available at http://www.cryptopp.com.


Michele

unread,
Jul 14, 2012, 4:47:51 AM7/14/12
to cryptop...@googlegroups.com, Michele
Yes, before calling Signature::SignHash i generate my keys with that code

CryptoPP::RSA::PrivateKey RSAPrivate;               //private key generating
CryptoPP::RSA::PublicKey RSAPublic(RSAPrivate);        //public key generating

I took this code in a wiki sample and i tested it in a stand alone project and it worked. Your advice is to modify this code with that you wrote?

Cheers, Michele
To unsubscribe, send an email to cryptopp-users-unsubscribe@googlegroups.com.

Fraser Hutchison

unread,
Jul 14, 2012, 9:06:12 AM7/14/12
to Michele, cryptop...@googlegroups.com
Hi Michele,

Yes, you're only constructing the private key here, and then initialising the public key with an invalid private key, which makes the public key invalid also.  The keys are not being generated here.

Inside Signature::SignHash, try adding the following to check:

bool valid_private(RSAprivate.Validate(RNG, 0));
bool valid_public(RSApublic.Validate(RNG, 0));
if (!valid_private || !valid_public) {
  std::cerr << std::boolalpha << "Valid private key: " << valid_private
            << "   Valid public key: " << valid_public << '\n';
  return;
}

So, somewhere before you first use the keys, you need to generate them, as per my previous email.  For more info, see http://www.cryptopp.com/wiki/Keys_and_Formats#Generating.2C_Validating.2C_Saving.2C_and_Loading_Keys

Cheers,
Fraser.
To unsubscribe, send an email to cryptopp-user...@googlegroups.com.

Michele

unread,
Jul 14, 2012, 10:02:33 AM7/14/12
to cryptop...@googlegroups.com, Michele
Hi Fraser, you are right!!

I've just tried ( sorry for my english) your "checking code" and the result is false twice. So i modified my code with that you suggested, in previous email:

[...]

1. RSA::PrivateKey RSAprivate;
2. RSAprivate.GenerateRandomWithKeySize(RNG,2048);
3. RSA::PublicKey RSApublic(RSAprivate);

[...]

Now it can't compile because of an error in 2.line : "expected contructor, destructor, or type conversion before ' . ' token". Now i'm reading keys and formats to fix this... thanks for your help!

Cheers, Michele.

Michele

unread,
Jul 14, 2012, 11:37:38 AM7/14/12
to cryptop...@googlegroups.com, Michele
OK, now i'm sure that i generate a pair RSAprivate/RSApublic of valid keys. My new signing function is:

void Sign::SignHash( string Digest)
{
RSASS < PSS , SHA1 >::Signer Signer(RSAprivate);

StringSource( Digest, true, new SignerFilter( RNG, Signer, new StringSink(Sign ) ) );
}

It crashes again in a Segmentation fault; i tried to fix this using Redirector (as my previous post)...another Segmentation fault... 

David Irvine

unread,
Jul 14, 2012, 12:11:47 PM7/14/12
to Michele, cryptop...@googlegroups.com
Are you sure you are getting a segfault and not an exception (possibly from the RNG, I am not sure how you are using this). Could you post the frame stack or perhaps a mini (smallest possible) version of a program that exposes this issue. 

Best Regards
David Irvine

To unsubscribe, send an email to cryptopp-user...@googlegroups.com.

Ingo Naumann

unread,
Jul 14, 2012, 12:47:49 PM7/14/12
to Michele, cryptop...@googlegroups.com
Dear Michele,

How do you initialize the string variable "Sign"?

And, BTW, one comment on item 4) in your first mail. The command you
are using in your code is for signing a message. The message gets
hashed and then the RSA function is applied to this hash (simplified
explanation). In your case, your RIPEMD128 hash (stored in "Digest")
will be re-hashed with a SHA1 and then RSA'ed. If that's what you
want, you are on the right track.

Ingo

Michele

unread,
Jul 14, 2012, 12:53:06 PM7/14/12
to cryptop...@googlegroups.com, Michele
Hi David,

this is the error i read in the shell: /bin/sh: line 1: 5233 Segmentation fault        /root/<myfolder>/debug/ . /src/ <myproject>. I'm new user of C++ so it could be not a segfault, but i'm not able to understand if it is or not. The class Sign is:

class Sign
{
private:
RSA::PrivateKey RSAprivate;
string DigitalSIgn;
public:
string Digest;
AutoSeededRandomPool RNG;
RSA::PublicKey RSApublic(RSA::PrivateKey);

contructor
destructor

void HashCalc(string);
void KeyGen();
void SignHash();
};

This class is used by a cpp file where i implemented those function, in summary:

void SIgn::HashCalc()
{
[...]  //calculate the Digest of a text and transform it in exadecimal format

Sign objectsign; 

if(keygen == false)               //call KeyGen only once
{
objectsign.KeyGen();
keygen = true;
}

objectsign.SignHash(Digest);
}

void Sign::KeyGen()
{
AutoSeededRandomPool RNG;
RSA::PrivateKey RSAprivate;
RSAprivate.GenerateRandomWithKeySize(RNG,1536);
RSA::PublicKey RSApublic(RSAprivate);

keygen=true;
}

void Sign::SignHash()
{
// here is the code i wrote in previous post
}

I hope this is what you asked....

David Irvine

unread,
Jul 14, 2012, 1:08:07 PM7/14/12
to Michele, cryptop...@googlegroups.com
It seems you may not be using the RNG correctly. It's generally preferred to have on per thread at least (or a global if you like).  i.e. in test.cpp you will see how this was done. In your case I am not sure you should have a  class member RNG used as you have. This can cause all sorts of issues with threading and protection of the os provided generator etc. 
 
static OFB_Mode<AES>::Encryption s_globalRNG;

RandomNumberGenerator & GlobalRNG()
 {
         return s_globalRNG;
 }
 

Best Regards
David Irvine

Michele

unread,
Jul 14, 2012, 1:08:51 PM7/14/12
to cryptop...@googlegroups.com, Michele
Hi Ingo,
what i want is sign the RIPEMD128 hash and the sign it. I choose RSA because it is most common and available in cryptopp, and its signature scheme use SHA1...

Variable string Sign is the end of StringSink, i define it in class Sign (chek my last post) and i initialize that so:

void SignHash()
{
DigitalSign = "";

Ingo Naumann

unread,
Jul 14, 2012, 1:58:45 PM7/14/12
to Michele, cryptop...@googlegroups.com
I believe that you should declare the variable "Sign" in your method
"SignHash" and maybe you should not have named it "Sign" because you
are using that for some other things already.

I am referring to the variable inside the "StringSink" command. So,
tru to rename that into "result", or whatever, and initialize it with
"string result;" before using it: "StringSink(result)".
> --
> You received this message because you are subscribed to the "Crypto++ Users"
> Google Group.
> To unsubscribe, send an email to
> cryptopp-user...@googlegroups.com.

Michele

unread,
Jul 14, 2012, 3:21:57 PM7/14/12
to cryptop...@googlegroups.com, Michele
Yes, i've done (i wrote my method in last post and called that variable DigitalSign) but it Segfault .... However thanks.
Now I'm reading the link that David posted.

Michele

unread,
Jul 14, 2012, 3:44:24 PM7/14/12
to cryptop...@googlegroups.com, Michele
Ok David, now i'm deleting RNG from class members. I'm not sure that I've understand your example but i will try...

Michele

unread,
Jul 15, 2012, 8:37:34 AM7/15/12
to cryptop...@googlegroups.com, Michele
Done!! Now item 4) of my first post works fine. 

Here is a part of my Signature.cpp :

static CryptoPP::AutoSeededRandomPool rng;               //this fixed rng troblues as David Irvine suggested

void Signature::SignHash()                   //method declared in my Signature.h file
{
[...]
static RSA::PrivateKey RSAprivate;                                 
RSAprivate.GenerateRandomWithKeySize(rng,1536);

static RSA::PublicKey RSApublic;                                     //keys created inside the method as Fraser suggested
                                                                                      //and not declared inside the class as Ingo Naumann suggested
[...]
}
I'm not sure that the key pair is generated only once ( as I want). I'm going to verify that key pair is not re-generated every time i call the method , because I have to sign every file with the same RSAprivate.

Thanks Everybody!!
Now I'm going to work on item 5) of my first post: perform the integrity check of files (created/hashed/signed). I think that, because of I declared my key pair as local static variables, I must implement a method Signature::IntegrityCheck() inside my Signature.cpp, because outside of it the keys will not be visible.......

David Irvine

unread,
Jul 15, 2012, 10:13:48 AM7/15/12
to Michele, cryptop...@googlegroups.com
No worries. 

If you want the same keys though you could create a static method to return the generated key. As it stands you will be regenerating the key every time (I tink, at least if you always run GenerateKeys method which will overwrite the contents of the static keys). It's maybe best to create keys and pass them into your object (const) if you want to use them as I think you do. That way you can control which keys are in use by the object and recreate additional objects when you work with multiple keys. 

You will, perhaps then find it easier to create checking objects etc. with the same key pair.

Best Regards
David Irvine




--
You received this message because you are subscribed to the "Crypto++ Users" Google Group.
To unsubscribe, send an email to cryptopp-user...@googlegroups.com.

Michele

unread,
Jul 16, 2012, 8:32:39 AM7/16/12
to cryptop...@googlegroups.com, Michele
After some attempts I modified the general structure of the project. In summary:

int main()
{
   Signature Keys;   
   Keys.KeyGen();

   Menu Start;        //object with options for creating/filling files
   Start.FileGen();  
}

//FileGen() save file and calls CalcHash();CalcHash() calls SignHash();SignHash() calls LoadPrivate(), gets the private key and finally signs the digest calculated. 

class Signature               //in signature.h
{public:
   string Digest;
   string DigSignature;
constructor
destructor 
  static void KeyGen();
   void SavePrivate(string,RSA::PrivateKey);
   void LoadPrivate();
   void CalcHash(string);
   void SignHash();
};
//I will define also SavePublic() , LoadPublic() and VerifySignature() (when signing process will work)

static AutoSeededRandomPool rng;
void Signature::KeyGen()
{
   static RSA::PrivateKey PV;
   PV.GenerateRandomWithKeySize(rng,1536);
   static RSA;;PublicKey PU;
// validation code 
   string saving;
   saving = "//path";
   Signature Saving;
   Saving.SavePV(saving, PV);   
}
void Signature::SavePV(const string saving, RSA::PrivateKey PV)
{
  ByteQueue queue;
  PV.Save(queue);
  Save(saving, queue);
}

Now I'm in troubles because SavePV doesn't compile and I don't know why. I think that I pass the parameters in a wrong way...... I need some advices....


Best Regards
David Irvine




To unsubscribe, send an email to cryptopp-users-unsubscribe@googlegroups.com.

David Irvine

unread,
Jul 16, 2012, 9:49:28 AM7/16/12
to Michele Gucciardo, Crypto++ Users
PV.Save(your transfomration); should do the trick. 
See this page 

Best Regards
David Irvine


On Mon, Jul 16, 2012 at 2:39 PM, Michele Gucciardo <michelegu...@gmail.com> wrote:
Done, now my class have this new member

class Signature
{
[..]
   static RSA::PrivateKey PV;
[..]
}
But this line

Save(saving,queue);

doesn't compile, because "Save is not in this scope" (i tried to make SavePV a static class function but it doesn't work). Maybe I have not understand your advice...

2012/7/16 David Irvine <david....@maidsafe.net>
 PV.Save(queue);

This item is not available in the scope you are calling it in. PV is in the KeyGen scope, you should make it a static class member in this case.


Best Regards
David Irvine



To unsubscribe, send an email to cryptopp-user...@googlegroups.com.

Michele

unread,
Jul 21, 2012, 7:59:41 AM7/21/12
to cryptop...@googlegroups.com, Michele Gucciardo
After some attempts I solved my problems with the key pair. At now, I can save/load and pass them to Signer/Verifier without faults.

The Verifiy functions fails:

void Signature::VerifySignature()
{
[...]      //load the public key, calculate the digest of the file (checked equal to that calculated in "signin function" ), load the signature
  try
  {
  StringSource SS( digest + signature, true, new       SignatureVerificationFilter(Verifier, new StringSink(recovered), SignatureVerificationFilter::THROW_EXCEPTION | SignatureVerificationFilter::PUT:MESSAGE));
  }
  catch(Exception e)
  {
  cerr << "error: " << e.what() << endl;
  }

}

It fails because: "digital signature not valid". I'm sure signature is valid because, at now, I run the program with only one file (testing). The variables signature, digest and recovered are public class members.

The variable signature, the one that causes the fault, is first saved in a file, when my "signing function" ends, by a "saving function":

void Signature::SaveSignature(string signed)
{
SIGNATURE = signed;

fstream savingfile;
savingfile.open("./Signatures", fstream::out | fstream::binary);       //SIGNATURE is local variable of a "saving function"
savingfile.write(SIGNATURE.c_str(), SIGNATURE.size());
savingfile.close();
}

Then is assigned to the variable signature , by a "loading function":

string Signature::LoadSignature()
{

fstream loadingfile;
loadingfile.open("./Signatures", fstream::in | fstream::binary);
getline(loadingfile, SIGNATURE);
loadingfile.close();

}

I think that troubles could derive from saving and loadind the signature, something about its format
I really need to fix this. So I will appreciate every suggestion that could take me on the right track....... 

David Irvine

unread,
Jul 21, 2012, 10:09:22 AM7/21/12
to Michele, cryptop...@googlegroups.com
All you need is in the download RSA-SSA-Filter-Test.zip - which is one this page http://www.cryptopp.com/wiki/RSA. That shoudl show you the FileFilter usage in some detail. 

Best Regards
David Irvine


maidsafe.net Limited is a limited liability company incorporated in Scotland with number SC297540. VAT Registered 889 0608 77. Registered Office: 72 Templehill, Troon, KA10 6BE.
Telephone Scotland: +44 1292 750020.





To unsubscribe, send an email to cryptopp-user...@googlegroups.com.

Michele

unread,
Jul 21, 2012, 10:48:17 AM7/21/12
to cryptop...@googlegroups.com, Michele
Ok David, I've read the sample but there's nothing about the signature..... So do you think the fault is still caused by the key pair?

Michele

unread,
Jul 23, 2012, 2:15:15 PM7/23/12
to cryptop...@googlegroups.com, Michele

Finally I found the bug:
The SignerFilter generate ever a signature of 192 bytes in size. SignatureVerificationFilter expects a signature exactly  192 bytes in size, if it is more or less the verify fails beacuse "digital signature is not valid".
Here is how I save the key:

cout << SIGNATURE.size() << "bytes\n";    //check that SIGNATURE generated is ever 192 bytes

fstream f1;

f1.open("./Signatures", fstream::out | fstream::binary);
f1.write(SIGNATURE.c_str(),SIGNATURE.size());          //if i check the file created when, after the program ends running, is is EVER 192 bytes in size
f1.close();

fstream f2;

f1.open("./Signatures", fstream::in | fstream::binary);
getline(f1,signature);                                                          //it reads ever something
f1.close();

cout  << signature.size() <<"bytes\n";                //sometimes this is not 192 bytes, then the verify fails

I need a way to understand WHY the reading of the files fails. Maybe something goes wrong with the getline?
Any ideas?

Christopher Head

unread,
Jul 23, 2012, 6:27:20 PM7/23/12
to cryptop...@googlegroups.com
getline() reads a line. Perhaps the signature is stored in binary? It
could then contain a newline, so getline() would stop reading there.
You probably want fstream::read() instead of getline().

Chris

Michele

unread,
Jul 27, 2012, 8:01:42 AM7/27/12
to cryptop...@googlegroups.com
Yes, I modified the program with read() instead of getline(). This works sometimes, I'm going to explain better:

I save the signature, in "signing method", calculated with RSASS<PSS,SHA1>  as a string object , this way:

fstream f1;                                            //local variable

f1.open("./Signatures", fstream::out | fstream::binary)         // I don't use fstream::app because I'm testing with only one file

//I use is_open() to check that the file is really open

f1.write(signature.c_str(), signature.size());                               // signature size is always 192 bytes, it is a public class member variable
f1.close();

I load the signature, in "checking method" this way:

fstream f2;
int size;                                                                                        //local variables

f2.open("./Signatures", fstream::in | fstream::binary)

//I use is_open() to check the file is really open

f2.seekg(0, ios::end);
size = tellg();                                                                             
cout << "size" << size << "bytes\n";                                             //it checks the size of the file "Signatures": always 192 bytes; because every time I sign a new file the new signature overwrite the old one

f2.seekg(0, ios::beg);                                             //get pointer back to the beginning of the file

char buffer[size];                                                     //local char array, dimensionated with the size of the signature (always 192 bytes)
int i;

for(i = 0; i< size; i++)
{
        buffer[i] = 0;                                                    //buffer initialization
}

f2.read(buffer, size);                                              
cout << f2.gcount() << "bytes\n";                         //it reads always:192 bytes
f2.close();

digsignature = "";                                                  //public class member variable
digsignature = buffer;                                           
cout << digsignature << "bytes\n";                    //The digital signature is valid only if digsignature = 192 bytes

try
{
StringSource SS(esadigest + buffer, true, new SignatureVerificationFilter(Verifier, new StirngSink(recovered), SignatureVerificationFilter::EXCEPTION | SignatureVerificationFilter::PUT_MESSAGE));

// I use buffer (always 192 bytes) in SS, but It works only if digsignature = 192 bytes. Sometimes it has a value less or more of 192 bytes (why???) 
}
catch(CryptoPP::Exception e)
{
        cerr << "ERROR:" << e.what();
}

e.what() returns: digital signature is not valid; esadigest is checked the same of that calculated; my key pair is checked valid and I don't think its format could make problems.

So the digital signature is the problem, something in the way I save/read it goes wrong. I am very close to finish this project, but I can't until I fix this.

Maybe I should build a function that transforms bytes to char and char to byte to deal with the signature? And in this case, how should I save the signature?

Any suggestions?

Michele

Christopher Head

unread,
Jul 27, 2012, 2:34:07 PM7/27/12
to cryptop...@googlegroups.com
Well here's the problem right here: when you assign a char array to an std::string using operator=, as you do in "digsignature=buffer;", the assignment operator treats the char array as a C string, meaning NUL-terminated; if your signature happened to contain NUL bytes, the resulting std::string would be truncated. You should use one of the mechanisms that allows specifying the length of the data instead; for example, construct digsignature as follows:

std::string digsignature(buffer, size);

Chris


On 2012-07-27, at 5:01, Michele <michelegu...@gmail.com> wrote:
Reply all
Reply to author
Forward
0 new messages