def setUp(self): self.kdb_orig = libkeepass.open(kdbf_t0, password="******") self.kdb_dest = libkeepass.open(kdbf_t0, password="******") self.kdb_src = libkeepass.open(kdbf_t0, password="******") self.kdbm = libkeepass.utils.merge.KDB4UUIDMerge(self.kdb_orig, self.kdb_orig, debug=False)
def setUp(self): self.kdb_dest = libkeepass.open(kdbf_t0, password="******", unprotect=True) self.kdb_src = libkeepass.open(kdbf_t1, password="******", unprotect=True)
def test_write_file(self): # valid password and plain keyfile, compressed kdb with libkeepass.open(absfile1, password="******") as kdb: self.assertEquals(kdb.opened, True) self.assertEquals(kdb.read(32), b'<?xml version="1.0" encoding="ut') kdb.set_compression(0) # kdb.set_comment("this is pretty cool!") kdb.clear_credentials() kdb.add_credentials(password="******") with open(output1, 'wb') as outfile: kdb.write_to(outfile) with libkeepass.open(output1, password="******") as kdb: self.assertEquals(kdb.read(32), b"<?xml version='1.0' encoding='ut") with libkeepass.open(absfile4, password="******", keyfile=keyfile4) as kdb: self.assertEquals(kdb.opened, True) self.assertEquals(kdb.read(32), b'<?xml version="1.0" encoding="ut') with open(output4, 'wb') as outfile: kdb.write_to(outfile) with libkeepass.open(output4, password="******", keyfile=keyfile4) as kdb: self.assertEquals(kdb.read(32), b"<?xml version='1.0' encoding='ut")
def get_entry(self, title): if self.databasefile == None or self.password == None: self._logger.error('Not initialized...') return None with libkeepass.open(self.databasefile, password = self.password) as kdb: found = False for entry in kdb.obj_root.findall('.//Entry'): for string in entry.findall('.//String'): if string.find('.//Key') != 'Title': continue if string.find('.//Value') == title: found = True break if found: for sting in entry.findall('.//String'): if sting.find('.//Key') == 'Notes': notes = sting.find('.//Value') elif sting.find('.//Key') == 'Password': password = sting.find('.//Value') elif sting.find('.//Key') == 'Title': title = sting.find('.//Value') elif sting.find('.//Key') == 'URL': url = sting.find('.//Value') elif sting.find('.//Key') == 'UserName': username = sting.find('.//Value') return KeePassEntry(notes, password, title, url, username) return None
def get_entry(self, title): if self.databasefile == None or self.password == None: print 'Not initalized' return None with libkeepass.open(self.databasefile, password = self.password) as kdb: found = False for entry in kdb.obj_root.findall('.//Entry'): for string in entry.findall('.//String'): if string.find('.//Key') != 'Title': continue if string.find('.//Value') == title: found = True break if found: for sting in entry.findall('.//String'): if sting.find('.//Key') == 'Notes': notes = sting.find('.//Value') elif sting.find('.//Key') == 'Password': password = sting.find('.//Value') elif sting.find('.//Key') == 'Title': title = sting.find('.//Value') elif sting.find('.//Key') == 'URL': url = sting.find('.//Value') elif sting.find('.//Key') == 'UserName': username = sting.find('.//Value') return KeePassEntry(notes, password, title, url, username) return None
def keepass(kpfile, keyfile, password): if os.path.exists(kpfile) and os.access(kpfile, os.R_OK) and os.path.exists(keyfile) and os.access(keyfile, os.R_OK): with libkeepass.open(kpfile, password=password, keyfile=keyfile) as kp: result = kp.pretty_print() kp.protect()
def try_open_db(db, key): try: return libkeepass.open(db, password=key) except IOError as e: if 'Master key invalid' in e.message: return None else: raise IOError(e.message)
def test_open_file_protected(self): # old kdb file with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") with libkeepass.open(absfile2, password="******", unprotect=False) as kdb: self.assertIsNotNone(kdb) self.assertEqual(w[0].category, UserWarning) self.assertTrue("KDB3 files do not support protected reading, " \ "the keyword will be ignored." in str(w[0].message))
def run(self, software_name = None): # password found on the memory dump class if constant.keepass: try: with libkeepass.open(constant.keepass['Database'], password=constant.keepass['Password'], keyfile=constant.keepass['KeyFilePath']) as kdb: pwdFound = kdb.to_dic() return pwdFound except: pass
def test_merge_self(self): """Test direct KDB4Reader class usage""" with libkeepass.open(kdbf_t0, password="******") as kdb_dest, \ libkeepass.open(kdbf_t0, password="******") as kdb_src: kdbm = libkeepass.utils.merge.KDB4UUIDMerge(kdb_dest, kdb_src, debug=False) kdbm.merge() # Merging file into itself, should have no effect self.assertEqual(kdb_dest.pretty_print(), kdb_src.pretty_print()) # Check using KDBEqual with all checks on eq = libkeepass.utils.check.KDBEqual(metadata=True, history=True, ignore_attrs=False, ignore_times=True) is_eq = eq.equal(kdb_dest, kdb_src) self.assertTrue(is_eq, msg="KDB not equal: %r" % (eq.error.msg, ))
def test_merge_t0_into_t1(self): with libkeepass.open(kdbf_t1, password="******") as kdb_orig, \ libkeepass.open(kdbf_t1, password="******") as kdb_dest, \ libkeepass.open(kdbf_t0, password="******") as kdb_src: dest_kdbxml_orig = kdb_dest.pretty_print() kdbm = libkeepass.utils.merge.KDB4UUIDMerge(kdb_dest, kdb_src, debug=False) kdbm.merge() # Merging ancestor into decendant should have no effect self.assertEqual(kdb_dest.pretty_print(), dest_kdbxml_orig) # Check using KDBEqual with all checks on eq = libkeepass.utils.check.KDBEqual(metadata=True, history=True, ignore_attrs=False) is_eq = eq.equal(kdb_dest, kdb_orig) self.assertTrue(is_eq, msg="KDB not equal: %r" % (eq.error.msg, ))
def kdbfile_shell(args): open_args = {} if 'keyfile' in args: open_args['keyfile'] = args.keyfile if 'passwords' in args: open_args['unprotect'] = args.passwords with OpenKDBXFiles(args.kdbfiles) as kdbfiles: code.interact(local=dict(kdbfiles=kdbfiles)) return kdbfiles = [] creds_list = [] prompt = 'Password: '******'' if ntry > 0: tries_s = ' (try {})'.format(ntry) prompt = '{} Password{}: '.format(kdbfile, tries_s) creds = {} if crlist: creds = crlist.pop() else: # Only increment ntry, when the user actually inputs a # password ntry += 1 creds = {'password': getpass.getpass(prompt=prompt)} if 'keyfile' in args: creds['keyfile'] = args.keyfile kwargs = creds kwargs['unprotect'] = args.passwords with libkeepass.open(os.path.expanduser(kdbfile), mode='rb', **kwargs) as kdb: kdb.pretty_print() if isinstance(kdb, libkeepass.kdb3.KDB3File): for g in kdb.groups: print(g['title'], g['group_id'], g['level'], g.get('groups', None), g.get('path', '!')) kdbfiles.append(kdb) creds_list.append(creds) break except OSError as ex: print(ex) else: del creds_list code.interact(local=dict(kdbfiles=kdbfiles))
def read(self, filename=None, password=None, keyfile=None): if not filename: filename = self.kdb_filename credentials = {} if password: credentials['password'] = password if keyfile: credentials['keyfile'] = keyfile assert filename, 'Filename should not be empty' logger.debug('Open file {}'.format(filename)) return libkeepass.open(filename, **credentials).__enter__()
def test_write_file(self): # valid password and plain keyfile, compressed kdb with libkeepass.open(absfile1, password="******") as kdb: self.assertEquals(kdb.opened, True) self.assertEquals(kdb.read(32), b'<?xml version="1.0" encoding="ut') kdb.set_compression(0) #kdb.set_comment("this is pretty cool!") kdb.clear_credentials() kdb.add_credentials(password="******") with open(output1, 'wb') as outfile: kdb.write_to(outfile) with libkeepass.open(output1, password="******") as kdb: self.assertEquals(kdb.read(32), b"<?xml version='1.0' encoding='ut") with libkeepass.open(absfile4, password="******", keyfile=keyfile4) as kdb: self.assertEquals(kdb.opened, True) self.assertEquals(kdb.read(32), b'<?xml version="1.0" encoding="ut') with open(output4, 'wb') as outfile: kdb.write_to(outfile) with libkeepass.open(output4, password="******", keyfile=keyfile4) as kdb: self.assertEquals(kdb.read(32), b"<?xml version='1.0' encoding='ut")
def load_kpx_db(self): """ Returns KPX DB data """ try: with libkeepass.open(self.kpx_db_path, password=self.kpx_db_password) as kpx_db: data = bf.data(fromstring(kpx_db.pretty_print())) except Exception: print("Script wasn't able to read KPX DB") raise else: return data
def run(self): # password found on the memory dump class if constant.keepass: res = [] for db in constant.keepass: try: with libkeepass.open(db.values()[0][u'Database'], password=db.get(u"KcpPassword", {}).get(u'Password'), keyfile=db.get(u"KcpKeyFile", {}).get(u'KeyFilePath')) as kdb: res.extend(kdb.to_dic()) except Exception: self.debug(traceback.format_exc()) return res
def kdbfile_dump(args): kdbfile = args.kdbfile kdbxmlfile = args.outfile pwd = getpass.getpass() try: with libkeepass.open(os.path.expanduser(kdbfile), password=pwd) as kdb: if kdbxmlfile == '-': print(kdb.pretty_print(True)) else: with open(kdbxmlfile, 'wb') as wf: wf.write(kdb.pretty_print()) except OSError as ex: print(ex)
def do_open(self, arg): """Open a file""" pwd = getpass.getpass() try: with libkeepass.open(os.path.expanduser(arg), password=pwd) as kdb: kdbx_data = kdb.pretty_print() self.root = lxml.etree.fromstring(kdbx_data) self.tree = lxml.etree.ElementTree(self.root) self.current_group = self.tree.xpath("/KeePassFile/Root/Group")[0] self.current_path = '/' + self.current_group.find('Name').text self.filename = arg self.prompt = self._prompt() except OSError as ex: print(ex)
def test_verify_kdb3(self): with libkeepass.open(absfile2, password="******") as kdb: self.assertEqual([e['title'] for e in kdb.groups], ['Internet', 'eMail']) self.assertEqual(len(kdb.entries), 1) verify_entry = kdb.entries[0].copy() verify_entry.update({ 'username': '******', 'password': '******', 'url': 'asdf', 'title': 'asdf', 'group_id': 623687138, 'group': 'Internet', 'modified': datetime.datetime(2012, 7, 20, 20, 27, 2), }) self.assertEqual(kdb.entries[0], verify_entry)
def do_open(self, arg): """Open a file""" pwd = getpass.getpass() try: with libkeepass.open(os.path.expanduser(arg), password=pwd) as kdb: kdbx_data = kdb.pretty_print() self.root = lxml.etree.fromstring(kdbx_data) self.tree = lxml.etree.ElementTree(self.root) self.current_group = self.tree.xpath( "/KeePassFile/Root/Group")[0] self.current_path = '/' + self.current_group.find('Name').text self.filename = arg self.prompt = self._prompt() except OSError as ex: print(ex)
def human_readable_dump(): with libkeepass.open(filename=sys.argv[1], password=sys.argv[2]) as kdb: root = kdb.tree.getroot() for group in root.Root.iter('Group'): try: print "GROUP:", group.Name for Entry in group.iter('Entry'): print "\t" + "=" * 80 for string in Entry.iter('String'): print "\t\t" + "-" * 80 print "\t\t" + string['Key'] + ":" + string['Value'] except: pass print "=" * 80
def export_entries(filename, password, keyfile=None, force_lowercase=False, skip_root=False): with libkeepass.open(filename, password=password, keyfile=keyfile) as kdb: xmldata = lxml.etree.fromstring(kdb.pretty_print()) tree = lxml.etree.ElementTree(xmldata) root_group = tree.xpath('/KeePassFile/Root/Group')[0] all_entries = export_entries_from_group( xmldata, root_group, force_lowercase=force_lowercase ) if skip_root: regex = re.compile(r'^{}/?'.format(get_group_name(root_group))) for e in all_entries: e['_path'] = regex.sub('', e['_path']) logger.info('Total entries: {}'.format(len(all_entries))) return all_entries
def main(): args = build_parser().parse_args() with libkeepass.open(args.kdbx, password=getpass.getpass(), mode='rb') as kdb: for entry in kdb.obj_root.findall('.//Group/Entry'): uuid = entry.find('./UUID').text kv = {string.find('./Key').text: string.find('./Value').text for string in entry.findall('./String')} if not kv['Password']: continue r = check_hash(kv['Password']) if r > 0: m = 'Password for %s (%s) seen %d times before' % (kv['Title'], uuid, r) if args.show_user: m += ' - %s' % kv.get('UserName') if args.show_password: m += ' - %s' % kv['Password'] print(m)
def get_host_vars(self, host, vault_password=None): """ Get host specific variables. """ # print "Host Invoke for %s " % host.name if "--ask-su-pass" in sys.argv: x_auth_system = host.get_variables().get("x_auth_system") x_auth_system_kdb = host.get_variables().get("x_auth_system_kdb") x_auth_system_master_key = host.get_variables().get("x_auth_system_master_key") passwd = "" ps = host.get_variables().get("ansible_su_pass") if ps is None: if x_auth_system == "keepass": x_auth_system_kdb = host.get_variables().get("x_auth_system_kdb") x_auth_system_master_key = host.get_variables().get("x_auth_system_master_key") if x_auth_system_kdb is None: x_auth_system_kdb = raw_input( "Provide full path to keepass kdb file: ") host.set_variable('x_auth_system_kdb', x_auth_system_kdb) if x_auth_system_master_key is None: prmt = "Enter keepass vault password for host "+host.name+": " x_auth_system_master_key = getpass.getpass(prompt = prmt) host.set_variable('x_auth_system_master_key', x_auth_system_master_key) rez = {} with libkeepass.open( x_auth_system_kdb , password = x_auth_system_master_key ) as kdb: xmldata = ET.fromstring(kdb.pretty_print()) for history in xmldata.xpath(".//History"): history.getparent().remove(history) for el in xmldata.findall('.//Entry'): uuid = el.find('./UUID').text rez[uuid] = {} for elem in el.findall('./String'): key = elem.find('./Key').text val = elem.find('./Value').text rez[uuid][key] = val for elem in rez.keys(): if rez[elem]['Title'] == host.name and rez[elem]['UserName'] == 'root' : passwd = rez[elem]['Password'] # print passwd, host.name else: raise Exception("Unknown Authentication System %s for host %s" % (x_auth_system, host.name)) if passwd == "": passwd = getpass.getpass(prompt="%s su password: " % host.name) host.set_variable('ansible_su_pass', passwd)
def get_keepass_pw(dbpath, title="", username=""): if os.path.isfile(dbpath): with libkeepass.open( os.path.expanduser(dbpath), password=getpass.getpass("Master password for '" + dbpath + "': ")) as kdb: entry = kdb.tree.xpath( './/Entry' '/String/Key[.="Title"]/../Value[.="{title}"]/../..' '/String/Key[.="UserName"]/../Value[.="{username}"]/../..' '/String/Key[.="Password"]/../Value'.format( title=title, username=username ) )[0] return entry.text else: print("Error: '" + dbpath + "' does not exist.") return
def export_entries(filename, password, keyfile=None): """ Get total entries exported from keepass file. """ with libkeepass.open(filename, password=password, keyfile=keyfile) as kdb: xmldata = lxml.etree.fromstring( kdb.pretty_print()) # Get keepass data in xml format tree = lxml.etree.ElementTree( xmldata) # Get the xml object of keepass data root_group = tree.xpath('/KeePassFile/Root/Group')[ 0] # Get the keepass file's root group all_entries = export_entries_from_group( xmldata, root_group) # Get all entries from keepass return all_entries
def kdbfile_convert4(args): kdbinfile = args.kdbinfile kdboutfile = args.kdboutfile pwd = getpass.getpass() try: with libkeepass.open(os.path.expanduser(kdbinfile), password=pwd) as kdb3: assert isinstance(kdb3, libkeepass.kdb3.KDB3File) with open(kdboutfile, 'wb') as wf: kdb4 = libkeepass.utils.convert_kdb3_to_kdb4(kdb3) kdb4.write_to(wf) if args.debugfile: with open(args.debugfile, 'wb') as wf: wf.write(kdb4.pretty_print()) if args.debug: code.interact(local=dict(kdb3=kdb3, kdb4=kdb4)) except OSError as ex: print(ex)
def get_keepass_pw(dbpath, title="", username=""): if os.path.isfile(dbpath): with libkeepass.open( os.path.expanduser(dbpath), password=getpass.getpass( "Master password for '" + dbpath + "': ")) as kdb: entry = kdb.tree.xpath( './/Entry' '/String/Key[.="Title"]/../Value[.="{title}"]/../..' '/String/Key[.="UserName"]/../Value[.="{username}"]/../..' '/String/Key[.="Password"]/../Value'.format( title=title, username=username ) )[0] return entry.text else: print "Error: Bad input filename." return
def load_cache(self): with libkeepass.open(self.kee_pass_file, password=self.session.session) as kpdb: self.session.write() self.entries = [] for kpEntry in kpdb.obj_root.findall('.//Entry'): simple_entry = SimpleEntry(None, [], None) for s in kpEntry.findall('./String'): key = s.find('./Key').text val = s.find('./Value').text if val is not None and val != '': if key == 'URL': simple_entry.addresses.append(val) elif key == 'Password': simple_entry.password = val elif key == 'UserName': simple_entry.username = val elif key == 'Title': simple_entry.name = val if simple_entry.name is not None and simple_entry.password is not None: self.entries.append(simple_entry)
def __enter__(self): creds_list = [] prompt = 'Password: '******'' if ntry > 0: tries_s = ' (try {})'.format(ntry) prompt = '{} Password{}: '.format(kdbfile, tries_s) creds = {} if crlist: creds = crlist.pop() else: # Only increment ntry, when the user actually inputs a # password ntry += 1 creds = {'password': getpass.getpass(prompt=prompt)} if self.keyfiles: creds['keyfile'] = self.keyfiles kwargs = creds kwargs['unprotect'] = self.unprotect with libkeepass.open(os.path.expanduser(kdbfile), mode='rb', **kwargs) as kdb: self.kdbs.append(kdb) creds_list.append(creds) break except OSError as ex: print(ex) else: del creds_list return self.kdbs
def get_host_vars(self, host, vault_password=None): """ Get host specific variables. """ print "Host Invoke for %s" % host.name if "--ask-su-pass" in sys.argv: x_auth_system = host.get_variables().get("x_auth_system") x_auth_system_kdb = host.get_variables().get("x_auth_system_kdb") x_auth_system_master_key = host.get_variables().get("x_auth_system_master_key") ps = host.get_variables().get("ansible_su_pass") if ps is None: if x_auth_system == "keepass": x_auth_system_kdb = host.get_variables().get("x_auth_system_kdb") x_auth_system_master_key = host.get_variables().get("x_auth_system_master_key") if x_auth_system_kdb is None: x_auth_system_kdb = raw_input("Provide full path to keepass kdb file: ") host.set_variable("x_auth_system_kdb", x_auth_system_kdb) if x_auth_system_master_key is None: x_auth_system_master_key = getpass.getpass(prompt="Enter keepass vault password: "******"x_auth_system_master_key", x_auth_system_master_key) rez = {} with libkeepass.open(x_auth_system_kdb, password=x_auth_system_master_key) as kdb: for el in kdb.obj_root.findall(".//Entry"): uuid = el.find("UUID").text rez[uuid] = {} for elem in el.findall(".//String"): key = elem.find("Key").text val = elem.find("Value").text rez[uuid][key] = val for elem in rez.keys(): if rez[elem]["Title"] == host.name and rez[elem]["UserName"] == "root": passwd = rez[elem]["Password"] # print passwd, host.name else: raise Exception("Unknown Authentication System %s for host %s" % (x_auth_system, host.name)) if passwd is None: passwd = getpass.getpass(prompt="%s: su password" % x_auth_system) host.set_variable("ansible_su_pass", passwd)
def scan_kdb(file, password, compare): '''Returns a dict with all Groups/Entries in a KDB file.''' paths = {'/KeePassFile/Root': ['']} items = {} with libkeepass.open(file, password=password) as kdb: for item in itertools.chain(kdb.obj_root.findall('.//Group'), kdb.obj_root.findall('.//Group/Entry')): parent = item.getroottree().getpath(item.getparent()) strings = find_item_strings(item) if item.tag == 'Group': name = item.find('./Name').text elif item.tag == 'Entry': name = strings['Title'] path = paths[parent] + [name] paths[item.getroottree().getpath(item)] = path path_display = '/'.join(path) if item.tag == 'Group': path_display += '/' key = path if compare == 'uuid': key = item.find('./UUID').text parent_id = '' if len(paths[parent]) > 1: parent_id = item.getparent().find('./UUID').text elif compare == 'path': key = tuple(path) parent_id = '/'.join(paths[parent]) + '/' else: raise NotImplementedError("Unrecognized compare method") items[key] = Node(item, path_display, item.find('./UUID').text, strings, parent_id) return items
def setUp(self): self.kdb_orig = libkeepass.open(kdbf_t0, password="******") self.kdbm = libkeepass.utils.merge.KDB4UUIDMerge(self.kdb_orig, self.kdb_orig, debug=False) uuid = 'spHmZwBbGUuqvbi/mVCknw==' self.entry = self.kdb_orig.obj_root.find(".//Entry[UUID='" + uuid + "']") # Add some more history elements self.entry.History.clear() n = 10 for i in range(n): ce = copy.deepcopy(self.entry) ce.remove(ce.History) modtime = libkeepass.utils.parse_timestamp( ce.Times.LastModificationTime.text) modtime_str = "{:%Y-%m-%dT%H:%M:%S}Z".format( modtime - datetime.timedelta(n - i - 1, 60)) ce.Times.LastModificationTime._setText(modtime_str) self.entry.History.append(ce) self.entry2 = copy.deepcopy(self.entry)
def do_import(self, filename): password = getpass.getpass(prompt='...' + 'Keepass Password'.rjust(20) + ': ', stream=None) with libkeepass.open(filename, password=password) as kdb: root = kdb.obj_root.find('Root/Group') if root is not None: groups = [root] pos = 0 while pos < len(groups): g = groups[pos] groups.extend(g.findall('Group')) pos = pos + 1 # Shared Folders for group in groups: if hasattr(group, 'Keeper'): keeper = group.Keeper if hasattr(keeper, 'IsShared'): if keeper.IsShared: sf = SharedFolder() sf.uid = base64.urlsafe_b64encode( base64.b64decode( group.UUID.text)).decode().rstrip('=') sf.path = KeepassImporter.get_folder(group) for sn in keeper.iterchildren(): if sn.tag == 'ManageUsers': sf.manage_users = sn == True elif sn.tag == 'ManageRecords': sf.manage_records = sn == True elif sn.tag == 'CanEdit': sf.can_edit = sn == True elif sn.tag == 'CanShare': sf.can_share = sn == True elif sn.tag == 'Permission': perm = Permission() if sf.permissions is None: sf.permissions = [] sf.permissions.append(perm) for p in sn.iterchildren(): if p.tag == 'UUID': perm.uid = base64.urlsafe_b64encode( base64.b64decode(p.text) ).decode().rstrip('=') elif p.tag == 'Name': perm.name = p.text elif p.tag == 'ManageUsers': perm.manage_users = p == True elif p.tag == 'ManageRecords': perm.manage_records = p == True yield sf for group in groups: entries = group.findall('Entry') if len(entries) > 0: folder = KeepassImporter.get_folder(group) for entry in entries: record = Record() fol = Folder() fol.path = folder record.folders = [fol] if hasattr(entry, 'UUID'): record.record_uid = base64.urlsafe_b64encode( base64.b64decode( entry.UUID.text)).decode().rstrip('=') if hasattr(entry, 'Keeper'): for sn in entry.Keeper.iterchildren(): if sn.tag == 'CanEdit': fol.can_edit = sn == True elif sn.tag == 'CanShare': fol.can_share = sn == True elif sn.tag == 'Link': f = Folder() for p in sn: if p.tag == 'Domain': f.domain = p.text elif p.tag == 'Path': f.path = p.text elif p.tag == 'CanEdit': f.can_edit = p == True elif p.tag == 'CanShare': f.can_share = p == True if f.domain or f.path: record.folders.append(f) for node in entry.findall('String'): sn = node.find('Key') if sn is None: continue key = sn.text sn = node.find('Value') if sn is None: continue value = sn.text if key == 'Title': record.title = value elif key == 'UserName': record.login = value elif key == 'Password': record.password = value elif key == 'URL': record.login_url = value elif key == 'Notes': record.notes = value else: record.custom_fields[key] = value if hasattr(kdb.obj_root.Meta, 'Binaries'): for bin in entry.findall('Binary'): try: ref = bin.Value.get('Ref') if ref: binary = kdb.obj_root.Meta.Binaries.find( 'Binary[@ID="{0}"]'.format( ref)) if binary: if record.attachments is None: record.attachments = [] atta = KeepassAttachment( binary) atta.name = bin.Key.text record.attachments.append(atta) except: pass yield record
def do_export(self, filename, records): print('Choose password for your Keepass file') master_password = getpass.getpass(prompt='...' + 'Keepass Password'.rjust(20) + ': ', stream=None) sfs = [] # type: [SharedFolder] rs = [] # type: [Record] for x in records: if type(x) is Record: rs.append(x) elif type(x) is SharedFolder: sfs.append(x) template_file = os.path.join(os.path.dirname(__file__), 'template.kdbx') with libkeepass.open(template_file, password='******') as kdb: root = kdb.obj_root.Root.Group for sf in sfs: comps = list(path_components(sf.path)) node = root for i in range(len(comps)): comp = comps[i] sub_node = node.find('Group[Name=\'{0}\']'.format(comp)) if sub_node is None: sub_node = objectify.Element('Group') sub_node.UUID = base64.b64encode( os.urandom(16)).decode() sub_node.Name = comp node.append(sub_node) if i == len(comps) - 1: # store Keeper specific info keeper = sub_node.find('Keeper') if keeper is None: keeper = objectify.Element('Keeper') sub_node.append(keeper) else: keeper.clear() keeper.IsShared = True keeper.ManageUsers = sf.manage_users keeper.ManageRecords = sf.manage_records keeper.CanEdit = sf.can_edit keeper.CanShare = sf.can_share if sf.permissions: for perm in sf.permissions: permission = objectify.Element('Permission') if perm.uid: permission.UUID = base64.b64encode( base64.urlsafe_b64decode( perm.uid + '==')).decode() permission.Name = perm.name permission.ManageUsers = perm.manage_users permission.ManageRecords = perm.manage_records keeper.append(permission) node = sub_node for r in rs: try: node = kdb.obj_root.Root.Group fol = None if r.folders: fol = r.folders[0] for is_shared in [True, False]: path = fol.domain if is_shared else fol.path if path: comps = list(path_components(path)) for i in range(len(comps)): comp = comps[i] sub_node = node.find( 'Group[Name=\'{0}\']'.format(comp)) if sub_node is None: sub_node = objectify.Element('Group') sub_node.UUID = base64.b64encode( os.urandom(16)).decode() sub_node.Name = comp node.append(sub_node) node = sub_node entry = None entries = node.findall('Entry') if len(entries) > 0: for en in entries: title = '' login = '' password = '' if hasattr(en, 'String'): for sn in en.String: if hasattr(sn, 'Key') and hasattr( sn, 'Value'): key = sn.Key.text value = sn.Value.text if key == 'Title': title = value elif key == 'UserName': login = value elif key == 'Password': password = value if title == r.title and login == r.login and password == r.password: entry = node break strings = {'URL': r.login_url, 'Notes': r.notes} if r.custom_fields: for cf in r.custom_fields: strings[cf] = r.custom_fields[cf] if entry is None: entry = objectify.Element('Entry') if r.uid: entry.UUID = base64.b64encode( base64.urlsafe_b64decode(r.uid + '==')).decode() else: entry.UUID = base64.b64encode( os.urandom(16)).decode() node.append(entry) strings['Title'] = r.title, strings['UserName'] = r.login, strings['Password'] = r.password, else: for str_node in entry.findall('String'): if hasattr(str_node, 'Key'): key = str_node.Key if key in strings: value = strings[key] if value: str_node.Value = value strings.pop(key) if not fol is None: if fol.domain: keeper = entry.find('Keeper') if keeper is None: keeper = objectify.Element('Keeper') entry.append(keeper) else: keeper.clear() keeper.CanEdit = fol.can_edit keeper.CanShare = fol.can_share for f in r.folders[1:]: link = objectify.Element('Link') keeper.append(link) if f.domain: link.Domain = f.domain link.CanEdit = f.can_edit link.CanShare = f.can_share if f.path: link.Path = f.Path for key in strings: value = strings[key] if value: s_node = objectify.Element('String') s_node.Key = key s_node.Value = value entry.append(s_node) if r.attachments: for atta in r.attachments: max_size = 1024 * 1024 if atta.size < max_size: bins = None bId = 0 if hasattr(kdb.obj_root.Meta, 'Binaries'): bins = kdb.obj_root.Meta.Binaries elems = bins.findall('Binary') bId = len(elems) else: bins = objectify.Element('Binaries') kdb.obj_root.Meta.append(bins) bId = 0 with atta.open() as s: buffer = s.read(max_size) if len(buffer) >= 32: iv = buffer[:16] cipher = AES.new( atta.key, AES.MODE_CBC, iv) buffer = cipher.decrypt(buffer[16:]) if len(buffer) > 0: buffer = unpad_binary(buffer) out = io.BytesIO() with gzip.GzipFile(fileobj=out, mode='w') as gz: gz.write(buffer) bin = objectify.E.Binary( base64.b64encode( out.getvalue()).decode(), Compressed=str(True), ID=str(bId)) bins.append(bin) bin = objectify.Element('Binary') bin.Key = atta.name bin.Value = objectify.Element( 'Value', Ref=str(bId)) entry.append(bin) else: print( 'Warning: File \'{0}\' was skipped because it exceeds the 1MB Keepass filesize limit.' .format(atta.name)) except Exception as e: pass objectify.deannotate(root, xsi_nil=True) etree.cleanup_namespaces(root) kdb.clear_credentials() kdb.add_credentials(password=master_password) with open(filename, 'wb') as output: kdb.write_to(output)
def test_open_file(self): # file not found, proper exception gets re-raised with self.assertRaisesRegexp(IOError, "No such file or directory"): with libkeepass.open(filename1, password="******"): pass # invalid password with self.assertRaisesRegexp(IndexError, "No credentials found."): with libkeepass.open(absfile1): pass # invalid password with self.assertRaisesRegexp(IOError, "Master key invalid."): with libkeepass.open(absfile1, password="******"): pass # invalid keyfile with self.assertRaisesRegexp(IOError, "Master key invalid."): with libkeepass.open(absfile1, password="******", keyfile="invalid"): pass # old kdb file with libkeepass.open(absfile2, password="******") as kdb: self.assertIsNotNone(kdb) self.assertEquals(kdb.opened, True) # valid password with libkeepass.open(absfile1, password="******") as kdb: self.assertIsNotNone(kdb) self.assertEquals(kdb.opened, True) self.assertIsInstance(kdb, libkeepass.kdb4.KDB4Reader) # valid password and xml keyfile with libkeepass.open(absfile3, password="******", keyfile=keyfile3) as kdb: self.assertIsNotNone(kdb) self.assertEquals(kdb.opened, True) self.assertIsInstance(kdb, libkeepass.kdb4.KDB4Reader) # valid password and plain keyfile, compressed kdb with libkeepass.open(absfile4, password="******", keyfile=keyfile4) as kdb: self.assertIsNotNone(kdb) self.assertEquals(kdb.opened, True) self.assertIsInstance(kdb, libkeepass.kdb4.KDB4Reader) # read raw data tmp1 = kdb.read(32) tmp2 = kdb.read(32) self.assertIsNotNone(tmp1) self.assertEquals(tmp1, b'<?xml version="1.0" encoding="ut') self.assertIsNotNone(tmp2) self.assertEquals(tmp2, b'f-8" standalone="yes"?>\n<KeePass') self.assertNotEquals(tmp1, tmp2) self.assertEquals(kdb.tell(), 64) kdb.seek(0) tmp3 = kdb.read(32) self.assertEquals(tmp1, tmp3) self.assertNotEquals(tmp2, tmp3) # read xml xml1 = kdb.obj_root.Root.Group.Entry.String[1].Value self.assertEquals(xml1, "Password") xml2 = kdb.obj_root.Root.Group.Entry.String[1].Value.get('ProtectedValue') kdb.protect() # re-encrypt protected values again xml3 = kdb.obj_root.Root.Group.Entry.String[1].Value self.assertEquals(xml2, xml3) kdb.unprotect() # and make passwords clear again xml4 = kdb.obj_root.Root.Group.Entry.String[1].Value self.assertEquals(xml1, xml4) self.assertIsNotNone(kdb.pretty_print())
def open_database(self): try: with libkeepass.open(self.database_path, password=self.passphrase) as kdb: return kdb except IOError: raise WrongPassword("Incorrect password")
filename = input( "Please enter file name with Address for example : D:\Keepass\Yavarich.kdbx \n" ) if filename == "": print("File not found") sys.exit() fdA = input( "Please enter password list name with Address for example : D:\Keepass\dic.txt \n" ) if fdA == "": print("File not found") sys.exit() else: fd = open(fdA, 'r') print("Please wait... \n") lines = [] for line in fd: lines.append(line.replace("\n", "")) for x in lines: try: with libkeepass.open(filename, password=x) as kdb: str = kdb.pretty_print() print("Password is : ", x) break except BaseException as e: logging.info(x) else: print("Password is not found!, please try with other password list")
def kdb_inventory(): filename = os.environ["KDB_PATH"] credentials = {'password': os.environ["KDB_PASS"]} vgroups = ['product', 'stage', 'tier', 'type', 'ansible_ssh_host'] hosts = {} inventory = {} inventory_vars = {} with libkeepass.open(filename, **credentials) as kdb: xmldata = ET.fromstring(kdb.pretty_print()) for history in xmldata.xpath(".//History"): history.getparent().remove(history) for group in xmldata.findall(".//Group"): group_name_raw = group.find("./Name").text group_name = re.sub('\s|=', '_', group_name_raw, flags=re.IGNORECASE).lower() if re.match('^recycle.bin.*', group_name): continue group_uuid = group.find("./UUID").text group_uuid = base64.b16encode( base64.b64decode(group_uuid)).decode('utf-8') group_name_uuid = group_name + "_" + group_uuid inventory[group_name_uuid] = {} inventory[group_name_uuid]["hosts"] = [] subgroups = [] for subgroup in group.findall("./Group"): subgroup_name_raw = subgroup.find("./Name").text subgroup_name = re.sub('\s|=', '_', subgroup_name_raw, flags=re.IGNORECASE).lower() subgroup_uuid = subgroup.find("./UUID").text subgroup_uuid = base64.b16encode( base64.b64decode(subgroup_uuid)).decode('utf-8') subgroup_name_uuid = subgroup_name + "_" + subgroup_uuid subgroups.append(subgroup_name_uuid) if subgroups: inventory[group_name_uuid]["children"] = subgroups for entry in group.findall("./Entry"): hostvars = {} hostgroups = [] hostname = None for string in entry.findall("./String"): key = string.findtext("./Key").lower() value = string.findtext("./Value") if key and value: if key == 'title': hostname = re.sub('\s|=', '_', value, flags=re.IGNORECASE) elif key == 'url': if re.match('^ssh://', value, flags=re.IGNORECASE): hostvars['ansible_host'] = re.sub( '^ssh://', '', value, flags=re.IGNORECASE) else: hostname = None # ignore entry with non-ssh url elif key == 'username': hostvars['ansible_user'] = value elif key == 'password': if re.match( '^{REF:', value, flags=re.IGNORECASE ): # KeePass can put a reference to another cell - ignore that hostname = None else: hostvars['ansible_ssh_pass'] = value hostvars['ansible_become_pass'] = value elif re.match('^---\n', value): hostvars[key] = yaml.safe_load(value) elif value in ['True', 'true']: hostvars[key] = True elif value in ['False', 'false']: hostvars[key] = False else: hostvars[key] = value if hostname == "group_vars": inventory[group_name_uuid]["vars"] = hostvars elif hostname: hosts[hostname] = hostvars hostgroups.append(group_name_uuid) groups = { group.find('Name').text.lower() for group in entry.xpath('ancestor::Group') } for group in groups: hostgroups.append(group) for vgroup in vgroups: if vgroup in hostvars: hostgroups.append(hostvars[vgroup]) tags_raw = entry.findtext("./Tags") tags = re.sub('\s|=', '_', tags_raw, flags=re.IGNORECASE).split(';') for tag in tags: if tag: hostgroups.append(tag) for hostgroup in hostgroups: try: inventory[hostgroup]["hosts"].append(hostname) except KeyError: try: inventory[hostgroup]["hosts"] = [hostname] except KeyError: inventory[hostgroup] = {} inventory[hostgroup]["hosts"] = [hostname] inventory_vars["hostvars"] = hosts inventory["_meta"] = inventory_vars print(json.dumps(inventory, indent=2, sort_keys=True))
#!/usr/bin/env python3 import libkeepass import getpass import sys try: filename = sys.argv[1] entry_title = sys.argv[2] except IndexError: print('query.py <kdbx file name> <entry title>') sys.exit(1) try: with libkeepass.open(filename, password=getpass.getpass()) as kdb: found = {} for entry in kdb.obj_root.findall('.//Group/Entry'): uuid = entry.find('./UUID').text kv = {string.find('./Key').text : string.find('./Value').text for string in entry.findall('./String')} if kv['Title'] == entry_title: found[uuid] = kv['Password'] removed_uuids = {uuid.text for uuid in kdb.obj_root.findall('.//DeletedObject/UUID')} for password in { found[k] for k in found.keys() if k not in removed_uuids }: print(password) except Exception as e: print('Could not query KeePass Database %s:\n%s' % (filename, str(e)), file=sys.stderr) sys.exit(2)
def kdb_inventory(): filename = os.environ["KDB_PATH"] credentials = { 'password' : os.environ["KDB_PASS"] } vgroups = ['product', 'stage', 'tier', 'type'] hosts = {} inventory = {} inventory_vars = {} with libkeepass.open(filename, **credentials) as kdb: xmldata = ET.fromstring(kdb.pretty_print()) for history in xmldata.xpath(".//History"): history.getparent().remove(history) for group in xmldata.findall(".//Group"): group_name = group.find("./Name").text.lower() group_uuid = group.find("./UUID").text group_uuid = base64.b16encode(base64.b64decode(group_uuid)) group_name_uuid = group_name + "_" + group_uuid inventory[group_name_uuid] = {} subgroups = [] for subgroup in group.findall("./Group"): subgroup_name = subgroup.find("./Name").text.lower() subgroup_uuid = subgroup.find("./UUID").text subgroup_uuid = base64.b16encode(base64.b64decode(subgroup_uuid)) subgroup_name_uuid = subgroup_name + "_" + subgroup_uuid subgroups.append(subgroup_name_uuid) if subgroups: inventory[group_name_uuid]["children"] = subgroups for entry in group.findall("./Entry"): hostvars = {} hostgroups = [] hostname = None for string in entry.findall("./String"): key = string.findtext("./Key").lower() value = string.findtext("./Value") if key == 'title' and ' ' not in value: hostname = value.lower() if value and key != "title": hostvars[key] = value if hostname and hostname != "group_vars" and ' ' not in hostname: hostgroups.append(group_name_uuid) groups = { group.find('Name').text.lower() for group in entry.xpath('ancestor::Group') } for group in groups: hostgroups.append(group) for vgroup in vgroups: if vgroup in hostvars: vgroup = hostvars[vgroup] hostgroups.append(vgroup) tags = entry.findtext("./Tags").split(';') for tag in tags: if tag: tag = tag.translate(maketrans('=','_')) hostgroups.append(tag) for hostgroup in hostgroups: try: inventory[hostgroup]["hosts"].append(hostname) except KeyError: try: inventory[hostgroup]["hosts"] = [hostname] except KeyError: inventory[hostgroup] = {} inventory[hostgroup]["hosts"] = [hostname] if hostname and hostname != "group_vars": hosts[hostname] = hostvars if hostname == "group_vars": inventory[group_name_uuid]["vars"] = hostvars inventory_vars["hostvars"] = hosts inventory["_meta"] = inventory_vars print json.dumps(inventory, indent=2, sort_keys=True)
#!/usr/bin/env python3 import libkeepass import getpass import sys try: filename = sys.argv[1] password = sys.argv[2] if len(sys.argv) == 3 else getpass.getpass() except IndexError: print('prettyprint.py <kdbx file name> [password]') sys.exit(1) try: with libkeepass.open(filename, password=password) as kdb: print(kdb.pretty_print().decode('unicode_escape')) except Exception as e: print('Could not prettyprint KeePass Database %s:\n%s' % (filename, str(e)), file=sys.stderr) sys.exit(2)