2018-08-29 21:16:22 +00:00
|
|
|
import base64
|
2018-08-28 09:27:54 +00:00
|
|
|
import hashlib
|
|
|
|
import os
|
|
|
|
|
|
|
|
def hash_with_salt(host, salt):
|
|
|
|
"""hash_with_salt(bytes, bytes) → bytes[32]
|
|
|
|
Hash the host using sha256 and the give salt"""
|
|
|
|
assert type(host) == bytes
|
|
|
|
assert type(salt) == bytes
|
|
|
|
m = hashlib.sha256()
|
|
|
|
m.update(host)
|
|
|
|
m.update(salt)
|
|
|
|
return m.digest()
|
|
|
|
|
|
|
|
def generate_salt():
|
|
|
|
"""generate_salt() → bytes[32]
|
|
|
|
Generates 32 bytes of randomness using the system urandom"""
|
|
|
|
return os.urandom(32)
|
|
|
|
|
|
|
|
def hash_host(host):
|
|
|
|
"""hash_host(bytes) → (bytes[32]: salt, bytes[32]: hashed_host)
|
|
|
|
Generates a salt and hashes the host with it"""
|
|
|
|
assert type(host) == bytes
|
|
|
|
salt = generate_salt()
|
|
|
|
hashed_host = hash_with_salt(host, salt)
|
|
|
|
return salt, hashed_host
|
2018-08-29 21:16:22 +00:00
|
|
|
|
|
|
|
def base64enc(b):
|
|
|
|
"""base64enc(bytes) → bytes
|
|
|
|
Uses no padding"""
|
|
|
|
# Base 64 encodes 3 bytes as 4 characters
|
|
|
|
# /byte 1\/byte 2\/byte 3\
|
|
|
|
# ABCDEFGHijklmnopQRSTUVWX
|
|
|
|
# \64 1/\64 2/\64 3/\64 4/
|
|
|
|
#
|
|
|
|
# If you have only one or two bytes, you don't have enough bits to
|
|
|
|
# fill all of the characters. The rest of the bits will be taken to
|
|
|
|
# be zeroes.
|
|
|
|
# /byte 1\
|
|
|
|
# ABCDEFGH0000
|
|
|
|
# \64 1/\64 2/
|
|
|
|
# /byte 1\
|
|
|
|
#
|
|
|
|
# /byte 1\/byte 2\
|
|
|
|
# ABCDEFGHijklmnop00
|
|
|
|
# \64 1/\64 2/\64 3/
|
|
|
|
#
|
|
|
|
# This way you end up with only 2 or 3 characters containing info.
|
|
|
|
# This usually gets padded into a multiple of 4 with =. However,
|
|
|
|
# since the amount of bytes left over mod 4 is enough to generate
|
|
|
|
# the padding back, we can strip it out
|
|
|
|
return base64.b64encode(b).replace(b'=', b'')
|
|
|
|
|
|
|
|
def base64dec(b64):
|
|
|
|
"""base64dec(bytes) → bytes
|
|
|
|
Can handle lack of padding."""
|
|
|
|
assert type(b64) == bytes
|
|
|
|
|
|
|
|
# Padded base64 is always a multiple of 4 bytes in length. The
|
|
|
|
# reasoning for this is because base64 decoding operates in groups
|
|
|
|
# of 4 base64 characters.
|
|
|
|
# Since we know the length of the string minus the padding, we can
|
|
|
|
# just pad it to the nearest multiple of 4
|
|
|
|
|
|
|
|
missing_padding_len = (4 - len(b64)%4) % 4
|
|
|
|
padding = b'=' * missing_padding_len
|
|
|
|
return base64.b64decode(b64 + padding, validate = True)
|