#!/usr/bin/env python3 """Detach CMS encrypted data. Detach encrypted data from a CMS envelopedData or authEnvelopedData message into a separate file. """ import argparse import asn1 # Parse command-line arguments # parser = argparse.ArgumentParser( description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter, ) parser.add_argument("-d", "--data", metavar="FILE", help="Write detached data (without envelope) to FILE") parser.add_argument("-e", "--envelope", metavar="FILE", help="Write envelope (without data) to FILE") parser.add_argument("-o", "--overwrite", action="store_true", help="Overwrite output files") parser.add_argument("file", help="Input envelope file") args = parser.parse_args() if args.data is None and args.envelope is None: parser.error("at least one of --data and --envelope is required") outmode = "wb" if args.overwrite else "xb" # Create decoder # decoder = asn1.Decoder() with open(args.file, mode="rb") as fh: decoder.start(fh.read()) # Create encoder # encoder = asn1.Encoder() encoder.start() # Detach encrypted data # data = None datastack = [ asn1.Numbers.Sequence, 0, asn1.Numbers.Sequence, asn1.Numbers.Sequence ] stack = [] while stack or not decoder.eof(): if decoder.eof(): encoder.leave() decoder.leave() stack.pop() else: tag = decoder.peek() if tag.typ == asn1.Types.Constructed: encoder.enter(nr=tag.nr, cls=tag.cls) decoder.enter() stack.append(tag.nr) else: (tag, value) = decoder.read() if stack == datastack and tag.nr == 0: data = value else: encoder.write(value, nr=tag.nr, cls=tag.cls) envelope = encoder.output() if data is None: parser.error("Input file does not contain any encrypted data") # Write envelope (without data), if applicable # if args.envelope: with open(args.envelope, mode=outmode) as fh: fh.write(envelope) # Write data (without envelope), if applicable # if args.data: with open(args.data, mode=outmode) as fh: fh.write(data)