예제 #1
0
파일: crypt.py 프로젝트: niklasad1/crypt
def decrypt(file):
  gpg_home = find_gpg_keys()
  if ( gpg_home == ''):
    print 'GPG keys not found'
    sys.exit(1)
  gpg = GPG(gnupghome=gpg_home, use_agent=True)
  public_keys = gpg.list_keys()
  key_id = public_keys[0]['keyid']
  if ( os.path.isfile(file)):
      if ( file.endswith('.gpg')):
        stream = open(file, 'rb')
        status = gpg.decrypt_file(stream, output=file[:-4])
        if ( status.ok):
          os.remove(file)
          print file[:-4] + ' succesfully decrypted'
      else:
        print file + ' not encrypted'
  elif ( os.path.isdir(file) ):
    for root, dirs, files in os.walk(file, topdown=True):
      for name in files:
        current_file = (os.path.join(root, name))
        if ( current_file.endswith('.gpg')):
          stream = open(current_file, "rb")
          status = gpg.decrypt_file(stream, output=current_file[:-4])
          if ( status.ok ):
            os.remove(current_file)
            print current_file[:-4] + ' successfully decrypted'
        else:
          print current_file + ' not encrypted'
  else:
    print 'ERROR: file or directory not found'
예제 #2
0
class GpgExtractor(StoqExtractorPlugin):

    def __init__(self):
        super().__init__()

    def activate(self, stoq):
        self.stoq = stoq

        super().activate()

        if not os.path.exists(self.gpg_home):
            self.critical("GPG Home is not defined! Skipping...")
            return

        self.gpg = GPG(gnupghome=self.gpg_home,
                       gpgbinary=self.gpg_bin,
                       keyring=self.public_keyring,
                       secret_keyring=self.secret_keyring)

    def extract(self, payload, **kwargs):
        """
        Decrypt content from provided payload

        :param bytes payload: Payload to be decrypted
        :param **kwargs kwargs: Additional attributes (unused)

        :returns: Decrypted payload
        :rtype: list of tuples

        """

        passphrase = None
        always_trust = False

        if self.passphrase:
            passphrase = self.passphrase

        if self.always_trust:
            always_trust = self.always_trust

        # Ensure the payload is a ByesIO object
        payload_object = BytesIO(payload)

        # Decrypt the payload and return a file object
        decrypted_payload = self.gpg.decrypt_file(payload_object,
                                                  passphrase=passphrase,
                                                  always_trust=always_trust)

        content = decrypted_payload.data

        if content:
            meta = {}
            meta['size'] = len(content)

            # Return the decrypted payload
            return [(meta, content)]

        else:
            self.log.error("Unable to decrypt payload: {}".format(kwargs))
            return
예제 #3
0
class GpgExtractor(StoqExtractorPlugin):

    def __init__(self):
        super().__init__()

    def activate(self, stoq):
        self.stoq = stoq

        super().activate()

        if not os.path.exists(self.gpg_home):
            self.stoq.exception("GPG Home is not defined! Skipping...")

        self.gpg = GPG(gnupghome=self.gpg_home,
                       gpgbinary=self.gpg_bin,
                       keyring=self.public_keyring,
                       secret_keyring=self.secret_keyring)


    def extract(self, payload, **kwargs):
        """
        Decrypt content from provided payload

        :param bytes payload: Payload to be decrypted
        :param **kwargs kwargs: Additional attributes (unused)

        :returns: Decrypted payload
        :rtype: list of tuples

        """

        passphrase = None
        always_trust = False

        if self.passphrase:
            passphrase = self.passphrase

        if self.always_trust:
            always_trust = self.always_trust

        # Ensure the payload is a ByesIO object
        payload_object = BytesIO(payload)

        # Decrypt the payload and return a file object
        decrypted_payload = self.gpg.decrypt_file(payload_object,
                                                  passphrase=passphrase,
                                                  always_trust=always_trust)

        content = decrypted_payload.data

        if content:
            meta = {}
            meta['size'] = len(content)

            # Return the decrypted payload
            return [(meta, content)]

        else:
            self.stoq.log.error("Unable to decrypt payload: {}".format(kwargs))
            return None
예제 #4
0
class reqPGP(object):
    def __init__(self, path=None):
        self.gpg = GPG(gpgbinary=('../gpg.exe' if osName == 'nt' else 'gpg'))
        if not path:
            try:
                self.path = environ["HOME"] + '/'
            except KeyError:
                self.path = environ["HOMEPATH"] + '\\'
        else:
            if path[-1] != '\\' and osName == 'nt':
                path += '\\'
            elif path[-1] != '/' and osName == 'posix':
                path += '/'
            self.path = path
            

    def genKey(self, account, passphrase):
        input_data = self.gpg.gen_key_input(
            name_email=account,
            passphrase=passphrase)
        self.gpg.gen_key(input_data)

    def encryptFile(self, account, data):
        encryptedData = str(self.gpg.encrypt(data, account))
        with open(self.path + '.' + account + '.req', 'w') as f:
            f.write(encryptedData)

    def decryptFile(self, account, passphrase):
        with open(self.path + '.' + account + '.req', 'rb') as f:
            decryptedData = str(self.gpg.decrypt_file(f, passphrase=passphrase))
        return decryptedData
    
    def deleteKey(self, keyId):
        self.gpg.delete_keys(keyId, True)
        self.gpg.delete_keys(keyId)
