| #!/usr/bin/env python3 |
| |
| """Detach CMS encrypted data. |
| |
| Detach encrypted data from a CMS envelopedData or authEnvelopedData |
| message into a separate file. |
| """ |
| |
| import argparse |
| from pathlib import Path |
| |
| from asn1crypto.cms import ContentInfo, AuthEnvelopedData, EnvelopedData |
| |
| # Parse command-line arguments |
| # |
| parser = argparse.ArgumentParser( |
| description=__doc__, |
| formatter_class=argparse.RawDescriptionHelpFormatter, |
| ) |
| parser.add_argument("-d", "--data", metavar="FILE", type=Path, |
| help="Write detached data (without envelope) to FILE") |
| parser.add_argument("-e", "--envelope", metavar="FILE", type=Path, |
| help="Write envelope (without data) to FILE") |
| parser.add_argument("-o", "--overwrite", action="store_true", |
| help="Overwrite output files") |
| parser.add_argument("file", type=Path, 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" |
| |
| # Read input envelope |
| # |
| envelope = ContentInfo.load(args.file.read_bytes()) |
| |
| # Locate encrypted content info |
| # |
| content = envelope["content"] |
| if type(content) is AuthEnvelopedData: |
| encinfo = content["auth_encrypted_content_info"] |
| elif type(content) is EnvelopedData: |
| encinfo = content["encrypted_content_info"] |
| else: |
| parser.error("Input file does not contain any encrypted data") |
| |
| # Detach encrypted content data |
| # |
| data = encinfo["encrypted_content"] |
| del encinfo["encrypted_content"] |
| |
| # Write envelope (without data), if applicable |
| # |
| if args.envelope: |
| with args.envelope.open(mode=outmode) as fh: |
| fh.write(envelope.dump()) |
| |
| # Write data (without envelope), if applicable |
| # |
| if args.data: |
| with args.data.open(mode=outmode) as fh: |
| fh.write(data.contents) |