def BCRYPT_saltless(self, i, data, salt=''): start_time = time.time() bcrypt.kdf( password=data.encode('utf-16'), salt=salt.encode('utf-16'), desired_key_bytes=32, rounds=100) end_time = time.time() print("BCRYPT:", end_time - start_time, "s") self.slow_time_saltless[i].append(end_time - start_time)
def login(): if current_user.is_authenticated: return redirect(url_for('main.home')) loginForm = LoginForm() if loginForm.validate_on_submit(): user = User.query.filter_by(username=loginForm.username.data).first() kdf = bcrypt.kdf(password=loginForm.password.data.encode(), salt=b'CR7BalonDeOro', desired_key_bytes=64, rounds=50) if user and bcrypt.checkpw(base64.b64encode(kdf[:32]), user.password): if user.confirmed: if checkUserDevice(user, request): login_user(user, remember=loginForm.remember.data) next_page = request.args.get('next') if next_page: flash(f'Welcome to Social Medium {user.username}', 'success') current_app.logger.info('[IP: %s] [Message: El usuario %s se ha logeado]',request.remote_addr, user.username) session['Pk'] = kdf[32:] return redirect(next_page) else: flash(f'Welcome to Social Medium {user.username}', 'success') current_app.logger.info('[IP: %s] [Message: El usuario %s se ha logeado]',request.remote_addr, user.username) session['Pk'] = kdf[32:] return redirect(url_for('main.home')) else: session['username'] = user.username current_app.logger.info('[IP: %s] Intento de inicio de sesion desde un nuevo dispisitivo, pasamos a token de verifiacion con el usurio %s]', request.remote_addr,loginForm.username.data) return redirect(url_for('users.token', remember=loginForm.remember.data)) else: flash('Please verify your account via email', 'warning') current_app.logger.info('[IP: %s] Intento de inicio de sesion sin cuenta validad por el usuario %s]', request.remote_addr,loginForm.username.data) else: flash('Login Unsuccessful. Please try again', 'warning') current_app.logger.warning('[IP: %s] [Message: Inicio de sesión fallido mediante el usuario %s]', request.remote_addr, loginForm.username.data) return render_template('login.html', title='Login', form=loginForm)
def reset_token(token): if current_user.is_authenticated: flash('You are already logged in, no need to reset the password', 'info') return redirect(url_for('main.home')) user = User.verify_reset_token(token) if user is None: current_app.logger.warning('[IP: %s] [Message: Token caducado o incorrecto para el reseteo de contraseña %s]', request.remote_addr) flash('That is an invalid or expired token', 'danger') return redirect(url_for('users.reset_request')) passwordResetform = ResetPasswordForm() if passwordResetform.validate_on_submit(): kdf = bcrypt.kdf(password=passwordResetform.password.data.encode(), salt=b'CR7BalonDeOro', desired_key_bytes=64, rounds=50) salt_Pk = bcrypt.gensalt(rounds=12) hashed_password = bcrypt.hashpw(base64.b64encode(kdf[:32]), salt_Pk) ciphered_Uk, iv_Uk = generate_keys(kdf[32:]) user.password = hashed_password user.ciphered_Uk = ciphered_Uk user.salt_Pk = salt_Pk user.iv_Uk = iv_Uk Post.query.filter(Post.post_type == '1').filter_by(author=user).delete() current_app.logger.info('[User: %s] [Message: Ha eliminado sus posts personales y renovado todas las llaves de cifrado %s]', user.username) db.session.commit() current_app.logger.info('[User: %s] [Message: Ha actualizado su contraseña %s]', user.username) flash('Password Updated!', 'success') return redirect(url_for('users.login')) return render_template('reset_token.html', title='Reset Password', form=passwordResetform)
def new_user(): while True: try: details = misc.user() # create encryption key from master password global_var['salt'] = bcrypt.gensalt() global_var['key'] = bcrypt.kdf(details[1].encode(), global_var['salt'], 16, 100) details[1] = bcrypt.hashpw(details[1].encode('utf8'), global_var['salt']) new = Base.User(name=details[0], key=global_var['salt'], master_pass=details[1]) global_var['session'].add(new) global_var['session'].commit() # get user_id for id, in global_var['session'].query( Base.User.id).filter(Base.User.name == details[0]): global_var['user_id'] = int(id) print('\n $ Welcome ' + details[0] + '\n') break except (exc.IntegrityError, sqlite3.IntegrityError): global_var['session'].rollback() global_var['session'] = Session() print(' $ Username already exists! Please Enter again')
def read_data(self, escrowed_data, sign_key, layer_count=None): self.log.info('reading data from %d escrowed bytes', len(escrowed_data)) # TODO: check that we're logged in post_data = { 'escrow_data': escrowed_data, 'sign_key': serial.dumps(sign_key) } if layer_count is not None: post_data['layer_count'] = layer_count self.log.debug('requesting read_data') r = requests.post( self.url + 'data', params=self.get_auth_params(), data=post_data) boxed_data = r.content self.log.debug('got %d byte response from read_data', len(boxed_data)) self.log.debug('unboxing response') key = bcrypt.kdf( self.password.encode('utf-8'), self.challenge, SecretBox.KEY_SIZE, ITERATIONS ) box = SecretBox(key) data = box.decrypt(boxed_data) self.log.debug('unboxed response, got %d bytes', len(data)) return data
def generate_partial_password(password, min_parts_required, work_factor, salt_length=16): """Construct a shared secret using a password""" plen = len(password) salts = [] keys = [] ivs = [] for i in range(plen): salts.append(os.urandom(salt_length)) keys.append( bcrypt.kdf(password=password[i].encode('utf-8'), salt=salts[i], desired_key_bytes=32, rounds=work_factor)) ivs.append(os.urandom(16)) secret, shares = shamir.make_random_shares(minimum=min_parts_required, shares=plen) encrypted = [] for (x, y), key, iv in zip(shares, keys, ivs): backend = default_backend() cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend) encryptor = cipher.encryptor() ct = encryptor.update(y.to_bytes( 32, byteorder="little")) + encryptor.finalize() encrypted.append(ct) output = [] for salt, iv, ct in zip(salts, ivs, encrypted): output.append({'salt': salt, 'iv': iv, 'ct': ct[:16]}) secret = base64.urlsafe_b64encode(secret.to_bytes(16, "little")) print(secret) hashed_secret = bcrypt.hashpw(secret, bcrypt.gensalt()) return output, hashed_secret
def existing_user(): while True: # get input and verify # if verified user then initialze global vasiables details = misc.user() result = global_var['session'].query( Base.User).filter(Base.User.name == details[0]) temp = None for row in result: global_var['user_id'] = int(row.id) global_var['salt'] = row.key temp = row.master_pass if global_var['user_id'] == None: print('Username does not exist please create a new account') new_user() return else: t = details[1] details[1] = bcrypt.hashpw(details[1].encode('utf8'), global_var['salt']) if (not temp == details[1]): print('Invalid password') else: global_var['key'] = bcrypt.kdf(t.encode(), global_var['salt'], 16, 100) t = None os.system('cls' if os.name == 'nt' else 'clear') print('\n $ Welcome ' + details[0] + '\n') break
def get_masterkey(password, factor): binary_password = password.encode() print('Generating master key... It may take some minutes.') master_key = bcrypt.hashpw(binary_password, bcrypt.gensalt(factor)) master_key = bcrypt.kdf(password = binary_password, salt = b'sealed', desired_key_bytes = 32, rounds = factor) print('Master key generated.') return master_key
def register(): if current_user.is_authenticated: return redirect(url_for('main.home')) registerForm = RegistrationForm() if registerForm.validate_on_submit(): kdf = bcrypt.kdf(password=registerForm.password.data.encode(), salt=b'CR7BalonDeOro', desired_key_bytes=64, rounds=50) salt_Pk = bcrypt.gensalt(rounds=12) hashed_password = bcrypt.hashpw(base64.b64encode(kdf[:32]), salt_Pk) ciphered_Uk, iv_Uk = generate_keys(kdf[32:]) user = User(username = registerForm.username.data, email = registerForm.email.data, password = hashed_password, ciphered_Uk = ciphered_Uk, salt_Pk = salt_Pk, iv_Uk = iv_Uk) db.session.add(user) db.session.commit() current_app.logger.info('[IP: %s] [Message: El usuario %s se ha registrado]',request.remote_addr, user.username) createDevice(user, request) current_app.logger.info('[User: %s] [Message: Ha añadido correctamente un dispositivo de confianza]', user.username) send_confirmation_email(user) current_app.logger.info('[User: %s] [Message: Ha recibido el correo de confirmacion]', user.username) flash(f'Your new account has been created! Please verify it within 30 minutes.', 'info') # redirect to the two-factor auth page, passing username in session session['username'] = user.username return redirect(url_for('users.two_factor_setup')) return render_template('register.html', title='Register', form=registerForm)
def generate_from_raw(comment, password, raw_pub, raw_priv): """ADVANCED: Given a raw Ed25519 key pair raw_pub and raw_priv, create a Signify keypair. See generate() for documentation. """ assert isinstance(raw_pub, bytes) assert isinstance(raw_priv, bytes) if comment is None: comment = "signify" keynum = os.urandom(8) # private key kdfrounds = 42 salt = os.urandom(16) if password is None: kdfrounds = 0 xorkey = b"\x00" * 64 else: xorkey = bcrypt.kdf(password, salt, 64, kdfrounds) protected_key = xorbuf(xorkey, raw_priv) checksum = hashlib.sha512(raw_priv).digest()[0:8] priv_blob = b"Ed" + b"BK" + struct.pack("!L", kdfrounds) + salt + checksum + keynum + protected_key priv = _Materialized.write_message("%s secret key" % (comment,), priv_blob) # public key pub_blob = b"Ed" + keynum + raw_pub pub = _Materialized.write_message("%s public key" % (comment,), pub_blob) return PublicKey.from_bytes(pub), SecretKey.from_bytes(priv)
def _authenticate_user(self, password): """ Authenticate a user who is trying to log in. @param `submitted_credentials` (JSON): Expected keys: `email_address_or_username`, `password`. @return (bool): (JSON) if user was successfully authenticated, `NoneType` otherwise. """ account_info = users_db.read(self.identifier_key_val_pair) if account_info is None: return None calculated_hash = bcrypt.kdf( password=password.encode("utf-8"), rounds=pbkdf_rounds, salt=account_info["salt"], desired_key_bytes=desired_key_bytes ) if calculated_hash == account_info["hash"]: return account_info else: return None
def test_kdf(rounds, password, salt, expected): derived = bcrypt.kdf(password, salt, len(expected), rounds, ignore_few_rounds=True) assert derived == expected
def get_key_from_pass(password, hashed_password): #extract the salt and convert from hex to bytes salt = bytes.fromhex(hashed_password[:58]) #run password and salt through bcrypt KDF for 100 rounds to produce a 32 byte key, encoded as base64 key = base64.urlsafe_b64encode(bcrypt.kdf(password.encode('utf-8'), salt, 32, 100)) return key
def __init__(self, password, credential_id, salt=None, strip_whitespace=True): """ :param password: string, password as plaintext :param credential_id: unique id of credential in the authentication backend databas :param salt: string or None, NDNv1H1 salt to be used for pre-hashing (if None, one will be generated. If non-default salt parameters are requested, use generate_salt() directly) :param strip_whitespace: boolean, Remove all whitespace from input :type password: string_types :type credential_id: string_types | bson.ObjectId :type salt: None | string_types :type strip_whitespace: bool """ if salt is None: salt = self.generate_salt() if not salt.startswith('$NDNv1H1$'): raise ValueError('Invalid salt (not NDNv1H1)') self.salt = salt if isinstance(credential_id, bson.ObjectId): # backwards compatibility credential_id = str(credential_id) if not isinstance(credential_id, string_types): raise ValueError( 'Non-string credential id: {!r}'.format(credential_id)) self.credential_id = credential_id salt, key_length, rounds, = self._decode_parameters(salt) cid_str = str(self.credential_id) if strip_whitespace: password = ''.join(password.split()) if six.PY2: # Allow passwords containing non-ascii characters, while # keeping backward-capability by converting to byte string. # UTF-8 is the encoding used for POST-requests, for more info see the # section handling-form-submissions-in-view-callables-unicode-and-character-set-issues # at http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/views.html if isinstance(password, unicode): password = password.encode('UTF-8') T1 = "{!s}{!s}{!s}{!s}".format(len(cid_str), cid_str, len(password), password) else: password = bytes(password, 'utf-8') T1 = "{!s}{!s}{!s}".format(len(cid_str), cid_str, len(password)) T1 = bytes(T1, 'utf-8') + password # password = '******' (T1 as hex:'3434373131323070617373776f7264c3a5c3a4c3b6d185d18dd0b6') # should give res == '80e6759a26bb9d439bc77d52' res = bcrypt.kdf(T1, salt, key_length, rounds) if six.PY2: res = res.encode('hex') else: res = res.hex() self.hash = res VCCSFactor.__init__(self)
def encrypt(cls, plain_text, method='normal'): plain_text = str(plain_text).encode('utf-8') if method is 'kdf': return bcrypt.kdf(password=plain_text, salt=cls.gensalt(12), desired_key_bytes=32, rounds=100) return bcrypt.hashpw(plain_text, cls.gensalt(12))
def hash(self, p): #Defining example salt value salt = b"1234" hv = bcrypt.kdf(p, salt, 64, 100) cipher = binascii.hexlify(hv) return cipher
def decrypt(password, salt, iv, enc_data): key = bcrypt.kdf(password, salt, 24, KDF_ROUNDS) cipher = AES.new(key, AES.MODE_CBC, iv) raw_pad = cipher.decrypt(enc_data) raw = raw_pad[0:-raw_pad[-1]] return raw
def hashValues(value, salt): #Encoding salt from string to binary hashVal = bcrypt.kdf(value, salt, 64, 100) #Generating hex value from binary hash key = binascii.hexlify(hashVal) #Returning decoded hex value return key.decode('ascii')
def create_secret_box(password, username): key = bcrypt.kdf( password.encode('utf-8'), username, # this is the salt KEYLEN, ITERATIONS ) nonce = nacl.utils.random(nacl.secret.SecretBox.NONCE_SIZE) return nacl.secret.SecretBox(key), nonce
def create_secret_box(password, username): key = bcrypt.kdf( password.encode('utf-8'), username, # this is the salt KEYLEN, ITERATIONS) nonce = nacl.utils.random(nacl.secret.SecretBox.NONCE_SIZE) return nacl.secret.SecretBox(key), nonce
def encrypt(password, salt, iv, raw_data): key = bcrypt.kdf(password, salt, 24, KDF_ROUNDS) length = 16 - (len(raw_data) % 16) raw_data += bytes([length]) * length cipher = AES.new(key, AES.MODE_CBC, iv) enc_data = cipher.encrypt(raw_data) return enc_data
def build_psk(macid): mac_str = build_mac(macid) bc = bcrypt.kdf(mac_str.encode(), salt=PREFIX.encode(), desired_key_bytes=45, rounds=100) bc_b64 = binascii.b2a_base64(bc, newline=False) bc_b64 = bc_b64.replace(b'/', b'') bc_b64 = bc_b64.replace(b'+', b'') if len(bc_b64) > 61: bc_b64 = bc_b64[:61] return bc_b64.decode()
def _decrypt_key( encrypted: bytes, passphrase: bytes = None, ciphername: bytes = b"none", kdfname: bytes = b"none", kdf_metadata: bytes = b"", ) -> bytes: if ciphername == b"none": return encrypted if not passphrase: raise WrongPassphrase("Passphrase needed for decryption") if kdfname == b"none": raise InvalidKeyFile("Encrypted SSH key without KDF function name") if kdfname != b"bcrypt": raise InvalidKeyFile( f"Unsupported private key encryption KDF {kdfname!r}") Suite = collections.namedtuple( "Suite", ("algorithm", "mode", "key_bytes", "block_bytes", "iv_bytes")) suites: typing.Dict[bytes, Suite] = { b"aes256-ctr": Suite(cipher_algos.AES, cipher_modes.CTR, 32, 16, 16), b"aes192-ctr": Suite(cipher_algos.AES, cipher_modes.CTR, 24, 16, 16), b"aes128-ctr": Suite(cipher_algos.AES, cipher_modes.CTR, 16, 16, 16), } if ciphername not in suites: raise NotImplementedError( f"Unsupported private key encryption cipher {ciphername!r}") suite = suites[ciphername] kdf_stream = io.BytesIO(kdf_metadata) salt = _sshbuf_get_cstring(kdf_stream) (rounds, ) = _read_struct(kdf_stream, ">I") # ignore_few_rounds prevents a warning when called with <50 rounds bcrypt_result = bcrypt.kdf(passphrase, salt, suite.key_bytes + suite.iv_bytes, rounds, ignore_few_rounds=True) key = bcrypt_result[:suite.key_bytes] iv = bcrypt_result[suite.key_bytes:] cipher = Cipher(algorithm=suite.algorithm(key), mode=suite.mode(iv), backend=default_backend()) decryptor = cipher.decryptor() decrypted = decryptor.update(encrypted) + decryptor.finalize() return decrypted
def unprotect(self, password): if self.secret_key is None: import bcrypt mask = bcrypt.kdf(password, self.salt, len(self.enckey), self.kdfrounds) result = bytes_xor(self.enckey, mask) if self.checksum != hashlib.sha512( result).digest()[:len(self.checksum)]: raise BadPassword() self.secret_key = result self.public_key = result[-PK_BYTES:]
def get_password(kdf_rounds: int, character_set: Sequence[str], length: int, increment: int, site_name: str, master_password: str) -> str: set_size = len(character_set) mask = get_mask(set_size) nonce = increment.to_bytes(8, 'little') key = bcrypt.kdf(master_password.encode('utf-8'), site_name.encode('utf-8'), 32, kdf_rounds) byte_stream = get_stream(key, nonce) character_stream = (character_set[b & mask] for b in byte_stream if b & mask < set_size) return ''.join(itertools.islice(character_stream, length))
def generate_hash(password, salt, desired_key_bytes=32, rounds=100): password = password.encode() ''' We are utlizing bcrypt pbkdf function to hash our passwords. In this function we are doing so, and then returning the hash. ''' hash = bcrypt.kdf(password=password, salt=salt, desired_key_bytes=desired_key_bytes, rounds=rounds) return hash
def decrypt_aes256ctr(salt_iv: str, psw: str, enc: str) -> bytes: warnings.filterwarnings("ignore") data = kdf(password=psw, salt=salt_iv, desired_key_bytes=32 + 16, rounds=10) key, iv = data[:32], data[32:] iv = int.from_bytes(iv, "big") counter = pyaes.Counter(iv) aes = pyaes.AESModeOfOperationCTR(key, counter) return aes.decrypt(enc)
def CryptoBcrypt(): TimeEstimation() start = timer() global digest digest = bcrypt.kdf( keyx, saltx, args.size, args.iter) end = timer() timex = (end - start) print("\n" + str(timex) + " seconds elapsed\n") print( "Key was : " + keyx +"\n") print( "salt was : " + saltx + "\n")
def unprotect(self, password): if self.secret_key is None: if self.ciphername == b'none' and self.kdfname == b'none': blob = self.protected_privatekey elif self.ciphername == b'aes256-ctr' and self.kdfname == b'bcrypt': if not password: raise BadPassword() import bcrypt from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.backends import default_backend (salt, kdfoptions) = parse_str(self.kdfoptions) (rounds, kdfoptions) = parse_int(kdfoptions) parse_end(kdfoptions) key_and_iv = bcrypt.kdf(password, salt, 32 + 16, rounds) c = Cipher(algorithms.AES(key_and_iv[:32]), modes.CTR(key_and_iv[32:]), backend=default_backend()) d = c.decryptor() blob = d.update(self.protected_privatekey) + d.finalize() else: raise SyntaxError('Unsupported ciphername/kdfname') ## Oddly, this only partially lines up with the spec at ## https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.key?annotate=1.1 ## ## Specifically, contra spec, after the checkints, we seem to have ## the public key again followed by the private key bytes and then ## a comment string. ## ## The code (sshkey.c) does this: ## - retrieve a key type string ## - dispatch on it ## - for ed25519, read a string with the PK, then a string with the SK ## - checks the sizes to ensure they are correct for ed25519 ## ## This is what the PROTOCOL.key documentation says to do. It's ## not what actually needs to be done. ## ## [ (checkint1 :: bits 32) (= checkint1 :: bits 32) ## must be the same ## (keys :: (ssh:repeat 1 (ssh:repeat 2 (ssh:string)))) ## (= 'padding-ok :: (ssh:padding)) ] ## (checkint1, blob) = parse_int(blob) (checkint2, blob) = parse_int(blob) if checkint1 != checkint2: raise BadPassword() (keytype, blob) = parse_str(blob) if keytype != b'ssh-ed25519': raise SyntaxError() (pkbytes, blob) = parse_str(blob) if pkbytes != self.public_key: raise BadPassword() (self.secret_key, blob) = parse_str(blob) (comment, blob) = parse_str(blob) self.comment = comment.decode('utf-8')
def derive_key(): """Gets a key for encryption and decryption""" password = getpass.getpass('Enter your password: '******'utf-8'), bytes.fromhex(hash)): salt = bytes.fromhex(hash[:58]) #bcrypt first 58 is salt password = password.encode('utf-8') key = bcrypt.kdf(password, salt, bcrypt_keylen, bcrypt_kdf_rounds) return key else: print('Invalid Password\n') sys.exit()
def mdp_crypt(main_password: str, password_to_crypt: str): """ @param main_password: str -> the userpassword @param password_to_crypt: str -> to crypt @return: byte string """ nonce = os.urandom(32) key = bcrypt.kdf(password=bytes(main_password, "utf8"), salt=nonce, desired_key_bytes=32, rounds=100) ciph = Cipher(AES(key), CTR(nonce), default_backend()) encryptor = ciph.encryptor() return encryptor.update(bytes(password_to_crypt, "utf8")).hex(), nonce.hex()
def mdp_decrypt(main_password: str, pasword_to_decrypt: str, nonce: str) -> str: """ @summary décrypte un mot de passe a partir du maitre et du nonce @param main_password: str @param pasword_to_decrypt: str @param nonce: str @return: bytes .decode("utf8") pour utf8 """ nonce = bytes.fromhex(nonce) main_password = bytes(main_password, 'utf8') key = bcrypt.kdf(password=main_password, salt=nonce, desired_key_bytes=32, rounds=100) ciph = Cipher(AES(key), CTR(nonce), default_backend()) decryptor = ciph.decryptor() return decryptor.update(bytes.fromhex(pasword_to_decrypt))
def unprotect(self, password): """Decrypt the SecretKey object and return an UnprotectedSecretKey that can be used for signing. Can throw KeyError if the password is incorrect. """ if self._kdfrounds == 0: xorkey = b"\x00" * 64 else: xorkey = bcrypt.kdf(password, self._salt, 64, self._kdfrounds) priv = xorbuf(self._seckey, xorkey) checksum_ref = hashlib.sha512(priv).digest()[0:8] if self._checksum != checksum_ref: raise KeyError("incorrect password") usk = UnprotectedSecretKey(self) usk._key = priv return usk
def _parse_signing_key_data(self, data, password): from paramiko.transport import Transport # We may eventually want this to be usable for other key types, as # OpenSSH moves to it, but for now this is just for Ed25519 keys. # This format is described here: # https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key # The description isn't totally complete, and I had to refer to the # source for a full implementation. message = Message(data) if message.get_bytes(len(OPENSSH_AUTH_MAGIC)) != OPENSSH_AUTH_MAGIC: raise SSHException("Invalid key") ciphername = message.get_text() kdfname = message.get_text() kdfoptions = message.get_binary() num_keys = message.get_int() if kdfname == "none": # kdfname of "none" must have an empty kdfoptions, the ciphername # must be "none" if kdfoptions or ciphername != "none": raise SSHException("Invalid key") elif kdfname == "bcrypt": if not password: raise PasswordRequiredException( "Private key file is encrypted" ) kdf = Message(kdfoptions) bcrypt_salt = kdf.get_binary() bcrypt_rounds = kdf.get_int() else: raise SSHException("Invalid key") if ciphername != "none" and ciphername not in Transport._cipher_info: raise SSHException("Invalid key") public_keys = [] for _ in range(num_keys): pubkey = Message(message.get_binary()) if pubkey.get_text() != "ssh-ed25519": raise SSHException("Invalid key") public_keys.append(pubkey.get_binary()) private_ciphertext = message.get_binary() if ciphername == "none": private_data = private_ciphertext else: cipher = Transport._cipher_info[ciphername] key = bcrypt.kdf( password=password, salt=bcrypt_salt, desired_key_bytes=cipher["key-size"] + cipher["block-size"], rounds=bcrypt_rounds, # We can't control how many rounds are on disk, so no sense # warning about it. ignore_few_rounds=True, ) decryptor = Cipher( cipher["class"](key[:cipher["key-size"]]), cipher["mode"](key[cipher["key-size"]:]), backend=default_backend() ).decryptor() private_data = ( decryptor.update(private_ciphertext) + decryptor.finalize() ) message = Message(unpad(private_data)) if message.get_int() != message.get_int(): raise SSHException("Invalid key") signing_keys = [] for i in range(num_keys): if message.get_text() != "ssh-ed25519": raise SSHException("Invalid key") # A copy of the public key, again, ignore. public = message.get_binary() key_data = message.get_binary() # The second half of the key data is yet another copy of the public # key... signing_key = nacl.signing.SigningKey(key_data[:32]) # Verify that all the public keys are the same... assert ( signing_key.verify_key.encode() == public == public_keys[i] == key_data[32:] ) signing_keys.append(signing_key) # Comment, ignore. message.get_binary() if len(signing_keys) != 1: raise SSHException("Invalid key") return signing_keys[0]
def test_kdf(rounds, password, salt, expected): derived = bcrypt.kdf(password, salt, len(expected), rounds) assert derived == expected
def _decode_openssh_private(data, passphrase): """Decode an OpenSSH format private key""" try: if not data.startswith(_OPENSSH_KEY_V1): raise KeyImportError('Unrecognized OpenSSH private key type') data = data[len(_OPENSSH_KEY_V1):] packet = SSHPacket(data) cipher_name = packet.get_string() kdf = packet.get_string() kdf_data = packet.get_string() nkeys = packet.get_uint32() _ = packet.get_string() # public_key key_data = packet.get_string() mac = packet.get_remaining_payload() if nkeys != 1: raise KeyImportError('Invalid OpenSSH private key') if cipher_name != b'none': if not _bcrypt_available: # pragma: no cover raise KeyEncryptionError('OpenSSH private key encryption ' 'requires bcrypt') if passphrase is None: raise KeyImportError('Passphrase must be specified to import ' 'encrypted private keys') try: key_size, iv_size, block_size, mode = \ get_encryption_params(cipher_name) except KeyError: raise KeyEncryptionError('Unknown cipher: %s' % cipher_name.decode('ascii')) from None if kdf != b'bcrypt': raise KeyEncryptionError('Unknown kdf: %s' % kdf.decode('ascii')) packet = SSHPacket(kdf_data) salt = packet.get_string() rounds = packet.get_uint32() packet.check_end() if isinstance(passphrase, str): passphrase = passphrase.encode('utf-8') try: # pylint: disable=no-member key = bcrypt.kdf(passphrase, salt, key_size + iv_size, rounds) # pylint: enable=no-member except ValueError: raise KeyEncryptionError('Invalid OpenSSH ' 'private key') from None cipher = get_cipher(cipher_name, key[:key_size], key[key_size:]) if mode == 'chacha': key_data = cipher.verify_and_decrypt(b'', key_data, UInt64(0), mac) mac = b'' elif mode == 'gcm': key_data = cipher.verify_and_decrypt(b'', key_data, mac) mac = b'' else: key_data = cipher.decrypt(key_data) if key_data is None: raise KeyEncryptionError('Incorrect passphrase') block_size = max(block_size, 8) else: block_size = 8 if mac: raise KeyImportError('Invalid OpenSSH private key') packet = SSHPacket(key_data) check1 = packet.get_uint32() check2 = packet.get_uint32() if check1 != check2: if cipher_name != b'none': raise KeyEncryptionError('Incorrect passphrase') from None else: raise KeyImportError('Invalid OpenSSH private key') alg = packet.get_string() handler = _public_key_alg_map.get(alg) if not handler: raise KeyImportError('Unknown OpenSSH private key algorithm') key_params = handler.decode_ssh_private(packet) _ = packet.get_string() # comment pad = packet.get_remaining_payload() if len(pad) >= block_size or pad != bytes(range(1, len(pad) + 1)): raise KeyImportError('Invalid OpenSSH private key') return handler.make_private(*key_params) except PacketDecodeError: raise KeyImportError('Invalid OpenSSH private key')
def export_private_key(self, format_name, passphrase=None, cipher_name='aes256-cbc', hash_name='sha256', pbe_version=2, rounds=16): """Export a private key in the requested format This function returns this object's private key encoded in the requested format. If a passphrase is specified, the key will be exported in encrypted form. Available formats include: pkcs1-der, pkcs1-pem, pkcs8-der, pkcs8-pem, openssh Encryption is supported in pkcs1-pem, pkcs8-der, pkcs8-pem, and openssh formats. For pkcs1-pem, only the cipher can be specified. For pkcs8-der and pkcs-8, cipher, hash and PBE version can be specified. For openssh, cipher and rounds can be specified. Available ciphers for pkcs1-pem are: aes128-cbc, aes192-cbc, aes256-cbc, des-cbc, des3-cbc Available ciphers for pkcs8-der and pkcs8-pem are: aes128-cbc, aes192-cbc, aes256-cbc, blowfish-cbc, cast128-cbc, des-cbc, des2-cbc, des3-cbc, rc4-40, rc4-128 Available ciphers for openssh format include the following :ref:`encryption algorithms <EncryptionAlgs>`. Available hashes include: md5, sha1, sha256, sha384, sha512, sha512-224, sha512-256 Available PBE versions include 1 for PBES1 and 2 for PBES2. Not all combinations of cipher, hash, and version are supported. The default cipher is aes256. In the pkcs8 formats, the default hash is sha256 and default version is PBES2. In openssh format, the default number of rounds is 16. :param string format_name: The format to export the key in. :param string passphrase: (optional) A passphrase to encrypt the private key with. :param string cipher_name: (optional) The cipher to use for private key encryption. :param string hash_name: (optional) The hash to use for private key encryption. :param integer pbe_version: (optional) The PBE version to use for private key encryption. :param integer rounds: (optional) The number of KDF rounds to apply to the passphrase. """ if format_name in ('pkcs1-der', 'pkcs1-pem'): data = der_encode(self.encode_pkcs1_private()) if passphrase is not None: if format_name == 'pkcs1-der': raise KeyExportError('PKCS#1 DER format does not support ' 'private key encryption') alg, iv, data = pkcs1_encrypt(data, cipher_name, passphrase) headers = (b'Proc-Type: 4,ENCRYPTED\n' + b'DEK-Info: ' + alg + b',' + binascii.b2a_hex(iv).upper() + b'\n\n') else: headers = b'' if format_name == 'pkcs1-pem': keytype = self.pem_name + b' PRIVATE KEY' data = (b'-----BEGIN ' + keytype + b'-----\n' + headers + _wrap_base64(data) + b'-----END ' + keytype + b'-----\n') return data elif format_name in ('pkcs8-der', 'pkcs8-pem'): alg_params, data = self.encode_pkcs8_private() data = der_encode((0, (self.pkcs8_oid, alg_params), data)) if passphrase is not None: data = pkcs8_encrypt(data, cipher_name, hash_name, pbe_version, passphrase) if format_name == 'pkcs8-pem': if passphrase is not None: keytype = b'ENCRYPTED PRIVATE KEY' else: keytype = b'PRIVATE KEY' data = (b'-----BEGIN ' + keytype + b'-----\n' + _wrap_base64(data) + b'-----END ' + keytype + b'-----\n') return data elif format_name == 'openssh': check = os.urandom(4) nkeys = 1 comment = b'' keydata = String(self.algorithm) + self.encode_ssh_private() data = b''.join((check, check, keydata, String(comment))) if passphrase is not None: if not _bcrypt_available: # pragma: no cover raise KeyExportError('OpenSSH private key encryption ' 'requires bcrypt') try: alg = cipher_name.encode('ascii') key_size, iv_size, block_size, mode = \ get_encryption_params(alg) except (KeyError, UnicodeEncodeError): raise KeyEncryptionError('Unknown cipher: %s' % cipher_name) from None kdf = b'bcrypt' salt = os.urandom(_OPENSSH_SALT_LEN) kdf_data = b''.join((String(salt), UInt32(rounds))) if isinstance(passphrase, str): passphrase = passphrase.encode('utf-8') # pylint: disable=no-member key = bcrypt.kdf(passphrase, salt, key_size + iv_size, rounds) # pylint: enable=no-member cipher = get_cipher(alg, key[:key_size], key[key_size:]) block_size = max(block_size, 8) else: cipher = None alg = b'none' kdf = b'none' kdf_data = b'' block_size = 8 mac = b'' pad = len(data) % block_size if pad: # pragma: no branch data = data + bytes(range(1, block_size + 1 - pad)) if cipher: if mode == 'chacha': data, mac = cipher.encrypt_and_sign(b'', data, UInt64(0)) elif mode == 'gcm': data, mac = cipher.encrypt_and_sign(b'', data) else: data, mac = cipher.encrypt(data), b'' data = b''.join((_OPENSSH_KEY_V1, String(alg), String(kdf), String(kdf_data), UInt32(nkeys), String(self.get_ssh_public_key()), String(data), mac)) return (b'-----BEGIN OPENSSH PRIVATE KEY-----\n' + _wrap_base64(data, _OPENSSH_WRAP_LEN) + b'-----END OPENSSH PRIVATE KEY-----\n') else: raise KeyExportError('Unknown export format')
import sqlite3 import bcrypt import hashlib from Crypto.Cipher import AES import codecs import json from password import encrypt, decrypt, toHex, fromHex pwdatabase = 'passwords.db' jsonfile = open('passwords.json', mode='w') password = input('Enter password: '******'select * from master_pass').fetchone() if bcrypt.checkpw(password, pwHash): print('Password is correct.') aes_key = bcrypt.kdf(password, salt, 16, 32) records = [list(i) for i in conn.execute('select * from passwords')] for i in range(len(records)): records[i][3] = decrypt(aes_key, records[i][3]).decode() records[i][4] = decrypt(aes_key, records[i][4]).decode() json.dump(records, jsonfile, indent=2) else: print('Incorrect password.') jsonfile.close() conn.close()
def test_kdf_str_password(): with pytest.raises(TypeError): bcrypt.kdf( six.text_type("password"), b"$2b$04$cVWp4XaNU8a4v1uMRum2SO", 10, 10 )
def test_00__test_vectors(self): for rounds, password, salt, expected in kdf_test_vectors: key = bcrypt.kdf(password, salt, len(expected), rounds) self.assertEqual(key, expected)
def kdf(password, salt): '''Generate aes key from password and salt.''' return bcrypt.kdf(password, salt, 16, 32)
def test_kdf_str_salt(): with pytest.raises(TypeError): bcrypt.kdf( b"password", six.text_type("salt"), 10, 10 )
def test_invalid_params(password, salt, desired_key_bytes, rounds, error): with pytest.raises(error): bcrypt.kdf(password, salt, desired_key_bytes, rounds)
def export_private_key( self, format_name, passphrase=None, cipher_name="aes256-cbc", hash_name="sha256", pbe_version=2, rounds=16 ): """Export a private key in the requested format This function returns this object's private key encoded in the requested format. If a passphrase is specified, the key will be exported in encrypted form. Available formats include: pkcs1-der, pkcs1-pem, pkcs8-der, pkcs8-pem, openssh Encryption is supported in pkcs1-pem, pkcs8-der, pkcs8-pem, and openssh formats. For pkcs1-pem, only the cipher can be specified. For pkcs8-der and pkcs-8, cipher, hash and PBE version can be specified. For openssh, cipher and rounds can be specified. Available ciphers for pkcs1-pem are: aes128-cbc, aes192-cbc, aes256-cbc, des-cbc, des3-cbc Available ciphers for pkcs8-der and pkcs8-pem are: aes128-cbc, aes192-cbc, aes256-cbc, blowfish-cbc, cast128-cbc, des-cbc, des2-cbc, des3-cbc, rc2-40-cbc, rc2-64-cbc, rc2-128-cbc, rc4-40, rc4-128 Available ciphers for openssh format include the following :ref:`encryption algorithms <EncryptionAlgs>`. Available hashes include: md5, sha1, sha256, sha384, sha512, sha512-224, sha512-256 Available PBE versions include 1 for PBES1 and 2 for PBES2. Not all combinations of cipher, hash, and version are supported. The default cipher is aes256. In the pkcs8 formats, the default hash is sha256 and default version is PBES2. In openssh format, the default number of rounds is 16. :param string format_name: The format to export the key in. :param string passphrase: (optional) A passphrase to encrypt the private key with. :param string cipher_name: (optional) The cipher to use for private key encryption. :param string hash_name: (optional) The hash to use for private key encryption. :param integer pbe_version: (optional) The PBE version to use for private key encryption. :param integer rounds: (optional) The number of KDF rounds to apply to the passphrase. """ if format_name in ("pkcs1-der", "pkcs1-pem"): data = der_encode(self.encode_pkcs1_private()) if passphrase is not None: if format_name == "pkcs1-der": raise KeyExportError("PKCS#1 DER format does not support " "private key encryption") alg, iv, data = pkcs1_encrypt(data, cipher_name, passphrase) headers = ( b"Proc-Type: 4,ENCRYPTED\n" + b"DEK-Info: " + alg + b"," + binascii.b2a_hex(iv).upper() + b"\n\n" ) else: headers = b"" if format_name == "pkcs1-pem": keytype = self.pem_name + b" PRIVATE KEY" data = ( b"-----BEGIN " + keytype + b"-----\n" + headers + _wrap_base64(data) + b"-----END " + keytype + b"-----\n" ) return data elif format_name in ("pkcs8-der", "pkcs8-pem"): alg_params, data = self.encode_pkcs8_private() data = der_encode((0, (self.pkcs8_oid, alg_params), data)) if passphrase is not None: data = pkcs8_encrypt(data, cipher_name, hash_name, pbe_version, passphrase) if format_name == "pkcs8-pem": if passphrase is not None: keytype = b"ENCRYPTED PRIVATE KEY" else: keytype = b"PRIVATE KEY" data = b"-----BEGIN " + keytype + b"-----\n" + _wrap_base64(data) + b"-----END " + keytype + b"-----\n" return data elif format_name == "openssh": check = urandom(4) nkeys = 1 comment = b"" data = b"".join((check, check, self.encode_ssh_private(), String(comment))) if passphrase is not None: if not _bcrypt_available: raise KeyExportError("OpenSSH private key encryption " "requires bcrypt") try: alg = cipher_name.encode("ascii") key_size, iv_size, block_size, mode = get_encryption_params(alg) except (KeyError, UnicodeEncodeError): raise KeyEncryptionError("Unknown cipher: %s" % cipher_name) from None kdf = b"bcrypt" salt = urandom(_OPENSSH_SALT_LEN) kdf_data = b"".join((String(salt), UInt32(rounds))) # pylint: disable=no-member key = bcrypt.kdf(passphrase.encode("utf-8"), salt, key_size + iv_size, rounds) # pylint: enable=no-member cipher = get_cipher(alg, key[:key_size], key[key_size:]) block_size = max(block_size, 8) else: cipher = None alg = b"none" kdf = b"none" kdf_data = b"" block_size = 8 mac = b"" pad = len(data) % block_size if pad: data = data + bytes(range(1, block_size + 1 - pad)) if cipher: if mode == "chacha": data, mac = cipher.encrypt_and_sign(b"", data, UInt64(0)) elif mode == "gcm": data, mac = cipher.encrypt_and_sign(b"", data) else: data, mac = cipher.encrypt(data), b"" data = b"".join( ( _OPENSSH_KEY_V1, String(alg), String(kdf), String(kdf_data), UInt32(nkeys), String(self.encode_ssh_public()), String(data), mac, ) ) return ( b"-----BEGIN OPENSSH PRIVATE KEY-----\n" + _wrap_base64(data, _OPENSSH_WRAP_LEN) + b"-----END OPENSSH PRIVATE KEY-----\n" ) else: raise KeyExportError("Unknown export format")
def _decode_openssh_private(data, passphrase): """Decode an OpenSSH format private key""" try: if not data.startswith(_OPENSSH_KEY_V1): raise KeyImportError("Unrecognized OpenSSH private key type") data = data[len(_OPENSSH_KEY_V1) :] packet = SSHPacket(data) cipher_name = packet.get_string() kdf = packet.get_string() kdf_data = packet.get_string() nkeys = packet.get_uint32() _ = packet.get_string() # public_key key_data = packet.get_string() mac = packet.get_remaining_payload() if nkeys != 1: raise KeyImportError("Invalid OpenSSH private key") if cipher_name != b"none": if not _bcrypt_available: raise KeyEncryptionError("OpenSSH private key encryption " "requires bcrypt") if passphrase is None: raise KeyEncryptionError("Passphrase must be specified to " "import encrypted private keys") try: key_size, iv_size, block_size, mode = get_encryption_params(cipher_name) except KeyError: raise KeyEncryptionError("Unknown cipher: %s" % cipher_name.decode("ascii")) from None if kdf != b"bcrypt": raise KeyEncryptionError("Unknown kdf: %s" % kdf.decode("ascii")) packet = SSHPacket(kdf_data) salt = packet.get_string() rounds = packet.get_uint32() packet.check_end() # pylint: disable=no-member key = bcrypt.kdf(passphrase.encode("utf-8"), salt, key_size + iv_size, rounds) # pylint: enable=no-member cipher = get_cipher(cipher_name, key[:key_size], key[key_size:]) if mode == "chacha": key_data = cipher.verify_and_decrypt(b"", key_data, UInt64(0), mac) mac = b"" elif mode == "gcm": key_data = cipher.verify_and_decrypt(b"", key_data, mac) mac = b"" else: key_data = cipher.decrypt(key_data) if key_data is None: raise KeyEncryptionError("Incorrect passphrase") from None block_size = max(block_size, 8) else: block_size = 8 if mac: raise KeyEncryptionError("Invalid OpenSSH private key") packet = SSHPacket(key_data) check1 = packet.get_uint32() check2 = packet.get_uint32() if check1 != check2: raise KeyImportError("Invalid OpenSSH private key") alg = packet.get_string() handler = _public_key_alg_map.get(alg) if not handler: raise KeyImportError("Unknown OpenSSH private key algorithm") key_params = handler.decode_ssh_private(packet) _ = packet.get_string() # comment pad = packet.get_remaining_payload() if len(pad) >= block_size or pad != bytes(range(1, len(pad) + 1)): raise KeyImportError("Invalid OpenSSH private key") if not key_params: raise KeyImportError("Invalid %s private key" % handler.pem_name.decode("ascii")) return handler.make_private(*key_params) except DisconnectError: raise KeyImportError("Invalid OpenSSH private key")