Bitcoin Forum

Bitcoin => Bitcoin Technical Support => Topic started by: redPanda on February 25, 2015, 08:29:12 PM



Title: SHA-256 in c++ with crypto++
Post by: redPanda on February 25, 2015, 08:29:12 PM
Hi

I would like to use the crypto++ librairy to create a transaction from scratch.
My first question is why this code doesn't work:

#include "crypto++/cryptlib.h"
#include "crypto++/sha.h"
#include "crypto++/hex.h"
#include <iostream>
using namespace std;

int main () {
   string myString    = string("abc");
   string myStringSHA = SHA256(myString);
   std::cout << "SHA(abc): " << myStringSHA << std::endl;
}

the output is:
SHA(abc): #x####AA@###"##a##z###a####

I have the right result with the following:

#include "crypto++/cryptlib.h"
#include "crypto++/sha.h"
#include "crypto++/hex.h"
#include <iostream>
using namespace std;

string SHA256(string);

int main () {
   CryptoPP::SHA256 hash;
    byte digest[ CryptoPP::SHA256::DIGESTSIZE ];
     string message = "abc";

    hash.CalculateDigest( digest, reinterpret_cast<byte*>(&message[0]), message.length() );
 
    CryptoPP::HexEncoder encoder;
     std::string output;
    encoder.Attach( new CryptoPP::StringSink( output ) );
        encoder.Put( digest, sizeof(digest) );
    encoder.MessageEnd();

    std::cout << " " << std::endl << "SHA(abc): " << output << std::endl;
}


string SHA256(string data)
{
    byte const* pbData = (byte*) data.data();
    unsigned int nDataLen = data.size();
    byte abDigest[CryptoPP::SHA256::DIGESTSIZE];

    CryptoPP::SHA256().CalculateDigest(abDigest, pbData, nDataLen);

    return string((char*)abDigest);
}

the output is:
SHA(abc): BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD
which is right according to:
http://www.xorbin.com/tools/sha256-hash-calculator

Thanks


Title: Re: SHA-256 in c++ with crypto++
Post by: Nikinger on February 25, 2015, 09:18:53 PM
Looks like that you forget to hex encode it.

Your result from your first try (#x####AA@###"##a##z###a####) looks like the raw byte representation of BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD but with #-replaced unprintable.

Code:
.. .x .. .. .. .. .. .. .A .A .@ .. .. .. ." .# .. .. .a .. .. .. .z .. .. .. .. .a .. .. .. ..
BA 78 16 BF 8F 01 CF EA 41 41 40 DE 5D AE 22 23 B0 03 61 A3 96 17 7A 9C B4 10 FF 61 F2 00 15 AD


Title: Re: SHA-256 in c++ with crypto++
Post by: redPanda on March 09, 2015, 07:04:05 PM
I made a test with this code:

Code:
int main () {
string myString    = string("abc");
string myStringSHA = SHA256(myString);
cout << "size of myStringSHA: " << myStringSHA.size() << endl;
cout << "myStringSHA: --" << myStringSHA << "---" << "--" << endl;

    for (std::size_t i = 0; i < myStringSHA.size(); ++i) {
        cout << i << ": ----" << myStringSHA[i] << "----  " << bitset<32>(myStringSHA[i]) << endl;
    }
   
    for (std::size_t i = 0; i < myStringSHA.size(); ++i) {
        bitset<8> myStringSHAbit(myStringSHA[i]);
        cout << hex << myStringSHAbit.to_ulong();
    }
    cout << endl;
    // the right answer is
    cout << "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" << endl;
}
and I got this result:

Code:
size of myStringSHA: 29
myStringSHA: --#x####AA@###"##a##z###a####--
0: ----#----  11111111111111111111111110111010
1: ----x----  00000000000000000000000001111000
2: --------  00000000000000000000000000010110
3: ----#----  11111111111111111111111110111111
4: ----#----  11111111111111111111111110001111
5: --------  00000000000000000000000000000001
6: ----##---  11111111111111111111111111001111
7: ----###--  11111111111111111111111111101010
8: ----A----  00000000000000000000000001000001
9: ----A----  00000000000000000000000001000001
10: ----@----  00000000000000000000000001000000
11: ----##---  11111111111111111111111111011110
12: ----]----  00000000000000000000000001011101
13: ----#----  11111111111111111111111110101110
14: ----"----  00000000000000000000000000100010
15: ----#----  00000000000000000000000000100011
16: ----#----  11111111111111111111111110110000
17: --------  00000000000000000000000000000011
18: ----a----  00000000000000000000000001100001
19: ----#----  11111111111111111111111110100011
20: ----#----  11111111111111111111111110010110
21: --------  00000000000000000000000000010111
22: ----z----  00000000000000000000000001111010
23: ----#----  11111111111111111111111110011100
24: ----#----  11111111111111111111111110110100
25: --------  00000000000000000000000000010000
26: ----#----  11111111111111111111111111111111
27: ----a----  00000000000000000000000001100001
28: ----####-  11111111111111111111111111110010
ba7816bf8f1cfea414140de5dae2223b0361a396177a9cb410ff61f2
ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
Why the trailing "----" are reduced to 3, 2 or 1 for some characters ?
And why there are 8 missing characters in my final answer ?


