def raw_bcrypt(password, ident, salt, log_rounds): """perform central password hashing step in bcrypt scheme. :param password: the password to hash :param ident: identifier w/ minor version (e.g. 2, 2a) :param salt: the binary salt to use (encoded in bcrypt-base64) :param rounds: the log2 of the number of rounds (as int) :returns: bcrypt-base64 encoded checksum """ #=================================================================== # parse inputs #=================================================================== # parse ident assert isinstance(ident, native_string_types) add_null_padding = True if ident == u('2a') or ident == u('2y') or ident == u('2b'): pass elif ident == u('2'): add_null_padding = False elif ident == u('2x'): raise ValueError("crypt_blowfish's buggy '2x' hashes are not " "currently supported") else: raise ValueError("unknown ident: %r" % (ident,)) # decode & validate salt assert isinstance(salt, bytes) salt = bcrypt64.decode_bytes(salt) if len(salt) < 16: raise ValueError("Missing salt bytes") elif len(salt) > 16: salt = salt[:16] # prepare password assert isinstance(password, bytes) if add_null_padding: password += BNULL # validate rounds if log_rounds < 4 or log_rounds > 31: raise ValueError("Bad number of rounds") #=================================================================== # # run EKS-Blowfish algorithm # # This uses the "enhanced key schedule" step described by # Provos and Mazieres in "A Future-Adaptable Password Scheme" # http://www.openbsd.org/papers/bcrypt-paper.ps # #=================================================================== engine = BlowfishEngine() # convert password & salt into list of 18 32-bit integers (72 bytes total). pass_words = engine.key_to_words(password) salt_words = engine.key_to_words(salt) # truncate salt_words to original 16 byte salt, or loop won't wrap # correctly when passed to .eks_salted_expand() salt_words16 = salt_words[:4] # do EKS key schedule setup engine.eks_salted_expand(pass_words, salt_words16) # apply password & salt keys to key schedule a bunch more times. rounds = 1<<log_rounds engine.eks_repeated_expand(pass_words, salt_words, rounds) # encipher constant data, and encode to bytes as digest. data = list(BCRYPT_CDATA) i = 0 while i < 6: data[i], data[i+1] = engine.repeat_encipher(data[i], data[i+1], 64) i += 2 raw = digest_struct.pack(*data)[:-1] return bcrypt64.encode_bytes(raw)
def raw_bcrypt(password, ident, salt, log_rounds): """perform central password hashing step in bcrypt scheme. :param password: the password to hash :param ident: identifier w/ minor version (e.g. 2, 2a) :param salt: the binary salt to use (encoded in bcrypt-base64) :param rounds: the log2 of the number of rounds (as int) :returns: bcrypt-base64 encoded checksum """ #=================================================================== # parse inputs #=================================================================== # parse ident assert isinstance(ident, unicode) if ident == u('2'): minor = 0 elif ident == u('2a'): minor = 1 # XXX: how to indicate caller wants to use crypt_blowfish's # workaround variant of 2a? elif ident == u('2x'): raise ValueError("crypt_blowfish's buggy '2x' hashes are not " "currently supported") elif ident == u('2y'): # crypt_blowfish compatibility ident which guarantees compat w/ 2a minor = 1 else: raise ValueError("unknown ident: %r" % (ident, )) # decode & validate salt assert isinstance(salt, bytes) salt = bcrypt64.decode_bytes(salt) if len(salt) < 16: raise ValueError("Missing salt bytes") elif len(salt) > 16: salt = salt[:16] # prepare password assert isinstance(password, bytes) if minor > 0: password += BNULL # validate rounds if log_rounds < 4 or log_rounds > 31: raise ValueError("Bad number of rounds") #=================================================================== # # run EKS-Blowfish algorithm # # This uses the "enhanced key schedule" step described by # Provos and Mazieres in "A Future-Adaptable Password Scheme" # http://www.openbsd.org/papers/bcrypt-paper.ps # #=================================================================== engine = BlowfishEngine() # convert password & salt into list of 18 32-bit integers (72 bytes total). pass_words = engine.key_to_words(password) salt_words = engine.key_to_words(salt) # truncate salt_words to original 16 byte salt, or loop won't wrap # correctly when passed to .eks_salted_expand() salt_words16 = salt_words[:4] # do EKS key schedule setup engine.eks_salted_expand(pass_words, salt_words16) # apply password & salt keys to key schedule a bunch more times. rounds = 1 << log_rounds engine.eks_repeated_expand(pass_words, salt_words, rounds) # encipher constant data, and encode to bytes as digest. data = list(BCRYPT_CDATA) i = 0 while i < 6: data[i], data[i + 1] = engine.repeat_encipher(data[i], data[i + 1], 64) i += 2 raw = digest_struct.pack(*data)[:-1] return bcrypt64.encode_bytes(raw)
def raw_bcrypt(password, ident, salt, log_rounds): """perform central password hashing step in bcrypt scheme. :param password: the password to hash :param ident: identifier w/ minor version (eg 2, 2a) :param salt: the binary salt to use (encoded in bcrypt-base64) :param rounds: the log2 of the number of rounds (as int) :returns: bcrypt-base64 encoded checksum """ #=========================================================== # parse inputs #=========================================================== # parse ident assert isinstance(ident, unicode) if ident == u('2'): minor = 0 elif ident == u('2a'): minor = 1 # XXX: how to indicate caller wants to use crypt_blowfish's # workaround variant of 2a? elif ident == u('2x'): raise ValueError("crypt_blowfish's buggy '2x' hashes are not " "currently supported") elif ident == u('2y'): # crypt_blowfish compatibility ident which guarantees compat w/ 2a minor = 1 else: raise ValueError("unknown ident: %r" % (ident,)) # decode & validate salt assert isinstance(salt, bytes) salt = bcrypt64.decode_bytes(salt) if len(salt) < 16: raise ValueError("Missing salt bytes") elif len(salt) > 16: salt = salt[:16] # prepare password assert isinstance(password, bytes) if minor > 0: password += BNULL # validate rounds if log_rounds < 4 or log_rounds > 31: raise ValueError("Bad number of rounds") #=========================================================== # # run EKS-Blowfish algorithm # # This uses the "enhanced key schedule" step described by # Provos and Mazieres in "A Future-Adaptable Password Scheme" # http:#www.openbsd.org/papers/bcrypt-paper.ps # #=========================================================== engine = BlowfishEngine() # convert password & salt into list of 18 32-bit integers. pass_words = engine.key_to_words(password) salt_words = engine.key_to_words(salt) # do EKS key schedule setup # NOTE: [:4] is due to salt being 16 bytes originally, # and the list needs to wrap properly engine.eks_expand(pass_words, salt_words[:4]) # apply password & salt keys to key schedule a bunch more times. rounds = 1<<log_rounds engine.eks_rounds_expand0(pass_words, salt_words, rounds) #encipher constant data, and encode to bytes as digest. data = list(BCRYPT_CDATA) i = 0 while i < 6: data[i], data[i+1] = engine.repeat_encipher(data[i], data[i+1], 64) i += 2 raw = digest_struct.pack(*data)[:-1] return bcrypt64.encode_bytes(raw)