Example #1
0
def test_identity_crypt_filter(use_alias, with_never_decrypt):
    w = writer.PdfFileWriter()
    sh = StandardSecurityHandler.build_from_pw("secret")
    w.security_handler = sh
    idf: IdentityCryptFilter = IdentityCryptFilter()
    assert sh.crypt_filter_config[pdf_name("/Identity")] is idf
    if use_alias:
        sh.crypt_filter_config._crypt_filters[pdf_name("/IdentityAlias")] = idf
        assert sh.crypt_filter_config[pdf_name("/IdentityAlias")] is idf
    if use_alias:
        # identity filter can't be serialised, so this should throw an error
        with pytest.raises(misc.PdfError):
            w._assign_security_handler(sh)
        return
    else:
        w._assign_security_handler(sh)
    test_bytes = b'This is some test data that should remain unencrypted.'
    test_stream = generic.StreamObject(stream_data=test_bytes, handler=sh)
    test_stream.apply_filter("/Crypt",
                             params={pdf_name("/Name"): pdf_name("/Identity")})
    ref = w.add_object(test_stream).reference
    out = BytesIO()
    w.write(out)

    r = PdfFileReader(out)
    r.decrypt("secret")
    the_stream = r.get_object(ref, never_decrypt=with_never_decrypt)
    assert the_stream.encoded_data == test_bytes
    assert the_stream.data == test_bytes
Example #2
0
def test_aes256_perm_read():
    r = PdfFileReader(BytesIO(MINIMAL_ONE_FIELD_AES256))
    result = r.decrypt("ownersecret")
    assert result.permission_flags is None
    r = PdfFileReader(BytesIO(MINIMAL_ONE_FIELD_AES256))
    result = r.decrypt("usersecret")
    assert result.permission_flags == -4

    assert r.trailer['/Encrypt']['/P'] == -4
Example #3
0
def test_copy_encrypted_file():
    r = PdfFileReader(BytesIO(MINIMAL_ONE_FIELD_AES256))
    r.decrypt("ownersecret")
    w = writer.copy_into_new_writer(r)
    old_root_ref = w.root_ref
    out = BytesIO()
    w.write(out)
    r = PdfFileReader(out)
    assert r.root_ref == old_root_ref
    assert len(r.root['/AcroForm']['/Fields']) == 1
    assert len(r.root['/Pages']['/Kids']) == 1
Example #4
0
def test_decrypt_ef_without_explicit_crypt_filter():
    # such files violate the spec, but since we can deal with them gracefully,
    # we certainly should

    with open(PDF_DATA_DIR + '/embedded-encrypted-nocf.pdf', 'rb') as inf:
        r = PdfFileReader(inf)
        ef_stm = r.root['/Names']['/EmbeddedFiles']['/Names'][1]['/EF'] \
            .raw_get('/F')
        r.decrypt('secret')
        assert not ef_stm.get_object()._has_crypt_filter
        assert ef_stm.get_object().data == VECTOR_IMAGE_PDF
def test_sign_crypt_aes256(password):
    w = IncrementalPdfFileWriter(BytesIO(MINIMAL_ONE_FIELD_AES256))
    w.encrypt(password)
    out = signers.sign_pdf(w,
                           signers.PdfSignatureMetadata(),
                           signer=FROM_CA,
                           existing_fields_only=True)

    r = PdfFileReader(out)
    r.decrypt(password)
    s = r.embedded_signatures[0]
    val_trusted(s)