Title: Re: SHA-256 in c++ with crypto++
Post by: hhanh00 on March 10, 2015, 12:29:17 AM
- The missing characters are in the "control character" range (1-1F), they are not displayed but not replaced by # either. You don't need to cast char to bitset<8>.
- The string constructor for a char* stop at the first null character because it takes a C-string. You can use string(char *, 32) or keep it as char *.


Title: Re: SHA-256 in c++ with crypto++
Post by: redPanda on March 10, 2015, 03:17:21 PM
Here is my last try:

Code:
int main () {
string myString    = string("abc");
string myStringSHA = SHA256(myString);
   
    for (size_t i = 0; i < myStringSHA.size(); ++i) {
        printf("%02x ", myStringSHA[i]);
    }

    cout << endl;
    // the right answer is
    cout << "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" << endl;
}

the output is
Code:
ffffffba 78 16 ffffffbf ffffff8f 01 ffffffcf ffffffea 41 41 40 ffffffde 5d ffffffae 22 23 ffffffb0 03 61 ffffffa3 ffffff96 17 7a ffffff9c ffffffb4 10 ffffffff 61 fffffff2 
ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad

if I remove all the trailling f and the spaces, I come with:
Code:
ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f2
ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad

question 1) why do I have all those 'f' ?
question 2) the first missing character is 00 which I guess is the NULL character,
so I do I tell to c++ to interpret this character as '00' ?


Title: Re: SHA-256 in c++ with crypto++
Post by: CIYAM on March 10, 2015, 03:28:11 PM
Let me see if I can "put you out of your misery" by creating a simple "print" function for you:

Code:
string print_hash( const string& hash )
{
   ostringstream outs;

   if( hash.length( ) == 32 )
   {
      for( size_t i = 0; i < 32; i++ )
         outs << hex << setw( 2 ) << setfill( '0' ) << ( unsigned )hash[ i ];
   }

   return outs.str( );
}

You'll need to add the #include <sstream> and #include <iomanip> but that should solve your problem.

You might want to throw an exception if the length isn't 32 (it will just return a blank string in that case as is).


Title: Re: SHA-256 in c++ with crypto++
Post by: redPanda on March 10, 2015, 04:42:32 PM
if I use your code

Code:
    cout << print_hash(myStringSHA) << endl;
   
    for (size_t i = 0; i < myStringSHA.size(); ++i) {
        printf("%02x", myStringSHA[i]);
    }
I get exactly the same as before:
Code:
ffffffba7816ffffffbfffffff8f01ffffffcfffffffea414140ffffffde5dffffffae2223ffffffb00361ffffffa3ffffff96177affffff9cffffffb410ffffffff61fffffff2
ffffffba7816ffffffbfffffff8f01ffffffcfffffffea414140ffffffde5dffffffae2223ffffffb00361ffffffa3ffffff96177affffff9cffffffb410ffffffff61fffffff2
and the size of myStringSHA is still 29 and not 32...


Title: Re: SHA-256 in c++ with crypto++
Post by: CIYAM on March 10, 2015, 04:48:33 PM
if I use your code

Code:
    cout << print_hash(myStringSHA) << endl;
    
    for (size_t i = 0; i < myStringSHA.size(); ++i) {
        printf("%02x", myStringSHA[i]);
    }
I get exactly the same as before:
Code:
ffffffba7816ffffffbfffffff8f01ffffffcfffffffea414140ffffffde5dffffffae2223ffffffb00361ffffffa3ffffff96177affffff9cffffffb410ffffffff61fffffff2
ffffffba7816ffffffbfffffff8f01ffffffcfffffffea414140ffffffde5dffffffae2223ffffffb00361ffffffa3ffffff96177affffff9cffffffb410ffffffff61fffffff2
and the size of myStringSHA is still 29 and not 32...

