forked from AlessandroZ/LaZagne
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Alessandro ZANNI
committed
Jul 2, 2016
1 parent
658a1a5
commit 6efadd8
Showing
3 changed files
with
95 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
#!/usr/bin/env python | ||
# -*- encoding: utf-8 -*- | ||
# Thanks to https://github.com/b4n/clawsmail-password-decrypter | ||
from Crypto.Cipher import DES | ||
from base64 import standard_b64decode as b64decode | ||
from ConfigParser import ConfigParser | ||
from config.moduleInfo import ModuleInfo | ||
from config.header import Header | ||
from config.write_output import print_debug, print_output | ||
import platform, os | ||
|
||
class ClawsMail(ModuleInfo): | ||
def __init__(self): | ||
options = {'command': '-c', 'action': 'store_true', 'dest': 'clawsmail', 'help': 'clawsmail'} | ||
ModuleInfo.__init__(self, 'clawsmail', 'mails', options) | ||
|
||
def run(self): | ||
# print the title | ||
Header().title_info('ClawsMail') | ||
|
||
path = self.get_path() | ||
if not path: | ||
print_debug('INFO', 'ClawsMail not installed.') | ||
|
||
mode = DES.MODE_CFB | ||
if 'FreeBSD' in platform.system(): | ||
mode = DES.MODE_ECB | ||
|
||
pwdFound = self.accountrc_decrypt(path, self.get_passcrypt_key(), mode) | ||
|
||
# print the results | ||
print_output('ClawsMail', pwdFound) | ||
|
||
def get_path(self): | ||
file = '~/.claws-mail/accountrc' | ||
file = os.path.expanduser(file) | ||
if os.path.exists(file): | ||
return file | ||
else: | ||
return None | ||
|
||
def get_passcrypt_key(self): | ||
PASSCRYPT_KEY = b'passkey0' | ||
return PASSCRYPT_KEY | ||
|
||
def pass_decrypt(self, p, key, mode=DES.MODE_CFB): | ||
""" Decrypts a password from ClawsMail. """ | ||
if p[0] == '!': # encrypted password | ||
buf = b64decode(p[1:]) | ||
|
||
""" | ||
If mode is ECB or CBC and the length of the data is wrong, do nothing | ||
as would the libc algorithms (as they fail early). Yes, this means the | ||
password wasn't actually encrypted but only base64-ed. | ||
""" | ||
if (mode in (DES.MODE_ECB, DES.MODE_CBC)) and ((len(buf) % 8) != 0 or | ||
len(buf) > 8192): | ||
return buf | ||
|
||
c = DES.new(key, mode=mode, IV=b'\0'*8) | ||
return c.decrypt(buf) | ||
else: # raw password | ||
return p | ||
|
||
|
||
def accountrc_decrypt(self, filename, key, mode=DES.MODE_CFB): | ||
""" Reads passwords from ClawsMail's accountrc file """ | ||
p = ConfigParser() | ||
p.read(filename) | ||
|
||
pwdFound = [] | ||
for s in p.sections(): | ||
values = {} | ||
try: | ||
try: | ||
address = p.get(s, 'address') | ||
account = p.get(s, 'account_name') | ||
except: | ||
address = '<unknown>' | ||
account = '<unknown>' | ||
|
||
password = self.pass_decrypt(p.get(s, 'password'), key, mode=mode) | ||
# print('password for %s, %s is "%s"' % (account, address, password)) | ||
values = {'Account' : account, 'Address': address, 'Password': password} | ||
except Exception as e: | ||
print_debug('ERROR', 'Error resolving password for account "%s": %s' % (s, e)) | ||
|
||
# write credentials into a text file | ||
if len(values) != 0: | ||
pwdFound.append(values) | ||
|
||
return pwdFound |