Example #6
0
def test_custom_crypt_filter(with_hex_filter, main_unencrypted):
    w = writer.PdfFileWriter()
    custom = pdf_name('/Custom')
    crypt_filters = {
        custom: StandardRC4CryptFilter(keylen=16),
    }
    if main_unencrypted:
        # streams/strings are unencrypted by default
        cfc = CryptFilterConfiguration(crypt_filters=crypt_filters)
    else:
        crypt_filters[STD_CF] = StandardAESCryptFilter(keylen=16)
        cfc = CryptFilterConfiguration(crypt_filters=crypt_filters,
                                       default_string_filter=STD_CF,
                                       default_stream_filter=STD_CF)
    sh = StandardSecurityHandler.build_from_pw_legacy(
        rev=StandardSecuritySettingsRevision.RC4_OR_AES128,
        id1=w.document_id[0],
        desired_user_pass="******",
        desired_owner_pass="******",
        keylen_bytes=16,
        crypt_filter_config=cfc)
    w._assign_security_handler(sh)
    test_data = b'This is test data!'
    dummy_stream = generic.StreamObject(stream_data=test_data)
    dummy_stream.add_crypt_filter(name=custom, handler=sh)
    ref = w.add_object(dummy_stream)
    dummy_stream2 = generic.StreamObject(stream_data=test_data)
    ref2 = w.add_object(dummy_stream2)

    if with_hex_filter:
        dummy_stream.apply_filter(pdf_name('/AHx'))
    out = BytesIO()
    w.write(out)
    r = PdfFileReader(out)
    r.decrypt("ownersecret")
    obj: generic.StreamObject = r.get_object(ref.reference)
    assert obj.data == test_data
    if with_hex_filter:
        cf_dict = obj['/DecodeParms'][1]
    else:
        cf_dict = obj['/DecodeParms']

    assert cf_dict['/Name'] == pdf_name('/Custom')

    obj2: generic.DecryptedObjectProxy = r.get_object(
        ref2.reference, transparent_decrypt=False)
    raw = obj2.raw_object
    assert isinstance(raw, generic.StreamObject)
    if main_unencrypted:
        assert raw.encoded_data == test_data
    else:
        assert raw.encoded_data != test_data
def test_sign_crypt_rc4_new(password, file):
    w = IncrementalPdfFileWriter(BytesIO(sign_crypt_rc4_files[file]))
    w.encrypt(password)
    out = signers.sign_pdf(
        w,
        signers.PdfSignatureMetadata(field_name='SigNew'),
        signer=FROM_CA,
    )
    out.seek(0)
    r = PdfFileReader(out)
    r.decrypt(password)

    s = r.embedded_signatures[0]
    val_trusted(s)
Example #8
0
def test_wrong_password(legacy):
    w = writer.PdfFileWriter()
    ref = w.add_object(generic.TextStringObject("Blah blah"))
    if legacy:
        sh = StandardSecurityHandler.build_from_pw_legacy(
            StandardSecuritySettingsRevision.RC4_OR_AES128,
            w._document_id[0].original_bytes,
            "ownersecret",
            "usersecret",
            keylen_bytes=16,
            use_aes128=True)
    else:
        sh = StandardSecurityHandler.build_from_pw("ownersecret", "usersecret")
    w.security_handler = sh
    w._encrypt = w.add_object(sh.as_pdf_object())
    out = BytesIO()
    w.write(out)
    r = PdfFileReader(out)
    with pytest.raises(misc.PdfReadError):
        r.get_object(ref.reference)
    assert r.decrypt("thispasswordiswrong") == AuthResult.FAILED
    assert r.security_handler._auth_failed
    assert r.security_handler.get_string_filter()._auth_failed
    with pytest.raises(misc.PdfReadError):
        r.get_object(ref.reference)
