| #!/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) |