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
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
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
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)
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)
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)
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
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))
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
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
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
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
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)
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