Example #9
0
def test_legacy_encryption(use_owner_pass, rev, keylen_bytes, use_aes):
    r = PdfFileReader(BytesIO(VECTOR_IMAGE_PDF))
    w = writer.PdfFileWriter()
    sh = StandardSecurityHandler.build_from_pw_legacy(
        rev,
        w._document_id[0].original_bytes,
        "ownersecret",
        "usersecret",
        keylen_bytes=keylen_bytes,
        use_aes128=use_aes,
        perms=-44)
    w.security_handler = sh
    w._encrypt = w.add_object(sh.as_pdf_object())
    new_page_tree = w.import_object(r.root.raw_get('/Pages'), )
    w.root['/Pages'] = new_page_tree
    out = BytesIO()
    w.write(out)
    r = PdfFileReader(out)
    result = r.decrypt("ownersecret" if use_owner_pass else "usersecret")
    if use_owner_pass:
        assert result.status == AuthStatus.OWNER
        assert result.permission_flags is None
    else:
        assert result.status == AuthStatus.USER
        assert result.permission_flags == -44
    page = r.root['/Pages']['/Kids'][0].get_object()
    assert r.trailer['/Encrypt']['/P'] == -44
    assert '/ExtGState' in page['/Resources']
    # just a piece of data I know occurs in the decoded content stream
    # of the (only) page in VECTOR_IMAGE_PDF
    assert b'0 1 0 rg /a0 gs' in page['/Contents'].data
