Commits

Erik Grinaker committed a17541c

added GPass 0.5.x import

  • Participants
  • Parent commits 9295ddb

Comments (0)

Files changed (4)

 
 	* improved the applet name and description
 
+	* added GPass 0.5.x import
+
 2005-08-22  Erik Grinaker <erikg@codepoet.no>
 
 	* added Password Safe 1.x import/export
 New features:
 - added Password Safe 2.x import/export
 - added Password Safe 1.x import/export
+- added GPass 0.5.x import
 - added MyPasswordSafe import/export
 - added Password Gorilla import/export
 
 - fix crash when searching with non-Unicode locale
 - fix crashes in applet and with drag/drop on 64-bit systems
 - encode data as Unicode when loading from files
+- more informative error messages for gnomemisc module
 - fix incorrect magic string in MIME-type entry
 - set correct app version number in datafile header
 - default lock timeout for applet set to 10 minutes
-- don't use unnecessary defsfiles when building gnomemisc module
-- more informative error messages for gnomemisc module
 
 Code changes:
 - check for necessary python modules at configure-time
+- don't use unnecessary defsfiles when building gnomemisc module
 - improved the applet name and description
 
 

src/lib/datahandler/__init__.py

 from base import HandlerError, DataError, FormatError, PasswordError, VersionError
 
 from fpm import FPM
-from gpass import GPass
+from gpass import GPass04, GPass05
 from netrc import NetRC
 from pwsafe import PasswordSafe1, PasswordSafe2, MyPasswordSafe, PasswordGorilla
 from rvl import RevelationXML, Revelation
 
 HANDLERS = [
 	FPM,
-	GPass,
+	GPass04,
+	GPass05,
 	MyPasswordSafe,
 	NetRC,
 	PasswordGorilla,

src/lib/datahandler/gpass.py

 import base
 from revelation import data, entry
 
+import locale, re
 from Crypto.Cipher import Blowfish
 from Crypto.Hash import SHA
 
 
 
 
-class GPass(base.DataHandler):
-	"Data handler for GNOME Password Manager data"
+class GPass04(base.DataHandler):
+	"Data handler for GPass 0.4.x data"
 
-	name		= "GNOME Password Manager (gpass)"
+	name		= "GPass 0.4.x (or older)"
 	importer	= True
 	exporter	= True
 	encryption	= True
 
 		return entrystore
 
+
+
+class GPass05(base.DataHandler):
+	"Data handler for GPass 0.5.x data"
+
+	name		= "GPass 0.5.x (or newer)"
+	importer	= True
+	exporter	= False
+	encryption	= True
+
+
+	def __init__(self):
+		base.DataHandler.__init__(self)
+
+
+	def __getint(self, input):
+		"Fetches an integer from the input"
+
+		if len(input) < 4:
+			raise base.FormatError
+
+		return ord(input[0]) << 0 | ord(input[1]) << 8 | ord(input[2]) << 16 | ord(input[3]) << 24
+
+
+	def __getstr(self, input):
+		"Fetches a string from the input"
+
+		length = self.__getint(input[:4])
+
+		if len(input) < (4 + length):
+			raise base.FormatError
+
+		string = input[4:4 + length]
+
+		if len(string) != length:
+			raise base.FormatError
+
+		return string
+
+
+	def __normstr(self, string):
+		"Normalizes a string"
+
+		string = re.sub("[\r\n]+", " ", string)
+		string = string.decode(locale.getpreferredencoding(), "replace")
+		string = string.encode("utf-8")
+
+		return string
+
+
+	def __unpackint(self, input):
+		"Fetches a packed number from the input"
+
+		value	= 0
+		b	= 1
+
+		for i in range(min(len(input), 6)):
+			c = ord(input[i])
+
+			if c & 0x80:
+				value	+= b * (c & 0x7f)
+				b	*= 0x80;
+
+			else:
+				value	+= b * c
+
+				return i + 1, value
+
+		# if we didn't return in the for-loop, the input is invalid
+		else:
+			raise base.FormatError
+
+
+	def __unpackstr(self, input):
+		"Unpacks a string from the input"
+
+		cut, length = self.__unpackint(input[:6])
+
+		if len(input) < cut + length:
+			raise base.FormatError
+
+		return cut + length, input[cut:cut + length]
+
+
+	def import_data(self, input, password):
+		"Imports data from a data stream to an entrystore"
+
+		# decrypt data
+		plain = Blowfish.new(SHA.new(password).digest(), Blowfish.MODE_CBC, self.IV).decrypt(input)
+
+		if plain[0:23] != "GPassFile version 1.1.0":
+			raise base.PasswordError
+
+		plain = plain[23:]
+
+		# remove padding
+		padchar = plain[-1]
+
+		if plain[-ord(padchar):] != padchar * ord(padchar):
+			raise base.FormatError
+
+		plain = plain[:-ord(padchar)]
+
+		# deserialize data
+		entrystore = data.EntryStore()
+		foldermap = {}
+
+		while len(plain) > 0:
+
+			# parse data
+			id		= self.__getint(plain[:4])
+			plain		= plain[4:]
+
+			parentid	= self.__getint(plain[:4])
+			plain		= plain[4:]
+
+			entrytype	= self.__getstr(plain)
+			plain		= plain[4 + len(entrytype):]
+
+			attrdata	= self.__getstr(plain)
+			plain		= plain[4 + len(attrdata):]
+
+
+			l, name		= self.__unpackstr(attrdata)
+			attrdata	= attrdata[l:]
+
+			l, desc		= self.__unpackstr(attrdata)
+			attrdata	= attrdata[l:]
+
+			l, ctime	= self.__unpackint(attrdata)
+			attrdata	= attrdata[l:]
+
+			l, mtime	= self.__unpackint(attrdata)
+			attrdata	= attrdata[l:]
+
+			l, expire	= self.__unpackint(attrdata)
+			attrdata	= attrdata[l:]
+
+			l, etime	= self.__unpackint(attrdata)
+			attrdata	= attrdata[l:]
+
+			if entrytype == "general":
+				l, username	= self.__unpackstr(attrdata)
+				attrdata	= attrdata[l:]
+
+				l, password	= self.__unpackstr(attrdata)
+				attrdata	= attrdata[l:]
+
+				l, hostname	= self.__unpackstr(attrdata)
+				attrdata	= attrdata[l:]
+
+			else:
+				username = password = hostname = ""
+
+
+			# create entry
+			if entrytype == "general":
+				e = entry.GenericEntry()
+
+				e.name			= self.__normstr(name)
+				e.description		= self.__normstr(desc)
+				e.updated		= mtime
+
+				e[entry.HostnameField]	= self.__normstr(hostname)
+				e[entry.UsernameField]	= self.__normstr(username)
+				e[entry.PasswordField]	= self.__normstr(password)
+
+			elif entrytype == "folder":
+				e = entry.FolderEntry()
+
+				e.name			= self.__normstr(name)
+				e.description		= self.__normstr(desc)
+				e.updated		= mtime
+
+			else:
+				continue
+
+
+			# add entry to entrystore
+			if foldermap.has_key(parentid):
+				parent = foldermap[parentid]
+
+			else:
+				parent = None
+
+			iter = entrystore.add_entry(e, parent)
+
+			if type(e) == entry.FolderEntry:
+				foldermap[id] = iter
+
+
+		return entrystore
+