예제 #5
0
class reqPGP(object):
    def __init__(self, path=None):
        self.gpg = GPG(gpgbinary=('../gpg.exe' if osName == 'nt' else 'gpg'))
        if not path:
            try:
                self.path = environ["HOME"] + '/'
            except KeyError:
                self.path = environ["HOMEPATH"] + '\\'
        else:
            if path[-1] != '\\' and osName == 'nt':
                path += '\\'
            elif path[-1] != '/' and osName == 'posix':
                path += '/'
            self.path = path

    def genKey(self, account, passphrase):
        input_data = self.gpg.gen_key_input(name_email=account,
                                            passphrase=passphrase)
        self.gpg.gen_key(input_data)

    def encryptFile(self, account, data):
        encryptedData = str(self.gpg.encrypt(data, account))
        with open(self.path + '.' + account + '.req', 'w') as f:
            f.write(encryptedData)

    def decryptFile(self, account, passphrase):
        with open(self.path + '.' + account + '.req', 'rb') as f:
            decryptedData = str(self.gpg.decrypt_file(f,
                                                      passphrase=passphrase))
        return decryptedData

    def deleteKey(self, keyId):
        self.gpg.delete_keys(keyId, True)
        self.gpg.delete_keys(keyId)
예제 #6
0
def decrypt_file(gpg: gnupg.GPG, targer_folder: str):
    configuration_kwargs = utils.get_configuratation(
        path=os.path.join(targer_folder, 'configuration'))
    gpg = _get_decryption(gpg=gpg, configuration_kwargs=configuration_kwargs)

    encrypted_filepaths = utils.get_files(
        path=os.path.join(targer_folder, 'encrypted_files'))

    decrypted_path = os.path.join(targer_folder, 'decrypted_files')
    password = configuration_kwargs.get('array')['passphrase'] \
        if settings.ENVIRONMENT == 'prod' else 'wow'

    for encryped_file in encrypted_filepaths:
        base_name = __set_file_name(path=encryped_file)

        logger.info(f'Decrypting file {base_name}')

        output_file = os.path.join(decrypted_path, base_name)

        with open(encryped_file, 'rb') as connection:
            status = gpg.decrypt_file(file=connection,
                                      passphrase=password,
                                      output=output_file)
            logger.info(f'Decrypting done')

        if not status.ok:
            logger.info(f'{status.stderr}')
        else:
            logger.info(f'Status [{status.status}]')
예제 #7
0
 def __call__(self):
     fileName = as_human_readable(self.get_chosen_files()[0])
     gpg = GPG()
     myPass, ok = show_prompt('Passphrase')
     # https://stackoverflow.com/questions/4444923/get-filename-without-extension-in-python
     fileNameOut, ok = show_prompt('Target',
                                   default=os.path.splitext(fileName)[0])
     with open(fileName, 'rb') as f:
         status = gpg.decrypt_file(f, passphrase=myPass, output=fileNameOut)
     show_alert('Status: ' + status.status)
예제 #8
0
파일: config.py 프로젝트: spurge/loadr
def load(file):
    if file.name[len(file.name) - 4:] in ('.gpg', '.pgp'):
        gpg = GPG()
        gpg.encoding = 'utf-8'
        data = gpg.decrypt_file(file.name)
        click.echo(data)
    else:
        data = file.read()

    return json.loads(data, 'utf-8')
예제 #9
0
def decrypt_files(path, gpg: gnupg.GPG):
    for files in os.listdir(path):
        actual_path = path + "/" + files
        if os.path.isfile(actual_path):
            if files.endswith(".gpg"):
                logger.debug(f"decrypting: {actual_path}")
                with open(actual_path, "rb") as reader:
                    print(gpg.decrypt_file(reader, passphrase=__passphrase__, output=actual_path).status)
                logger.debug(f"encrypting: {actual_path}")
                with open(actual_path, "rb") as reader:
                    print(gpg.encrypt_file(reader, recipients=__newkeyid__, output=actual_path).status)
        else:
            decrypt_files(actual_path, gpg)
예제 #10
0
def decrypt_and_load(filename, passphrase):
    # initialize gpg
    gpg = GPG(gnupghome=f"{os.environ['HOME']}/.gnupg")

    # open the encrypted file and decrypt it
    with open(filename, "rb") as f:
        data = gpg.decrypt_file(f, passphrase=passphrase)

    # check for errors
    if not data.ok:
        raise Exception(data.stderr)

    # load the contents as yaml
    yml = ruamel.yaml.YAML(typ="safe")
    return yml.load(data.data)
예제 #11
0
파일: gpg.py 프로젝트: rbuzatu90/passpy
def read_key(path, gpg_bin, gpg_opts):
    """Read and decrypt a single key file.

    :param str path: The path to the key to decrypt.

    :param str gpg_bin: The path to the gpg binary.

    :param list gpg_opts: The options for gpg.

    :rtype: str
    :returns: The unencrypted content of the file at `path`.

    """
    gpg = GPG(gpgbinary=gpg_bin, options=gpg_opts)
    with open(path, 'rb') as key_file:
        return str(gpg.decrypt_file(key_file))