Example #10
0
def validate_signatures(ctx, infile, executive_summary, pretty_print,
                        validation_context, trust, trust_replace, other_certs,
                        ltv_profile, force_revinfo, soft_revocation_check,
                        no_revocation_check, password, retroactive_revinfo):

    if no_revocation_check:
        soft_revocation_check = True

    if pretty_print and executive_summary:
        raise click.ClickException(
            "--pretty-print is incompatible with --executive-summary.")

    if ltv_profile is not None:
        ltv_profile = RevocationInfoValidationType(ltv_profile)

    vc_kwargs = _build_vc_kwargs(
        ctx,
        validation_context,
        trust,
        trust_replace,
        other_certs,
        retroactive_revinfo,
        allow_fetching=False if no_revocation_check else None)

    key_usage_settings = _get_key_usage_settings(ctx, validation_context)
    with pyhanko_exception_manager():
        r = PdfFileReader(infile)
        sh = r.security_handler
        if isinstance(sh, crypt.StandardSecurityHandler):
            if password is None:
                password = getpass.getpass(prompt='File password: '******'t match.")
        elif sh is not None:
            raise click.ClickException(
                "The CLI supports only password-based encryption when "
                "validating (for now)")

        for ix, embedded_sig in enumerate(r.embedded_regular_signatures):
            fingerprint: str = embedded_sig.signer_cert.sha256.hex()
            status_str = _signature_status(ltv_profile, force_revinfo,
                                           soft_revocation_check, pretty_print,
                                           vc_kwargs, key_usage_settings,
                                           executive_summary, embedded_sig)
            name = embedded_sig.field_name

            if pretty_print:
                header = f'Field {ix + 1}: {name}'
                line = '=' * len(header)
                print(line)
                print(header)
                print(line)
                print('\n\n' + status_str)
            else:
                print('%s:%s:%s' % (name, fingerprint, status_str))
Example #11
0
def test_empty_user_pass():
    r = PdfFileReader(BytesIO(MINIMAL_ONE_FIELD))
    w = writer.copy_into_new_writer(r)
    old_root_ref = w.root_ref
    w.encrypt('ownersecret', '')
    out = BytesIO()
    w.write(out)
    r = PdfFileReader(out)
    result = r.decrypt('')
    assert result.status == AuthStatus.USER
    assert r.root_ref == old_root_ref
    assert len(r.root['/AcroForm']['/Fields']) == 1
    assert len(r.root['/Pages']['/Kids']) == 1
Example #12
0
def test_copy_to_encrypted_file():
    r = PdfFileReader(BytesIO(MINIMAL_ONE_FIELD))
    w = writer.copy_into_new_writer(r)
    old_root_ref = w.root_ref
    w.encrypt("ownersecret", "usersecret")
    out = BytesIO()
    w.write(out)
    r = PdfFileReader(out)
    result = r.decrypt("ownersecret")
    assert result.status == AuthStatus.OWNER
    assert r.root_ref == old_root_ref
    assert len(r.root['/AcroForm']['/Fields']) == 1
    assert len(r.root['/Pages']['/Kids']) == 1
Example #13
0
def test_page_tree_import(stream_xrefs, with_objstreams, encrypt):
    r = PdfFileReader(BytesIO(VECTOR_IMAGE_PDF))
    w = writer.PdfFileWriter(stream_xrefs=stream_xrefs)
    if encrypt:
        w.encrypt("secret")
    if with_objstreams:
        objstream = w.prepare_object_stream()
    else:
        objstream = None
    new_page_tree = w.import_object(r.root.raw_get('/Pages'),
                                    obj_stream=objstream)
    if objstream is not None:
        w.add_object(objstream.as_pdf_object())
    w.root['/Pages'] = new_page_tree
    out = BytesIO()
    w.write(out)
    r = PdfFileReader(out)
    if encrypt:
        r.decrypt("secret")
    page = r.root['/Pages']['/Kids'][0].get_object()
    assert '/ExtGState' in page['/Resources']
    # just a piece of data I know occurs in the decoded content stream
    # of the (only) page in VECTOR_IMAGE_PDF
    assert b'0 1 0 rg /a0 gs' in page['/Contents'].data
Example #14
0
def test_wrapper_doc():
    w = embed.wrap_encrypted_payload(VECTOR_IMAGE_PDF, password='******')
    out = BytesIO()
    w.write(out)

    r = PdfFileReader(out)
    assert b'attached file' in r.root['/Pages']['/Kids'][0]['/Contents'].data

    assert r.root['/Collection']['/D'] == 'attachment.pdf'
    assert r.root['/Collection']['/View'] == '/H'
    ef_stm = r.root['/Names']['/EmbeddedFiles']['/Names'][1]['/EF'] \
        .raw_get('/F')

    result = r.decrypt('secret')
    assert result.status == AuthStatus.OWNER

    assert ef_stm.get_object()._has_crypt_filter
    assert ef_stm.get_object().data == VECTOR_IMAGE_PDF
Example #15
0
def decrypt_with_password(infile, outfile, password, force):
    with pyhanko_exception_manager():
        with open(infile, 'rb') as inf:
            r = PdfFileReader(inf)
            if r.security_handler is None:
                raise click.ClickException("File is not encrypted.")
            if not password:
                password = getpass.getpass(prompt='File password: '******'t match.")
            w = copy_into_new_writer(r)
            with open(outfile, 'wb') as outf:
                w.write(outf)
Example #16
0
def test_encrypt_efs():
    r = PdfFileReader(BytesIO(MINIMAL))
    w = writer.copy_into_new_writer(r)
    cf = crypt.StandardAESCryptFilter(keylen=32)
    cf.set_embedded_only()
    sh = crypt.StandardSecurityHandler.build_from_pw(
        'secret',
        crypt_filter_config=crypt.CryptFilterConfiguration(
            {crypt.STD_CF: cf},
            default_stream_filter=crypt.IDENTITY,
            default_string_filter=crypt.IDENTITY,
            default_file_filter=crypt.STD_CF),
        encrypt_metadata=False)
    w._assign_security_handler(sh)
    modified = datetime.now(tz=tzlocal.get_localzone())
    created = modified - timedelta(days=1)
    _embed_test(w,
                fname='vector-test.pdf',
                ufname='ใƒ†ใ‚นใƒˆ.pdf',
                data=VECTOR_IMAGE_PDF,
                created=created,
                modified=modified)

    out = BytesIO()
    w.write(out)

    r = PdfFileReader(out)
    # should be able to access this without authenticating
    assert b'Hello' in r.root['/Pages']['/Kids'][0]['/Contents'].data
    ef_stm = r.root['/Names']['/EmbeddedFiles']['/Names'][1]['/EF']\
        .raw_get('/F')

    result = r.decrypt('secret')
    assert result.status == AuthStatus.OWNER

    assert ef_stm.get_object()._has_crypt_filter
    assert ef_stm.get_object().data == VECTOR_IMAGE_PDF