Question

Ok, I'm using a raw SHA1 hash to seed a Mersenne Twister pseudo-random number generator the generator gives me the option to seed either with an unsigned long or a array of unsigned longs

the SHA1 class I'm using gives me the hash as a 20 byte array of unsigned chars

I figured I could recast this array of chars to an array of longs to get a working seed but how can I know how long the resulting array of longs is?

example code:

CSHA1 sha1;
sha1.Update((unsigned char*)key, size_key);
sha1.Final();
unsigned char* hash;
sha1.GetHash(hash);

// Seed the random with the key
MTRand mt((unsigned long*)hash, <size of array of longs>);

I'm hoping that there is no data loss (as in no bytes are dropped off) as I need this to remain cryptography secure

Was it helpful?

Solution

You can say

sizeof(unsigned long) / sizeof(unsigned char)

to get the number of octets in a long.

However there are two potential problems with simply casting.

First, the array of chars might not be properly aligned. On some processors this can cause a trap. On others it just slows execution.

Second, you're asking for byte order problems if the program must work the same way on different architecutures.

You can solve both problems by copying the bytes into an array of longs explicitly. Untested code:

const int bytes_per_long = sizeof(unsigned long) / sizeof(unsigned char);
unsigned long hash_copy[key_length_in_bytes / bytes_per_long];
int i_hash = 0;
for (int i_copy = 0; i_copy < sizeof hash_copy / sizeof hash_copy[0]; i_copy++) {
  unsigned long b = 0;
  for (int i_byte = 0; i_byte < bytes_per_long; i_byte++)
    b = (b << 8) | hash[i_hash++];
  hash_copy[i_copy] = b;
}
// Now use hash_copy.

OTHER TIPS

You can use len_of_chars * sizeof(char) / sizeof(long), where len_of_chars is presumably 20.

Your library seems to assume 32-bit unsigned longs, so there's no [more] harm in you doing the same. In fact, I'd go as far to assume 8-bit unsigned chars and perhaps even unpadded, little-endian representations for both. So you could use a simple cast (though I'd use a reinterpret_cast), or maybe @Gene's memcpy sample for alignment.

Portable code*, however, should use <cstdint>, the uint#_t types therein and piecewise, by-value copying for conversion:

uint32_t littleEndianInt8sToInt32(uint8_t bytes[4]) {
    return bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24);
}

...and better names. Sorry, it's getting late here :)

*: Though, of course, stdint itself isn't very portable (>= C++11) and the exact-width types aren't guaranteed to be in it. Ironic.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top