So your problem is the string not the output of the string.

If you feed my function the actual "binary digest" it'll work perfectly.


Title: Re: SHA-256 in c++ with crypto++
Post by: redPanda on March 10, 2015, 06:31:27 PM
from wikipedia:

"The input data is often called the message, and the hash value is often called the message digest or simply the digest."

so my digest is "myStringSHA" :

string myStringSHA = SHA256(myString);

but it is defined as a string. How can I convert it to "binary digest" ?


Title: Re: SHA-256 in c++ with crypto++
Post by: CIYAM on March 10, 2015, 06:34:18 PM
The output you are getting "is the digest in binary form".

So just pass that to the function I gave you and you should see your hash in ASCII form.



Title: Re: SHA-256 in c++ with crypto++
Post by: redPanda on March 10, 2015, 07:21:19 PM
OK, I put my output in your function and I get nothing,
The size of that output is 29. If I change 32 for 29 in your
function I have a (wrong) result. I still don't see what's wrong.
Code:
int main ()
{
string myString    = string("abc");
string myStringSHA = SHA256(myString);

cout << print_hash(myStringSHA) << endl;
}
Quote
If you are just determined to be an idiot then no-one can help you
Maybe, I spent too much time the last years, doing my PhD in physics :-\


Title: Re: SHA-256 in c++ with crypto++
Post by: redPanda on March 10, 2015, 08:47:05 PM
OK, Thanks a lot, I get the point.
By the way, I also appreciate your link to the ignore list...


Title: Re: SHA-256 in c++ with crypto++
Post by: hhanh00 on March 11, 2015, 12:03:03 AM
 Replace
 return string((char*)abDigest);

With   return string((char*)abDigest, 32);

String can store binary data.


Title: Re: SHA-256 in c++ with crypto++
Post by: hhanh00 on March 11, 2015, 04:48:59 AM
The output you are getting "is the digest in binary form".

So just pass that to the function I gave you and you should see your hash in ASCII form.

(delete your fucking code and use what I gave you)

If you are just determined to be an idiot then no-one can help you (maybe give up on trying to write software).

Or maybe *you* should stop being condescending and at least provide good code.

Your function has the same bug as his and then some.
Code:
#include <sstream>
#include <iomanip>

string print_hash( const string& hash )
{
   ostringstream outs;

   if( hash.length == 32 )
   {
      for( size_t i = 0; i < 32; i++ )
         outs << hex << setw( 2 ) << setfill( '0' ) << ( unsigned )hash[ i ];
   }

   return outs.str( );
}

1. length is a method, not a field. It should be length()
2. you are missing the using clauses. At least 'using namespace std;'
3. not a bug per say but misleading name: 'print_hash' does not print the hash. It converts it to a hex string.
4. the reason why the output have sometimes ff is because of the (unsigned) cast. It casts the char to (unsigned int). Since there is no
direct conversion path, it goes char -> int -> unsigned int. When the char is negative (because >= 0x80), the promotion to int preserves the negative sign. The proper way is to do in two steps
Code:
(int)(unsigned char)hash[i]

Or in the OP's way
Code:
printf("%02x", (unsigned char)myStringSHA[i]);





Title: Re: SHA-256 in c++ with crypto++
Post by: CIYAM on March 11, 2015, 06:24:50 AM
Or maybe *you* should stop being condescending and at least provide good code.

I was not meaning to be condescending (but admittedly got a bit frustrated - I have now removed the offensive comments from my post).

Here is the fixed code (that I have tested with g++) that will work assuming that your string is the binary hash:

Code:
#include <iomanip>
#include <sstream>
#include <iostream>

using namespace std;

string print_hash_as_hex( const string& hash )
{
   ostringstream outs;

   if( hash.length( ) == 32 )
   {
      for( size_t i = 0; i < 32; i++ )
         outs << hex << setw( 2 ) << setfill( '0' ) << ( int )( unsigned char )hash[ i ];
   }

   return outs.str( );
}

int main( )
{
   string hash( "\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a" );

   cout << print_hash_as_hex( hash );
}

Replace the first line in "main" with your SHA256 string object.


Title: Re: SHA-256 in c++ with crypto++
Post by: redPanda on March 11, 2015, 02:16:05 PM
If I use the two steps conversion path, I can get rid of the trailling 'f'
but I still miss the last characters (the size of my string is 29).
When I use your advice:
Quote
Replace
 return string((char*)abDigest);
With   return string((char*)abDigest, 32);
then I get the perfect result.
Great!
and thanks for your explanations, I like to understand what I'm doing