From 70a338343ebc3114866dc8aa0f3d073d84111902 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 22 Aug 2017 13:29:45 +0200 Subject: [PATCH] implement decryption for tolerant mode MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Not possible to reuse the existing CLI decryption since we’re operating with fds in scan mode. --- deltatar/crypto.py | 67 ++++++++++++++++++++++++++++++++++++++++++--------- 1 files changed, 55 insertions(+), 12 deletions(-) diff --git a/deltatar/crypto.py b/deltatar/crypto.py index 268bbbf..7528281 100755 --- a/deltatar/crypto.py +++ b/deltatar/crypto.py @@ -590,14 +590,48 @@ def inspect_hdr (fd, off): return HDR_CAND_GOOD, hdr -def try_decrypt (fd, off, hdr, fname=None): +def try_decrypt (fd, off, hdr, secret, fname=None): """ Attempt to decrypt the object in the (seekable) descriptor *fd* starting at - *off* using the metadata in *hdr*. An output file can be specified with - *fname*; if it is *None*, the decrypted payload will be discarded. + *off* using the metadata in *hdr* and *secret*. An output file can be + specified with *fname*; if it is *None*, the decrypted payload will be + discarded. + + Always creates a fresh decryptor, so validation steps across objects don’t + apply. """ + ctleft = hdr ["ctsize"] + pos = off + + ks = secret [0] + if ks == PDTCRYPT_SECRET_PW: + decr = Decrypt (password=secret [1]) + elif ks == PDTCRYPT_SECRET_KEY: + key = binascii.unhexlify (secret [1]) + decr = Decrypt (key=key) + else: + raise RuntimeError + + if fname is not None: raise NotImplementedError + + decr.next (hdr) + + try: + os.lseek (fd, pos, os.SEEK_SET) + while ctleft > 0: + cnksiz = min (ctleft, PDTCRYPT_BLOCKSIZE) + cnk = os.read (fd, cnksiz) + ctleft -= cnksiz + pos += cnksiz + _pt = decr.process (cnk) + + _pt = decr.done () + except Exception as exn: + noise ("PDT: error decrypting object %d–%d@%d, %d B remaining [%s]" + % (off, off + hdr ["ctsize"], pos, ctleft, exn)) + raise - raise NotImplementedError + return pos - off ############################################################################### @@ -1705,7 +1739,7 @@ def noise_output_candidates (cands, indent=8, cols=PDTCRYPT_TT_COLUMNS): noise (line) -def mode_scan (pw, fname, nacl=None): +def mode_scan (secret, fname, nacl=None): """ Dissect a binary file, looking for PDTCRYPT headers and objects. """ @@ -1740,19 +1774,22 @@ def mode_scan (pw, fname, nacl=None): else: off0 = cand + PDTCRYPT_HDR_SIZE if PDTCRYPT_VERBOSE is True: - noise ("PDT: read payload @%d: %s" % (off0, hdr_fmt (hdr))) - vdtt = try_decrypt (fd, off0, hdr) + noise ("PDT: read payload @%d" % off0) + pretty = hdr_fmt_pretty (hdr) + noise (reduce (lambda a, e: (a + "\n" if a else "") + "PDT:\t· " + e, + pretty.splitlines (), "")) - if vdt == HDR_CAND_GOOD and vdtt == HDR_CAND_GOOD: + ok = try_decrypt (fd, off0, hdr, secret) == hdr ["ctsize"] + if vdt == HDR_CAND_GOOD and ok is True: noise ("PDT: %d → ✓ valid object %d–%d" % (cand, off0, off0 + hdr ["ctsize"])) - elif vdt == HDR_CAND_FISHY and vdtt == HDR_CAND_GOOD: + elif vdt == HDR_CAND_FISHY and ok is True: noise ("PDT: %d → × object %d–%d, corrupt header" % (cand, off0, off0 + hdr ["ctsize"])) - elif vdt == HDR_CAND_GOOD and vdtt == HDR_CAND_FISHY: + elif vdt == HDR_CAND_GOOD and ok is False: noise ("PDT: %d → × object %d–%d, problematic payload" % (cand, off0, off0 + hdr ["ctsize"])) - elif vdt == HDR_CAND_FISHY and vdtt == HDR_CAND_FISHY: + elif vdt == HDR_CAND_FISHY and ok is False: noise ("PDT: %d → × object %d–%d, corrupt header, problematic " "ciphertext" % (cand, off0, off0 + hdr ["ctsize"])) else: @@ -1760,6 +1797,12 @@ def mode_scan (pw, fname, nacl=None): finally: os.close (fd) + if len (junk) == 0: + noise ("PDT: all headers ok") + else: + noise ("PDT: %d candidates not parseable as headers:" % len (junk)) + noise_output_candidates (junk) + def usage (err=False): out = print if err is True: @@ -1916,7 +1959,7 @@ def parse_argv (argv): bail ("ERROR: please supply an input file for scanning") if insspec == '-': bail ("ERROR: input must be seekable; please specify a file") - return True, partial (mode_scan, secret [1].encode (), insspec, nacl) + return True, partial (mode_scan, secret, insspec, nacl) if subcommand == PDTCRYPT_SUB_SCRYPT: if secret [0] == PDTCRYPT_SECRET_KEY: -- 1.7.1