예제 #12
0
파일: gpg.py 프로젝트: bfrascher/passpy
def read_key(path, gpg_bin, gpg_opts):
    """Read and decrypt a single key file.

    :param str path: The path to the key to decrypt.

    :param str gpg_bin: The path to the gpg binary.

    :param list gpg_opts: The options for gpg.

    :rtype: str
    :returns: The unencrypted content of the file at `path`.

    """
    gpg = GPG(gpgbinary=gpg_bin, options=gpg_opts)
    with open(path, 'rb') as key_file:
        return str(gpg.decrypt_file(key_file))
예제 #13
0
def decrypt_file(filename, remove_source=None):
    cfg = ConfigFromJSON(section='gpg')

    if not op.exists(filename):
        raise ValueError('File {} not exisit'.format(filename))

    gpg = GPG()
    target = filename.rstrip('.gpg')
    with open(filename, 'rb') as f:
        dec = gpg.decrypt_file(f, passphrase=cfg.passphrase, output=target)
    if not dec.ok:
        raise RuntimeError(dec.status)

    if remove_source:
        os.remove(filename)

    return target
예제 #14
0
class Vault(object):

    def __init__(self):
        self.vault = {}
        self._gpg = GPG()
        self._file_descriptor = None
        self.passphrase = None

    def reload(self):
        if None in (self._file_descriptor, self.passphrase):
            raise RuntimeError('Cannot reload before calling .load()')
        self.load(self._file_descriptor, self.passphrase)

    def load(self, file_descriptor, passphrase):
        self._file_descriptor = file_descriptor
        self.passphrase = passphrase
        self._file_descriptor.seek(0)
        json_ = self._gpg.decrypt_file(self._file_descriptor, passphrase=self.passphrase)
        self.vault = json.loads(str(json_))

    def save(self, file_descriptor=None, passphrase=None):
        if file_descriptor is not None:
            self._file_descriptor = file_descriptor
        if passphrase is not None:
            self.passphrase = passphrase
        self._file_descriptor.seek(0)
        json_ = json.dumps(self.vault)
        encrypted = self._gpg.encrypt(json_, False, passphrase=self.passphrase, symmetric=True)
        self._file_descriptor.write(str(encrypted))

    def __getitem__(self, key):
        return self.vault[key]

    def get(self, name, default=None):
        return self.vault.get(name, default)

    def __setitem__(self, key, value):
        self.vault[key] = value

    def __delitem__(self, key):
        del self._vault[key]

    def list(self):
        return sorted(self._vault.keys())
예제 #15
0
    def execute(self):
        gpg = GPG(gnupghome=os.path.join(os.path.expanduser('~'), '.gnupg'))

        paths = [
            os.path.basename(f.path) for f in self.fm.thistab.get_selection()
        ]

        for p in [p for p in paths if p.endswith('gpg')]:
            with open(p, 'rb') as enc:
                dec_b = gpg.decrypt_file(enc)

            out_fname = os.path.splitext(p)[0]
            with open(out_fname, 'wb+') as dec_f:
                dec_f.write(dec_b.data)

            if self.arg(1) != 'true':
                os.remove(p)

            if tarfile.is_tarfile(out_fname):
                tarfile.open(out_fname).extractall(path='.')
                os.remove(out_fname)
예제 #16
0
if __name__ == '__main__':
    get_env_vars()
    parser = argparse.ArgumentParser(description=DESCR, epilog=EPILOG)
    parser.add_argument('-k', '--key', dest='key', type=str, help=KEY_DSC)
    parser.add_argument('-l', '--list',  action='store_true')
    parser.add_argument('-p', '--password',  action='store_true')
    parser.add_argument('-u', '--user',  action='store_true')
    parser.add_argument('-s', '--set',  action='store_true')
    parser.add_argument('-r', '--remove',  action='store_true')
    args = parser.parse_args()

    gpg_home, pass_loc = get_env_vars()
    gpg = GPG(gnupghome=gpg_home)
    with open(pass_loc, mode='rb') as f:
        decoded = gpg.decrypt_file(f, passphrase=getpass())
    if decoded.data == b'':
        print("Incorrect Passphrase")
        exit()
    passes = loads(clean_gpg_json(decoded.data))

    if args.list:
        for key in passes.keys(): print(key)
    if args.key is not None:
        if args.password:
            print_pass(passes, args.key)
        if args.user:
            print_user(passes, args.key)
    if args.set or args.remove:
        keys = gpg.list_keys()
        for index, key in enumerate(keys):
