"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/lib/datahandler/fpm.py" between
revelation-0.5.3.tar.xz and revelation-0.5.4.tar.xz

About: Revelation is a password manager for the GNOME 3 desktop.

fpm.py  (revelation-0.5.3.tar.xz):fpm.py  (revelation-0.5.4.tar.xz)
skipping to change at line 34 skipping to change at line 34
# #
from . import base from . import base
from revelation import data, entry, util from revelation import data, entry, util
import math, random, string, xml.dom.minidom import math, random, string, xml.dom.minidom
from xml.parsers.expat import ExpatError from xml.parsers.expat import ExpatError
from Cryptodome.Cipher import Blowfish from Cryptodome.Cipher import Blowfish
from Cryptodome.Hash import MD5 from Cryptodome.Hash import MD5
import Cryptodome.Random as Random
class FPM(base.DataHandler): class FPM(base.DataHandler):
"Data handler for Figaro's Password Manager data" "Data handler for Figaro's Password Manager data"
name = "Figaro's Password Manager" name = "Figaro's Password Manager"
importer = True importer = True
exporter = True exporter = True
encryption = True encryption = True
def __init__(self): def __init__(self):
base.DataHandler.__init__(self) base.DataHandler.__init__(self)
def __decrypt(self, cipher, data): def __decrypt(self, cipher, data):
"Decrypts data" "Decrypts data"
# decode ascii armoring if isinstance(data, str):
decoded = "" data = data.encode()
for i in range(len(data) / 2): # decode ascii armoring
high = ord(data[2 * i]) - ord("a") decoded = b""
low = ord(data[2 * i + 1]) - ord("a")
decoded += chr(high * 16 + low)
for i in range(len(data) // 2):
high = data[2 * i] - ord("a")
low = data[2 * i + 1] - ord("a")
decoded += bytes((high * 16 + low,))
data = decoded data = decoded
# decrypt data # decrypt data
data = cipher.decrypt(data) data = cipher.decrypt(data)
# unrotate field # unrotate field
blocks = int(math.ceil(len(data) / float(8))) blocks = int(math.ceil(len(data) / float(8)))
plain = "" plain = b""
for offset in range(8): for offset in range(8):
for block in range(blocks): for block in range(blocks):
plain += data[block * 8 + offset] plain += bytes((data[block * 8 + offset],))
return plain.split("\x00")[0] return plain.split(b"\x00")[0]
def __encrypt(self, cipher, data): def __encrypt(self, cipher, data):
"Encrypts data" "Encrypts data"
# get data sizes # get data sizes
blocks = (len(data) / 7) + 1 blocks = (len(data) // 7) + 1
size = 8 * blocks size = 8 * blocks
# add noise # add noise
data += "\x00" + util.random_string(size - len(data) - 1) rand = Random.new()
data += b'\x00' + rand.read(size - len(data) - 1)
# rotate data # rotate data
rotated = "" rotated = b""
for block in range(blocks): for block in range(blocks):
for offset in range(8): for offset in range(8):
rotated += data[offset * blocks + block] rotated += bytes((data[offset * blocks + block],))
data = rotated data = rotated
# encrypt data # encrypt data
data = cipher.encrypt(data) data = cipher.encrypt(data)
# ascii-armor data # ascii-armor data
res = "" res = b""
for i in range(len(data)): for i in range(len(data)):
high = ord(data[i]) / 16 high = data[i] // 16
low = ord(data[i]) - high * 16 low = data[i] - high * 16
res += chr(ord("a") + high) + chr(ord("a") + low) res += bytes((ord("a") + high, ord("a") + low))
data = res data = res
return data return data
def check(self, input): def check(self, input):
"Checks if the data is valid" "Checks if the data is valid"
try: try:
if input is None: if input is None:
skipping to change at line 142 skipping to change at line 146
self.check(input) self.check(input)
return True return True
except ( base.FormatError, base.VersionError, base.DataError ): except ( base.FormatError, base.VersionError, base.DataError ):
return False return False
def export_data(self, entrystore, password): def export_data(self, entrystore, password):
"Exports data from an entrystore" "Exports data from an entrystore"
# set up encryption engine # set up encryption engine
salt = "".join( [ random.choice(string.ascii_lowercase) for i in range(8 salt = bytes( [ random.choice(string.ascii_lowercase.encode()) for i in
) ] ) range(8) ] )
password = MD5.new(salt + password).digest() password = MD5.new(salt + password.encode()).digest()
cipher = Blowfish.new(password) cipher = Blowfish.new(password, Blowfish.MODE_ECB)
# generate data # generate data
xml = "<?xml version=\"1.0\" ?>\n" xml = "<?xml version=\"1.0\" ?>\n"
xml += "<FPM full_version=\"00.58.00\" min_version=\"00.58.00\" display_ version=\"00.58.00\">\n" xml += "<FPM full_version=\"00.58.00\" min_version=\"00.58.00\" display_ version=\"00.58.00\">\n"
xml += " <KeyInfo salt=\"%s\" vstring=\"%s\" />\n" % ( salt, self.__e ncrypt(cipher, "FIGARO") ) xml += " <KeyInfo salt=\"%s\" vstring=\"%s\" />\n" % ( salt.decode(), self.__encrypt(cipher, b"FIGARO").decode() )
xml += " <LauncherList></LauncherList>\n" xml += " <LauncherList></LauncherList>\n"
xml += " <PasswordList>\n" xml += " <PasswordList>\n"
iter = entrystore.iter_children(None) iter = entrystore.iter_children(None)
while iter is not None: while iter is not None:
e = entrystore.get_entry(iter) e = entrystore.get_entry(iter)
if type(e) != entry.FolderEntry: if type(e) != entry.FolderEntry:
e = e.convert_generic() e = e.convert_generic()
xml += " <PasswordItem>\n" xml += " <PasswordItem>\n"
xml += " <title>%s</title>\n" % e.name xml += " <title>%s</title>\n" % self.__encrypt(cipher
xml += " <url>%s</url>\n" % e.get_field(entry.Hostnam , e.name.encode()).decode()
eField).value xml += " <url>%s</url>\n" % self.__encrypt(cipher, e.
xml += " <user>%s</user>\n" % e.get_field(entry.Usern get_field(entry.HostnameField).value.encode()).decode()
ameField).value xml += " <user>%s</user>\n" % self.__encrypt(cipher,
xml += " <password>%s</password>\n" % e.get_field(ent e.get_field(entry.UsernameField).value.encode()).decode()
ry.PasswordField).value xml += " <password>%s</password>\n" % self.__encrypt(
xml += " <notes>%s</notes>\n" % e.description cipher, e.get_field(entry.PasswordField).value.encode()).decode()
xml += " <notes>%s</notes>\n" % self.__encrypt(cipher
, e.description.encode()).decode()
path = entrystore.get_path(iter) path = entrystore.get_path(iter).to_string()
if len(path) > 1: if len(path) > 1:
xml += " <category>%s</category>\n" % entrystore. foldername = entrystore.get_entry(entrystore.get_iter(path[0
get_entry(entrystore.get_iter(path[0])).name ])).name
xml += " <category>%s</category>\n" % self.__encr
ypt(cipher, foldername.encode()).decode()
else: else:
xml += " <category></category>\n" xml += " <category></category>\n"
xml += " <launcher></launcher>\n" xml += " <launcher></launcher>\n"
xml += " </PasswordItem>\n" xml += " </PasswordItem>\n"
iter = entrystore.iter_traverse_next(iter) iter = entrystore.iter_traverse_next(iter)
xml += " </PasswordList>\n" xml += " </PasswordList>\n"
skipping to change at line 201 skipping to change at line 206
# check and load data # check and load data
self.check(input) self.check(input)
dom = xml.dom.minidom.parseString(input.strip()) dom = xml.dom.minidom.parseString(input.strip())
if dom.documentElement.nodeName != "FPM": if dom.documentElement.nodeName != "FPM":
raise base.FormatError raise base.FormatError
# set up decryption engine, and check if password is correct # set up decryption engine, and check if password is correct
keynode = dom.documentElement.getElementsByTagName("KeyInfo")[0] keynode = dom.documentElement.getElementsByTagName("KeyInfo")[0]
salt = keynode.attributes["salt"].nodeValue salt = keynode.attributes["salt"].nodeValue.encode()
vstring = keynode.attributes["vstring"].nodeValue vstring = keynode.attributes["vstring"].nodeValue.encode()
password = MD5.new(salt + password).digest() password = MD5.new(salt + password.encode()).digest()
cipher = Blowfish.new(password) cipher = Blowfish.new(password, Blowfish.MODE_ECB)
if self.__decrypt(cipher, vstring) != "FIGARO": if self.__decrypt(cipher, vstring) != b"FIGARO":
raise base.PasswordError raise base.PasswordError
except ExpatError: except ExpatError:
raise base.FormatError raise base.FormatError
except ( IndexError, KeyError ): except ( IndexError, KeyError ):
raise base.FormatError raise base.FormatError
# import entries into entrystore # import entries into entrystore
entrystore = data.EntryStore() entrystore = data.EntryStore()
folders = {} folders = {}
for node in dom.getElementsByTagName("PasswordItem"): for node in dom.getElementsByTagName("PasswordItem"):
parent = None parent = None
e = entry.GenericEntry() e = entry.GenericEntry()
for fieldnode in [ node for node in node.childNodes if node.nodeType == node.ELEMENT_NODE ]: for fieldnode in [ node for node in node.childNodes if node.nodeType == node.ELEMENT_NODE ]:
content = self.__decrypt(cipher, util.dom_text(fieldnode)) content = self.__decrypt(cipher, util.dom_text(fieldnode)).decod e()
if content == "": if content == "":
continue continue
elif fieldnode.nodeName == "title": elif fieldnode.nodeName == "title":
e.name = content e.name = content
elif fieldnode.nodeName == "user": elif fieldnode.nodeName == "user":
e.get_field(entry.UsernameField).value = content e.get_field(entry.UsernameField).value = content
 End of changes. 23 change blocks. 
39 lines changed or deleted 47 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)