0,0 → 1,142 |
#!/usr/bin/env python |
# -*- coding: UTF-8 -*- |
|
import getopt |
import libxml2 |
import os |
import sys |
import zlib |
from Crypto.Cipher import AES |
|
""" |
Relevation Password Printer |
a command line interface to Revelation Password Manager |
|
Code based on Revelation's former BTS (no longer online, not archived?): |
(1) code: |
http://oss.wired-networks.net/bugzilla/attachment.cgi?id=13&action=view |
(2) bug report: |
http://oss.wired-networks.net/bugzilla/show_bug.cgi?id=111 |
-> http://web.archive.org/http://oss.wired-networks.net/bugzilla/show_bug.cgi?id=111 |
""" |
|
__author__ = 'Toni Corvera' |
__date__ = '$Date$' |
__revision__ = '$Rev$' |
__version_info__ = ( 0, 1, 0 ) |
__version__ = '.'.join(map(str, __version_info__)) |
|
def usage(channel): |
def p(s): |
channel.write(s) |
p(' -f <FILE>, --file=<FILE> Revelation password file\n') |
p(' -p <PASS>, --password=<PASS> Master password\n') |
p(' -s <STRING>, --search=<STRING> Search for string\n') |
p(' -i, --case-insensitive Case insensitive search [default]\n') |
p(' -c, --case-sensitive Case sensitive search\n') |
p(' -0, --stdin Read password from standard input\n') |
# p(' -a, --ask Ask password interactively\n') |
p('\n') |
|
def main(): |
datafile = None |
password = None |
search = None |
caseInsensitive = True |
|
sys.stderr.write('Relevation v%s, (c) 2011 Toni Corvera\n\n' % __version__) |
try: |
ops, args = getopt.getopt(sys.argv[1:], 'f:p:s:0ci', |
[ 'file=', 'password=', 'search=', 'stdin', |
'case-sensitive', 'case-insensitive' ]) |
except getopt.GetoptError, err: |
print str(err) |
usage(sys.stderr) |
sys.exit(os.EX_USAGE) |
for opt, arg in ops: |
if opt in ( '-f', '--file' ): |
datafile = arg |
elif opt in ( '-p', '--password' ): |
password = arg |
elif opt in ( '-0', '--stdin' ): |
sys.stderr.write('Getting password from stdin\n') |
p = sys.stdin.readline() |
p = p[:-1] |
elif opt in ( '-s', '--search' ): |
search = arg |
elif opt in ( '-i', '--case-insensitive' ): |
caseInsensitive = True |
elif opt in ( '-c', '--case-sensitive' ): |
caseInsensitive = False |
else: |
assert False, "internal error parsing options" |
if not datafile or not password: |
usage(sys.stderr) |
sys.exit(os.EX_USAGE) |
# read data from file |
f = open(datafile, "rb") |
data = f.read() |
f.close() |
# pad the password |
password += (chr(0) * (32 - len(password))) |
# get the IV |
c = AES.new(password) |
iv = c.decrypt(data[12:28]) |
# decrypt the data |
c = AES.new(password, AES.MODE_CBC, iv) |
rawdata = c.decrypt(data[28:]) |
# fetch padlen, and decompress data |
padlen = ord(rawdata[-1]) |
xmldata = zlib.decompress(rawdata[:-padlen], 15, 32768) |
if not search: |
print xmldata |
sys.exit(os.EX_OK) |
|
doc = libxml2.parseDoc(xmldata) |
ctxt = doc.xpathNewContext() |
commonXPath = '//revelationdata//entry[@type!="folder"]//text()' |
caseSensitiveXPath = '[contains(., "%s")]/../..' % search |
caseInsensitiveXPath = '[contains(translate(., "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz"), "%s")]/../..' % search |
if caseInsensitive: |
xpath = commonXPath + caseInsensitiveXPath |
else: |
xpath = commonXPath + caseSensitiveXPath |
res = ctxt.xpathEval(xpath) |
if not len(res): |
sys.stderr.write('No matches\n') |
sys.exit(2) |
print '%d matches:' % len(res) |
tagnames ={ 'generic-url': 'Url:', |
'generic-username': 'Username:', |
'generic-password': 'Password:', |
} |
for x in res: |
print '- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - ' |
print '' |
for attr in x.properties: # Is it accessible directly? |
if attr.name == 'type': |
print 'Type:',attr.children |
for chld in x.children: |
n = chld.name |
val = chld.content |
if n == 'name': |
print 'Name:',val |
elif n == 'description': |
print 'Description:',val |
elif n == 'field': |
for attr in chld.properties: |
if attr.name == 'id': |
idv = attr.content |
if idv in tagnames: |
idv = tagnames[idv] |
print idv,chld.content |
print '' |
# for chld in x.children |
doc.freeDoc() |
ctxt.xpathFreeContext() |
|
|
if __name__ == '__main__': |
main() |
|
# vim:set ts=4 et ai fileencoding=utf-8: # |
Property changes: |
Added: svn:executable |