예제 #17
0
파일: pyaxo.py 프로젝트: ghtdak/pyaxo
class Axolotl:
    def __init__(self, name, dbname='axolotl.db', dbpassphrase='',
                 user_pathstring='~'):
        self.ratchetKey = None
        self.ratchetPKey = None
        self.name = name
        self.db = None
        self.mode = None
        self.staged_HK_mk = None
        self.state = None
        self.handshakeKey = None
        self.handshakePKey = None
        self.storeTime = None

        user_path = os.path.expanduser(user_pathstring)
        keyring = [user_path + '/.gnupg/pubring.gpg']
        secret_keyring = [user_path + '/.gnupg/secring.gpg']

        self.dbname = user_path + '/tmp/pyaxo_db/' + dbname

        self.gpg = GPG(gnupghome=user_path + '/.axolotl', gpgbinary='gpg',
                       keyring=keyring,
                       secret_keyring=secret_keyring,
                       options=['--throw-keyids',
                                '--personal-digest-preferences=sha256',
                                '--s2k-digest-algo=sha256'])
        self.gpg.encoding = 'utf-8'

        if dbpassphrase != '' or dbpassphrase is None:
            self.dbpassphrase = dbpassphrase
        else:
            self.dbpassphrase = getpass(
                'Database passphrase for ' + self.name + ': ').strip()

        self.db_init()

    def db_init(self):

        try:
            self.db = self.open_db()
        except sqlite3.OperationalError:
            raise (Axolotl_exception('Bad sql! Password problem - \
            cannot create the database.'))

        self.mode = None
        self.staged_HK_mk = {}

        self.state = {}
        self.state['DHIs_priv'], self.state['DHIs'] = self.genKey()
        self.state['DHRs_priv'], self.state['DHRs'] = self.genKey()

        self.handshakeKey, self.handshakePKey = self.genKey()

        # minimum time (seconds) to store missed ephemeral message keys
        self.storeTime = 2 * 86400
        with self.db:
            cur = self.db.cursor()

            cur.execute("""
            CREATE TABLE IF NOT EXISTS skipped_mk
            (my_identity, to_identity, HKr TEXT, mk TEXT,
              timestamp INTEGER )""")

            cur.execute("""
            CREATE UNIQUE INDEX IF NOT EXISTS
                         message_keys ON skipped_mk (mk)""")

            cur.execute("""
            CREATE TABLE IF NOT EXISTS conversations
            (my_identity TEXT, other_identity TEXT, RK TEXT, HKs TEXT,
              HKr TEXT, NHKs TEXT, NHKr TEXT, CKs TEXT, CKr TEXT,
              DHIs_priv TEXT, DHIs TEXT, DHIr TEXT, DHRs_priv TEXT,
              DHRs TEXT, DHRr TEXT, CONVid TEXT, Ns INTEGER, Nr INTEGER,
              PNs INTEGER, ratchet_flag INTEGER, mode INTEGER)""")

            cur.execute("""
            CREATE UNIQUE INDEX IF NOT EXISTS
                         conversation_route ON
                         conversations (my_identity, other_identity)""")
        self.commit_skipped_mk()

    def triple_dh(self, a, a0, B, B0):
        if self.mode is None:
            raise (Axolotl_exception('Mode must be set'))
        if self.mode:
            return sha256(
                self.gen_dh(a, B0) + self.gen_dh(a0, B) +
                self.gen_dh(a0, B0)).digest()
        else:
            return sha256(
                self.gen_dh(a0, B) + self.gen_dh(a, B0) +
                self.gen_dh(a0, B0)).digest()

    def initState(self, other_name, other_identityKey, other_handshakeKey,
                  other_ratchetKey, verify=True):
        if verify:
            print('Confirm ' + other_name + ' has identity key fingerprint:\n')
            fingerprint = sha224(other_identityKey).hexdigest().upper()
            fprint = ''
            for i in range(0, len(fingerprint), 4):
                fprint += fingerprint[i:i + 2] + ':'
            print(fprint[:-1] + '\n')
            print('Be sure to verify this fingerprint with ' + other_name +
                  ' by some out-of-band method!')
            print('Otherwise, you may be subject to a \
            Man-in-the-middle attack!\n')
            ans = raw_input('Confirm? y/N: ').strip()
            if ans != 'y':
                raise (Axolotl_exception('Key fingerprint \
                not confirmed - exception'))

        if self.state['DHIs'] < other_identityKey:
            self.mode = True
        else:
            self.mode = False
        mkey = self.triple_dh(self.state['DHIs_priv'], self.handshakeKey,
                              other_identityKey, other_handshakeKey)

        self.createState(other_name, mkey,
                         mode=self.mode,
                         other_identityKey=other_identityKey,
                         other_ratchetKey=other_ratchetKey)

    def createState(self, other_name, mkey, mode=None, other_identityKey=None,
                    other_ratchetKey=None):
        self.mode = mode

        if self.mode is None:  # mode not selected
            raise (Axolotl_exception('Mode must be set'))
        if self.mode:  # alice mode
            RK = pbkdf2(mkey, b'\x00', 10, prf='hmac-sha256')
            HKs = None
            HKr = pbkdf2(mkey, b'\x02', 10, prf='hmac-sha256')
            NHKs = pbkdf2(mkey, b'\x03', 10, prf='hmac-sha256')
            NHKr = pbkdf2(mkey, b'\x04', 10, prf='hmac-sha256')
            CKs = None
            CKr = pbkdf2(mkey, b'\x06', 10, prf='hmac-sha256')
            DHRs_priv = None
            DHRs = None
            DHRr = other_ratchetKey
            CONVid = pbkdf2(mkey, b'\x07', 10, prf='hmac-sha256')
            Ns = 0
            Nr = 0
            PNs = 0
            ratchet_flag = True
        else:  # bob mode
            RK = pbkdf2(mkey, b'\x00', 10, prf='hmac-sha256')
            HKs = pbkdf2(mkey, b'\x02', 10, prf='hmac-sha256')
            HKr = None
            NHKs = pbkdf2(mkey, b'\x04', 10, prf='hmac-sha256')
            NHKr = pbkdf2(mkey, b'\x03', 10, prf='hmac-sha256')
            CKs = pbkdf2(mkey, b'\x06', 10, prf='hmac-sha256')
            CKr = None
            DHRs_priv = self.state['DHRs_priv']
            DHRs = self.state['DHRs']
            DHRr = None
            CONVid = pbkdf2(mkey, b'\x07', 10, prf='hmac-sha256')
            Ns = 0
            Nr = 0
            PNs = 0
            ratchet_flag = False
        DHIr = other_identityKey

        self.state = \
            {'name': self.name, 'other_name': other_name, 'RK': RK,
             'HKs': HKs, 'HKr': HKr, 'NHKs': NHKs, 'NHKr': NHKr, 'CKs': CKs,
             'CKr': CKr, 'DHIs_priv': self.state['DHIs_priv'],
             'DHIs': self.state['DHIs'], 'DHIr': DHIr,
             'DHRs_priv': DHRs_priv, 'DHRs': DHRs, 'DHRr': DHRr,
             'CONVid': CONVid, 'Ns': Ns, 'Nr': Nr, 'PNs': PNs,
             'ratchet_flag': ratchet_flag,
             }

        self.ratchetKey = False
        self.ratchetPKey = False

    def encrypt(self, plaintext):
        if self.state['ratchet_flag']:
            self.state['DHRs_priv'], self.state['DHRs'] = self.genKey()
            self.state['HKs'] = self.state['NHKs']
            self.state['RK'] = sha256(self.state['RK'] +
                                      self.gen_dh(
                                          self.state['DHRs_priv'],
                                          self.state['DHRr'])).digest()
            if self.mode:
                self.state['NHKs'] = pbkdf2(self.state['RK'], b'\x03', 10,
                                            prf='hmac-sha256')
                self.state['CKs'] = pbkdf2(self.state['RK'], b'\x05', 10,
                                           prf='hmac-sha256')
            else:
                self.state['NHKs'] = pbkdf2(self.state['RK'], b'\x04', 10,
                                            prf='hmac-sha256')
                self.state['CKs'] = pbkdf2(self.state['RK'], b'\x06', 10,
                                           prf='hmac-sha256')
            self.state['PNs'] = self.state['Ns']
            self.state['Ns'] = 0
            self.state['ratchet_flag'] = False
        mk = sha256(self.state['CKs'] + '0').digest()
        msg1 = self.enc(self.state['HKs'], str(self.state['Ns']).zfill(3) +
                        str(self.state['PNs']).zfill(3) + self.state['DHRs'])
        msg2 = self.enc(mk, plaintext)
        pad_length = 106 - len(msg1)
        pad = os.urandom(pad_length - 1) + chr(pad_length)
        msg = msg1 + pad + msg2
        self.state['Ns'] += 1
        self.state['CKs'] = sha256(self.state['CKs'] + '1').digest()
        return msg

    def commit_skipped_mk(self):
        timestamp = int(time())
        with self.db:
            cur = self.db.cursor()
            for mk, HKr in self.staged_HK_mk.iteritems():
                cur.execute("""REPLACE INTO skipped_mk (my_identity,
                  to_identity, HKr, mk, timestamp ) VALUES (?, ?, ?, ?, ?)""",
                            self.state['name'],
                            self.state['other_name'],
                            b2a_base64(HKr).strip(),
                            b2a_base64(mk).strip(),
                            timestamp)

            rowtime = timestamp - self.storeTime
            cur.execute('DELETE FROM skipped_mk WHERE timestamp < ?',
                        (rowtime,))

    def trySkippedMK(self, msg, pad_length, name, other_name):
        with self.db:
            cur = self.db.cursor()
            cur.execute('SELECT * FROM skipped_mk')
            rows = cur.fetchall()
            for row in rows:
                if name == row[0] and other_name == row[1]:
                    msg1 = msg[:106 - pad_length]
                    msg2 = msg[106:]
                    header = self.dec(a2b_base64(row[2]), msg1)
                    body = self.dec(a2b_base64(row[3]), msg2)
                    if header != '' and body != '':
                        cur.execute('DELETE FROM skipped_mk WHERE mk = ?',
                                    (row[3],))
                        return body
        return False

    def stageSkippedMK(self, HKr, Nr, Np, CKr):
        CKp = CKr
        for i in range(Np - Nr):
            mk = sha256(CKp + '0').digest()
            CKp = sha256(CKp + '1').digest()
            self.staged_HK_mk[mk] = HKr

        mk = sha256(CKp + '0').digest()
        CKp = sha256(CKp + '1').digest()
        return CKp, mk

    def decrypt(self, msg):
        pad = msg[105:106]
        pad_length = ord(pad)
        msg1 = msg[:106 - pad_length]

        body = self.trySkippedMK(msg, pad_length, self.state['name'],
                                 self.state['other_name'])
        if body and body != '':
            return body

        header = None
        if self.state['HKr']:
            header = self.dec(self.state['HKr'], msg1)
        if header and header != '':
            Np = int(header[:3])
            CKp, mk = self.stageSkippedMK(self.state['HKr'], self.state['Nr'],
                                          Np, self.state['CKr'])
            body = self.dec(mk, msg[106:])
            if not body or body == '':
                raise (Axolotl_exception('Undecipherable message'))
        else:
            header = self.dec(self.state['NHKr'], msg1)
            if self.state['ratchet_flag'] or not header or header == '':
                raise (Axolotl_exception('Undecipherable message'))

            Np = int(header[:3])
            PNp = int(header[3:6])
            DHRp = header[6:]
            if self.state['CKr']:
                self.stageSkippedMK(self.state['HKr'], self.state['Nr'], PNp,
                                    self.state['CKr'])
            HKp = self.state['NHKr']
            RKp = sha256(
                self.state['RK'] + self.gen_dh(self.state['DHRs_priv'],
                                               DHRp)).digest()
            if self.mode:
                NHKp = pbkdf2(RKp, b'\x04', 10, prf='hmac-sha256')
                CKp = pbkdf2(RKp, b'\x06', 10, prf='hmac-sha256')
            else:
                NHKp = pbkdf2(RKp, b'\x03', 10, prf='hmac-sha256')
                CKp = pbkdf2(RKp, b'\x05', 10, prf='hmac-sha256')
            CKp, mk = self.stageSkippedMK(HKp, 0, Np, CKp)
            body = self.dec(mk, msg[106:])
            if not body or body == '':
                raise (Axolotl_exception('Undecipherable message'))

            self.state['RK'] = RKp
            self.state['HKr'] = HKp
            self.state['NHKr'] = NHKp
            self.state['DHRr'] = DHRp
            self.state['DHRs_priv'] = None
            self.state['DHRs'] = None
            self.state['ratchet_flag'] = True
        self.commit_skipped_mk()
        self.state['Nr'] = Np + 1
        self.state['CKr'] = CKp
        return body

    def encrypt_file(self, filename):
        with open(filename, 'r') as f:
            plaintext = f.read()
        ciphertext = b2a_base64(self.encrypt(plaintext))
        with open(filename + '.asc', 'w') as f:
            lines = [ciphertext[i:i + 64] for i in
                     xrange(0, len(ciphertext), 64)]
            for line in lines:
                f.write(line + '\n')

    def decrypt_file(self, filename):
        with open(filename, 'r') as f:
            ciphertext = a2b_base64(f.read())
        plaintext = self.decrypt(ciphertext)
        print(plaintext)

    def encrypt_pipe(self):
        plaintext = sys.stdin.read()
        ciphertext = b2a_base64(self.encrypt(plaintext))
        sys.stdout.write(ciphertext)
        sys.stdout.flush()

    def decrypt_pipe(self):
        ciphertext = a2b_base64(sys.stdin.read())
        plaintext = self.decrypt(ciphertext)
        sys.stdout.write(plaintext)
        sys.stdout.flush()

    def printKeys(self):
        print('Your Identity key is:\n' + b2a_base64(
            self.state['DHIs']))
        fingerprint = sha224(self.state['DHIs']).hexdigest().upper()
        fprint = ''
        for i in range(0, len(fingerprint), 4):
            fprint += fingerprint[i:i + 2] + ':'
        print('Your identity key fingerprint is: ')
        print(fprint[:-1] + '\n')
        print('Your Ratchet key is:\n' + b2a_base64(
            self.state['DHRs']))
        if self.handshakeKey:
            print('Your Handshake key is:\n' + b2a_base64(
                self.handshakePKey))
        else:
            print('Your Handshake key is not available')

    def to_json(self):
        _j = {'name': self.name,
              'identity_key': b2a_base64(self.state('DHIs')),
              'fingerprint': sha224(self.state['DHIs']).hexdigest().upper(),
              'ratchet_key': b2a_base64(self.state['DHRs'])}
        return json.dumps(_j)

    def init_from_json(self, _jsn):
        _k = json.loads(_jsn)
        self.initState(_k['name'], a2b_base64(_k['identity_key']),
                       a2b_base64(_k['fingerprint']),
                       a2b_base64(_k['ratchet_key']))
        self.saveState()

    def saveState(self):
        ktup = ('HKs', 'HKr', 'CKs', 'CKR', 'DHIr', 'DHRs_priv', 'DHRs')

        v = {k: b2a_base64(self.state[k]).strip for k in ktup}

        ratchet_flag = 1 if self.state['ratchet_flag'] else 0
        mode = 1 if self.mode else 0
        with self.db:
            cur = self.db.cursor()
            cur.execute("""\
            REPLACE INTO conversations (
                       my_identity, other_identity, RK,HKS, HKr, NHKs, NHKr,
                       CKs, CKr, DHIs_priv, DHIs, DHIr, DHRs_priv, DHRs,
                       DHRr, CONVid, Ns, Nr, PNs, ratchet_flag, mode)
                       VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
                       ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
                        (self.state['name'],
                         self.state['other_name'],
                         b2a_base64(self.state['RK']).strip(),
                         v['HKs'], v['HKr'],
                         b2a_base64(self.state['NHKs']).strip(),
                         b2a_base64(self.state['NHKr']).strip(),
                         v['CKs'], v['CKr'],
                         b2a_base64(self.state['DHIs_priv']).strip(),
                         b2a_base64(self.state['DHIs']).strip(),
                         v['DHIr'], v['DHRs_priv'], v['DHRs'], v['DHRr'],
                         b2a_base64(self.state['CONVid']).strip(),
                         self.state['Ns'], self.state['Nr'], self.state['PNs'],
                         ratchet_flag,
                         mode
                         ))
        self.write_db()

    def loadState(self, name, other_name):
        self.db = self.open_db()
        with self.db:
            cur = self.db.cursor()
            try:
                cur.execute('SELECT * FROM conversations')
            except sqlite3.OperationalError:
                raise (Axolotl_exception('Bad sql! Password problem - \
                cannot loadState()'))

            rows = cur.fetchall()
            for row in rows:
                if row[0] == name and row[1] == other_name:
                    self.state = {'name': row[0],
                                  'other_name': row[1],
                                  'RK': a2b_base64(row[2]),
                                  'NHKs': a2b_base64(row[5]),
                                  'NHKr': a2b_base64(row[6]),
                                  'DHIs_priv': a2b_base64(row[9]),
                                  'DHIs': a2b_base64(row[10]),
                                  'CONVid': a2b_base64(row[15]),
                                  'Ns': row[16],
                                  'Nr': row[17],
                                  'PNs': row[18]}

                    self.name = self.state['name']

                    def do_bin(loc):
                        if row[loc] == '0':
                            return None
                        else:
                            return a2b_base64(row[loc])

                    self.state['HKs'] = do_bin(3)
                    self.state['HKr'] = do_bin(4)
                    self.state['CKs'] = do_bin(7)
                    self.state['CKr'] = do_bin(8)
                    self.state['DHIr'] = do_bin(11)
                    self.state['DHRs_priv'] = do_bin(12)
                    self.state['DHRs'] = do_bin(13)
                    self.state['DHRr'] = do_bin(14)

                    ratchet_flag = row[19]
                    if ratchet_flag == 1:
                        self.state['ratchet_flag'] = True
                    else:
                        self.state['ratchet_flag'] = False

                    mode = row[20]
                    self.mode = True if mode == 1 else False
                    return  # exit at first match
            return False  # if no matches

    def open_db(self):

        db = sqlite3.connect(':memory:')

        try:
            with open(self.dbname, 'rb') as f:
                if self.dbpassphrase is not None:
                    sql = \
                        self.gpg.decrypt_file(f, passphrase=self.dbpassphrase)

                    if sql is not None and sql != '':
                        db.cursor().executescript(sql.data)
                        return db
                    else:
                        raise (Axolotl_exception('Bad passphrase!'))
                else:
                    sql = f.read()
                    db.cursor().executescript(sql)
                    return db
        except IOError:
            return db

    def write_db(self):

        sql = ''
        for item in self.db.iterdump():
            sql = sql + item + '\n'
        if self.dbpassphrase is not None:
            crypt_sql = self.gpg.encrypt(sql, recipients=None,
                                         symmetric='AES256',
                                         armor=False,
                                         always_trust=True,
                                         passphrase=self.dbpassphrase)

            with open(self.dbname, 'wb') as f:
                f.write(crypt_sql.data)
        else:
            with open(self.dbname, 'w') as f:
                f.write(sql)

    def print_state(self):

        print('\nWarning: saving this data to disk is insecure!\n')

        for key in sorted(self.state):
            if 'priv' in key:
                pass
            else:
                if self.state[key] is None:
                    print(key + ': None')
                elif type(self.state[key]) is bool:
                    if self.state[key]:
                        print(key + ': True')
                    else:
                        print(key + ': False')
                elif type(self.state[key]) is str:
                    try:
                        self.state[key].decode('ascii')
                        print(key + ': ' + self.state[key])
                    except UnicodeDecodeError:
                        print(key + ': ' + b2a_base64(
                            self.state[key]).strip())
                else:
                    print(key + ': ' + str(self.state[key]))
        if self.mode:
            print('Mode: Alice')
        else:
            print('Mode: Bob')

    @staticmethod
    def genKey():
        key = keys.Private()
        privkey = key.private
        pubkey = key.get_public().serialize()
        return privkey, pubkey

    @staticmethod
    def gen_dh(a, B):
        key = keys.Private(secret=a)
        return key.get_shared_key(keys.Public(B))

    def dec(self, key, encrypted):
        key = hexlify(key)
        msg = self.gpg.decrypt(GPG_HEADER + encrypted,
                               passphrase=key, always_trust=True)
        return msg.data

    def enc(self, key, plaintext):
        key = hexlify(key)
        msg = self.gpg.encrypt(plaintext, recipients=None,
                               symmetric=GPG_CIPHER,
                               armor=False,
                               always_trust=True, passphrase=key)
        return msg.data[6:]
예제 #18
0
class gpg(object):
    """
    module to wrap the gnupg library and gpg binary
    """
    def __init__(self, folder_path=None, binary_path=None):
        # ugly but working
        if binary_path is None:
            binary_path = join(project_base, "gpg", "gpg.exe")
            if not isfile(binary_path):
                binary_path = join(project_base, 'gpg')
                if not isfile(binary_path):
                    binary_path = find_executable('gpg')
                    if not isfile(binary_path):
                        raise RuntimeError('gpg not found')
        self.gpg = GPG(
            binary_path,  # gpgbinary
            folder_path,  # gnupghome
            verbose=False,
            options=["--allow-non-selfsigned-uid"])

    def get_key(self, fingerprint, private, passphrase):
        """
        returns the key belonging to the fingerprint given. if 'private' is
        True, the private key is returned. If 'private' is False, the public
        key will be returned.
        """
        key = self.gpg.export_keys(fingerprint,
                                   private,
                                   armor=False,
                                   passphrase=passphrase)
        return b64encode(key)

    def add_keypair(self, public_key, private_key, site, user, passphrase):
        """
        add a keypair into the gpg key database
        """
        try:
            result1 = self.gpg.import_keys(b64decode(public_key))
            result2 = self.gpg.import_keys(b64decode(private_key))
        except TypeError as error:
            getLogger(__name__).critical("add_keypair TypeError " + str(error))
        # make sure this is a key _pair_
        try:
            assert result1.fingerprints[0] == result2.fingerprints[0]
        except (IndexError, AssertionError) as error:
            getLogger(__name__).exception(
                'add_keypair IndexError/AssertionError: ' + str(error))
            return None
        fingerprint = result1.fingerprints[0]

        if self.is_passphrase_valid(passphrase=passphrase,
                                    fingerprint=fingerprint):
            old_fingerprint = self.get_fingerprint(site, user)
            if not old_fingerprint:
                sql = "INSERT INTO keys (site, user, fingerprint) VALUES (?, ?, ?)"
                database_execute(sql, (site, user, fingerprint))
            else:
                sql = "UPDATE keys SET SITE=? WHERE fingerprint=?"
                database_execute(sql, (site, old_fingerprint))
                if fingerprint != old_fingerprint:
                    getLogger(__name__).warn('updating %s fingerprint to %s' %
                                             (user, fingerprint))
            return fingerprint
        else:
            return None

    def add_public_key(self, site, user, public_key):
        """
        add a public key into the gpg key database
        """
        try:
            result1 = self.gpg.import_keys(b64decode(public_key))
            fingerprint = result1.fingerprints[0]

            sql = "INSERT INTO keys (site, user, fingerprint) VALUES (?, ?, ?)"
            database_execute(sql, (site, user, fingerprint))
            return fingerprint
        except TypeError as error:
            getLogger(__name__).critical("add_public_key TypeError " +
                                         str(error))
        except DatabaseError as error:
            getLogger(__name__).critical("add_public_key DatabaseError " +
                                         str(error))

    def is_passphrase_valid(self,
                            passphrase,
                            label=None,
                            user=None,
                            fingerprint=None):
        if not fingerprint:
            fingerprint = self.get_fingerprint(label, user)

        sign_result = self.gpg.sign("test",
                                    keyid=fingerprint,
                                    passphrase=passphrase)

        return sign_result.data != ''

    def generate(self, passphrase, site, user):
        """
        Generate a new 2048 bit GPG key and add it to the gpg manager.
        """
        data = self.gpg.gen_key_input(key_length=2048, passphrase=passphrase)
        dat = self.gpg.gen_key(data)
        fingerprint = dat.fingerprint
        sql = "INSERT INTO keys (site, user, fingerprint) VALUES (?, ?, ?);"
        database_execute(sql, (site, user, fingerprint))
        return fingerprint

    def get_fingerprint(self, site, user):
        sql = "select fingerprint from keys where site = ? and user = ?"
        result = database_execute(sql, (site, user))
        if not len(result):
            return None
        return result[0][0]

    def has_key(self, site, user):
        """
        Check whether a key is present for a certain site and user
        """
        return self.get_fingerprint(site, user) is None

    def encrypt(self, data, site, user, armor=False):
        """
        encrypt data for user at site.
        """
        fingerprint = self.get_fingerprint(site, user)
        cryptdata = self.gpg.encrypt_file(StringIO(data),
                                          fingerprint,
                                          always_trust=True,
                                          armor=armor)
        return str(cryptdata)

    def decrypt(self, data, passphrase):
        """
        decrypt data received from site.
        """
        datafile = StringIO(data)
        result = self.gpg.decrypt_file(datafile,
                                       passphrase=passphrase,
                                       always_trust=True)
        return str(result)

    @staticmethod
    def add_pkcs7_padding(contents):
        # Input strings must be a multiple of the segment size 16 bytes in length
        segment_size = 16

        # calculate how much padding is needed
        old_contents_length = len(contents)
        next_mult = old_contents_length + (segment_size -
                                           old_contents_length % segment_size)
        getLogger(__name__).debug(
            'old contents length %s || new contents length %s' %
            (old_contents_length, next_mult))

        # do the padding
        padding_byte = chr(next_mult - old_contents_length)
        contents = contents.ljust(next_mult, padding_byte)

        return contents

    @staticmethod
    def remove_pkcs7_padding(contents):
        """
        Remove PKCS#7 padding bytes

        >>> gpg.remove_pkcs7_padding('some_content'.ljust(16, chr(4)))
        'some_content'

        >>> gpg.remove_pkcs7_padding('some_content')
        'some_content'

        >>> gpg.remove_pkcs7_padding('')
        ''

        :param contents:
        :return: contents without padding
        """
        if len(contents) < 1:
            getLogger(__name__).debug(
                'contents is empty. No PKCS#7 padding removed')
            return contents

        bytes_to_remove = ord(contents[-1])  # will work up to 255 bytes

        # check if contents have valid PKCS#7 padding
        if bytes_to_remove > 1 and contents[-2] != contents[-1]:
            getLogger(__name__).debug('no PKCS#7 padding detected')
            return contents

        getLogger(__name__).debug('removing %s bytes of PKCS#7 padding' %
                                  bytes_to_remove)
        return contents[0:(len(contents) - bytes_to_remove)]