47,14 → 47,17 |
import sys |
import zlib |
|
# Import PyCrypto if present, fall back to PyCryptoPlus otherwise |
USE_PYCRYPTO = True |
|
try: |
from Crypto.Cipher import AES |
except ImportError: |
USE_PYCRYPTO = False |
try: |
from CryptoPlus.Cipher import AES |
from crypto.cipher import rijndael, cbc |
from crypto.cipher.base import noPadding |
except ImportError: |
sys.stderr.write('Error: Either PyCrypto or PyCryptoPlus must be installed\n') |
sys.stderr.write('Either PyCrypto or cryptopy are required\n') |
raise |
|
__author__ = 'Toni Corvera' |
64,6 → 67,19 |
__version__ = '.'.join(map(str, __version_info__)) |
RELEASE=True |
|
# These are pseudo-standardized exit codes, in Linux (*NIX?) they are defined |
#+in the header </usr/include/sysexits.h> and available as properties of 'os' |
#+In windows they aren't defined at all |
|
if 'EX_OK' not in dir(os): |
# If not defined set them manually |
codes = { 'EX_OK': 0, 'EX_USAGE': 64, 'EX_DATAERR': 65, |
'EX_NOINPUT': 66, 'EX_SOFTWARE': 70, 'EX_IOERR': 74, |
} |
for (k,v) in codes.items(): |
setattr(os, k, v) |
del codes, k, v |
|
def usage(channel): |
' Print help message ' |
def p(s): |
205,7 → 221,7 |
if os.path.isfile(cfg): |
if os.access(cfg, os.R_OK): |
wr = world_readable(cfg) |
if wr: |
if wr and sys.platform != 'win32': |
sys.stderr.write('Configuration (~/.relevation.conf) is world-readable!!!\n') |
parser = ConfigParser.ConfigParser() |
parser.read(cfg) |
213,7 → 229,7 |
if 'file' in ops: |
fl = os.path.expanduser(parser.get('relevation', 'file')) |
if 'password' in ops: |
if wr and sys.platform != 'win32': # TODO: how to check in windows? |
if wr: # TODO: how to check in windows? |
sys.stderr.write('Your password can be read by anyone!!!\n') |
pw = parser.get('relevation', 'password') |
else: # exists but not readable |
220,6 → 236,29 |
sys.stderr.write('Configuration file (~/.relevation.conf) is not readable!\n') |
return ( fl, pw ) |
|
def decrypt_gz(key, cipher_text): |
''' |
decrypt(str, str) -> cleartext (gzipped xml) |
Decrypt cipher_text using key. |
This function will use the underlying, available, cipher module. |
''' |
if USE_PYCRYPTO: |
# Extract IV |
c = AES.new(key) |
iv = c.decrypt(cipher_text[12:28]) |
# Decrypt data, CBC mode |
c = AES.new(key, AES.MODE_CBC, iv) |
ct = c.decrypt(cipher_text[28:]) |
else: |
# Extract IV |
c = rijndael.Rijndael(key, keySize=len(key), padding=noPadding()) |
iv = c.decrypt(cipher_text[12:28]) |
# Decrypt data, CBC mode |
bc = rijndael.Rijndael(key, keySize=len(key), padding=noPadding()) |
c = cbc.CBC(bc, padding=noPadding()) |
ct = c.decrypt(cipher_text[28:], iv=iv) |
return ct |
|
def main(): |
datafile = None |
password = None |
310,12 → 349,8 |
f.close() |
# Pad password |
password += (chr(0) * (32 - len(password))) |
# Data IV |
c = AES.new(password) |
iv = c.decrypt(data[12:28]) |
# Decrypt. Decrypted data is compressed |
c = AES.new(password, AES.MODE_CBC, iv) |
cleardata_gz = c.decrypt(data[28:]) |
cleardata_gz = decrypt_gz(password, data) |
# Length of data padding |
padlen = ord(cleardata_gz[-1]) |
# Decompress actual data (15 is wbits [ref3] DON'T CHANGE, 2**15 is the (initial) buf size) |