def evaluate_pgp(self, tree, check_sigs=True, decrypt=False): if 'text_parts' not in tree: return tree pgpdata = [] for part in tree['text_parts']: if 'crypto' not in part: part['crypto'] = {} ei = si = None if check_sigs: if part['type'] == 'pgpbeginsigned': pgpdata = [part] elif part['type'] == 'pgpsignedtext': pgpdata.append(part) elif part['type'] == 'pgpsignature': pgpdata.append(part) try: gpg = GnuPG() message = ''.join([p['data'].encode(p['charset']) for p in pgpdata]) si = pgpdata[1]['crypto']['signature' ] = gpg.verify(message) pgpdata[0]['data'] = '' pgpdata[2]['data'] = '' except Exception, e: print e if decrypt: if part['type'] in ('pgpbegin', 'pgptext'): pgpdata.append(part) elif part['type'] == 'pgpend': pgpdata.append(part) gpg = GnuPG() (signature_info, encryption_info, text ) = gpg.decrypt(''.join([p['data'] for p in pgpdata])) # FIXME: If the data is binary, we should provide some # sort of download link or maybe leave the PGP # blob entirely intact, undecoded. text, charset = self.decode_text(text, binary=False) ei = pgpdata[1]['crypto']['encryption'] = encryption_info si = pgpdata[1]['crypto']['signature'] = signature_info if encryption_info["status"] == "decrypted": pgpdata[1]['data'] = text pgpdata[0]['data'] = "" pgpdata[2]['data'] = "" # Bubbling up! if (si or ei) and 'crypto' not in tree: tree['crypto'] = {'signature': SignatureInfo(), 'encryption': EncryptionInfo()} if si: tree['crypto']['signature'].mix(si) if ei: tree['crypto']['encryption'].mix(ei)
def evaluate_pgp(self, tree, check_sigs=True, decrypt=False): if "text_parts" not in tree: return tree pgpdata = [] for part in tree["text_parts"]: if "crypto" not in part: part["crypto"] = {} ei = si = None if check_sigs: if part["type"] == "pgpbeginsigned": pgpdata = [part] elif part["type"] == "pgpsignedtext": pgpdata.append(part) elif part["type"] == "pgpsignature": pgpdata.append(part) try: gpg = GnuPG() message = "".join([p["data"].encode(p["charset"]) for p in pgpdata]) si = pgpdata[1]["crypto"]["signature"] = gpg.verify(message) pgpdata[0]["data"] = "" pgpdata[2]["data"] = "" except Exception, e: print e if decrypt: if part["type"] in ("pgpbegin", "pgptext"): pgpdata.append(part) elif part["type"] == "pgpend": pgpdata.append(part) gpg = GnuPG() (signature_info, encryption_info, text) = gpg.decrypt("".join([p["data"] for p in pgpdata])) # FIXME: If the data is binary, we should provide some # sort of download link or maybe leave the PGP # blob entirely intact, undecoded. text, charset = self.decode_text(text, binary=False) ei = pgpdata[1]["crypto"]["encryption"] = encryption_info si = pgpdata[1]["crypto"]["signature"] = signature_info if encryption_info["status"] == "decrypted": pgpdata[1]["data"] = text pgpdata[0]["data"] = "" pgpdata[2]["data"] = "" # Bubbling up! if (si or ei) and "crypto" not in tree: tree["crypto"] = {"signature": SignatureInfo(), "encryption": EncryptionInfo()} if si: tree["crypto"]["signature"].mix(si) if ei: tree["crypto"]["encryption"].mix(ei)
def decrypt_gpg(lines, fd): for line in fd: lines.append(line) if line.startswith(GPG_END_MESSAGE): break gpg = GnuPG() _, encryption_info, plaintext = gpg.decrypt(''.join(lines)) if encryption_info['status'] != 'decrypted': gpg_exec = distutils.spawn.find_executable('gpg') gpg_version = gpg.version() raise AccessError("GPG (version: %s, location: %s) was unable to decrypt the data: %s" % (gpg_version, gpg_exec, encryption_info['status'])) return plaintext.splitlines(True)
def UnwrapMimeCrypto(part, si=None, ei=None): """ This method will replace encrypted and signed parts with their contents and set part attributes describing the security properties instead. """ part.signature_info = si or SignatureInfo() part.encryption_info = ei or EncryptionInfo() mimetype = part.get_content_type() if part.is_multipart(): # FIXME: Check the protocol. PGP? Something else? # FIXME: This is where we add hooks for other MIME encryption # schemes, so route to callbacks by protocol. if mimetype == 'multipart/signed': gpg = GnuPG() boundary = part.get_boundary() payload, signature = part.get_payload() # The Python get_payload() method likes to rewrite headers, # which breaks signature verification. So we manually parse # out the raw payload here. head, raw_payload, junk = part.as_string( ).replace('\r\n', '\n').split('\n--%s\n' % boundary, 2) part.signature_info = gpg.verify( gpg.pgpmime_normalize(raw_payload), signature.get_payload()) # Reparent the contents up, removing the signature wrapper part.set_payload(payload.get_payload()) for h in payload.keys(): del part[h] for h, v in payload.items(): part.add_header(h, v) # Try again, in case we just unwrapped another layer # of multipart/something. return UnwrapMimeCrypto(part, si=part.signature_info, ei=part.encryption_info) elif mimetype == 'multipart/encrypted': gpg = GnuPG() preamble, payload = part.get_payload() (part.signature_info, part.encryption_info, decrypted ) = gpg.decrypt(payload.as_string()) if part.encryption_info['status'] == 'decrypted': newpart = email.parser.Parser().parse( StringIO.StringIO(decrypted)) # Reparent the contents up, removing the encryption wrapper part.set_payload(newpart.get_payload()) for h in newpart.keys(): del part[h] for h, v in newpart.items(): part.add_header(h, v) # Try again, in case we just unwrapped another layer # of multipart/something. return UnwrapMimeCrypto(part, si=part.signature_info, ei=part.encryption_info) # If we are still multipart after the above shenanigans, recurse # into our subparts and unwrap them too. if part.is_multipart(): for subpart in part.get_payload(): UnwrapMimeCrypto(subpart, si=part.signature_info, ei=part.encryption_info) else: # FIXME: This is where we would handle cryptoschemes that don't # appear as multipart/... pass