random.random() will "return the next random floating point number in the range [0.0, 1.0).", and int() will always convert from a float by truncating (rounding down). Therefore,
int(random.random() * 255) only returns ints from 0-254, not the full range 0-255 as I assume is intended.
But I'm wondering why random_string() exists at all. Since it's returning a string of bytes, not limited to ASCII chars, it's basically doing the same thing as os.urandom(). Using a custom function for that only adds more possibility for errors, like in issue #82 and here.
Does it make sense to get rid of random_string() and replace it with os.urandom() directly?