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?


  • Mod

    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 ) );
    }
    

Anmelden zum Antworten