C++ und sha1-Algorithmus
-
hallo
ich will mit dem pseudocode aus wikipedia einen sha1-algorithmus programmieren. es geht mir in erster linie nicht um portability, es soll nur auf meinem system laufen (win64, little endian)
das ist mein code:template <typename InputIterator> std::string generate_sha1(InputIterator begin, InputIterator end) { long long int seq_size = sizeof(InputIterator::value_type) * (end - begin); // initial size of input sequence in bytes unsigned h[] = { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 }; // initial 32-bit values for sha1 algorithm unsigned extension_size = 64 - (seq_size + 8) % 64; // size of 1000... extension in bytes std::vector<unsigned char> extend_seq(seq_size + extension_size + 8); // extended sequence = origin sequence + extension + message length std::copy(begin, end, extend_seq.begin()); // copy the original sequence extend_seq[seq_size] = 128; // add 1 bit at the end of the original sequence // fill up rest for 0 for(long long int n = seq_size + 1; n != seq_size + extension_size; ++n) extend_seq[n] = 0; long long int be_seq_size = _byteswap_uint64(seq_size * 8); // swap endian of bitwise length of the original sequence std::memcpy(&extend_seq[seq_size + extension_size], &be_seq_size, 8); // concatenate big endian length at the end // for every 512bit block... for(unsigned n = 0; n < extend_seq.size(); n += 64) { std::vector<unsigned> words(80); // 32-bit blocks of the extended sequence std::memcpy(&words[0], &extend_seq[n], 64); // copy 512 bit into new memory std::transform(words.begin(), words.end(), words.begin(), _byteswap_ulong); // transform words to big endian // now begin sha1-algorithm for(unsigned i = 16; i < 80; ++i) { words[i] = left_rotate(words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16], 1); } int a = h[0], b = h[1], c = h[2], d = h[3], e = h[4], f, k; for(unsigned n = 0; n < 79; ++n) { if(n >= 60) { f = b ^ c ^ d; k = 0xCA62C1D6; } else if(n >= 40 && n <= 59) { f = (b & c) | (b & d) | (c & d); k = 0x8F1BBCDC; } else if(n >= 20 && n <=39) { f = b ^ c ^ d; k = 0x6ED9EBA1; } else if(n <= 19) { f = (b & c) | (!b & d); k = 0x5A827999; } unsigned tmp = left_rotate(a, 5) + f + e + k + words[n]; e = d; d = c; c = left_rotate(b, 30); b = a; a = tmp; } h[0] += a; h[1] += b; h[2] += c; h[3] += d; h[4] += e; } // convert result into string, swap endian back to little endian std::stringstream ss; h[0] = _byteswap_ulong(h[0]); h[1] = _byteswap_ulong(h[1]); h[2] = _byteswap_ulong(h[2]); h[3] = _byteswap_ulong(h[3]); h[4] = _byteswap_ulong(h[4]); ss << std::hex << h[0] << h[1] << h[2] << h[3] << h[4]; return ss.str(); }leider kommt für den hash bei leerem string nicht das richtige ergebnis, weiß aber nicht, wo der fehler sein könnte.
im wikipedia steht, dass man die 32-bit-wörter im big endian haben muss und dass das ergebnis in big endian ist, also konvertiere ich dort um. aber trotzdem klappt es nicht. was ist am endian-swap falsch?
-
for(unsigned n = 0; n < 79; ++n)sieht nicht richtig aus.
Die gerechte Strafe für das loop-switch-Idiom.
-
Darf man fragen warum du überhaupt noch etwas mit SHA1 machen willst, und nicht gleich einen Algorithmus der SHA2 Familie nimmst?
-
camper schrieb:
for(unsigned n = 0; n < 79; ++n)sieht nicht richtig aus.
Die gerechte Strafe für das loop-switch-Idiom.stimmt, das war falsch. aber es haut immernoch nicht hin.

mein left_rotate sieht so aus:unsigned int left_rotate(unsigned int val, int n) { char t; while(n--) { if(val & 0x80000000) t = 1; else t = 0; val <<= 1; val |= t; } return val; }
-
Dein Shift sollte zwar passen aber was spricht gegen folgende Lösung:
unsigned int loopless_left_rotate( unsigned int val, int n ) { return ( val << n ) | ( val >> ( sizeof( unsigned int ) * CHAR_BIT - n ) ); }