Java 使用iText锁定pdf
我最近尝试迁移到iText7,但我有一些问题。我已经有一个PDF,我正在尝试锁定和限制对此PDF的权限。我对itext5使用了相同的方法,但结果不一样。更准确地说:Java 使用iText锁定pdf,java,pdf,itext7,Java,Pdf,Itext7,我最近尝试迁移到iText7,但我有一些问题。我已经有一个PDF,我正在尝试锁定和限制对此PDF的权限。我对itext5使用了相同的方法,但结果不一样。更准确地说: 我曾经 PdfWriter writer = new PdfWriter(fos, new WriterProperties() .setPublicKeyEncryption(chain, new int[EncryptionConstants.ALLOW_DEGRADED_PRINTING],
PdfWriter writer = new PdfWriter(fos, new WriterProperties()
.setPublicKeyEncryption(chain,
new int[EncryptionConstants.ALLOW_DEGRADED_PRINTING],
EncryptionConstants.ENCRYPTION_AES_256));
public void signPDF(InputStream inputStream, HttpServletResponse response) {
LOG.debug("Inside signPDF...");
Security.addProvider(new BouncyCastleProvider());
try(OutputStream os = response.getOutputStream();
PdfReader reader = new PdfReader(inputStream);
PdfWriter writer = new PdfWriter(os, new WriterProperties().setStandardEncryption(null, "test".getBytes(), EncryptionConstants.ALLOW_PRINTING,
EncryptionConstants.ENCRYPTION_AES_128 | EncryptionConstants.DO_NOT_ENCRYPT_METADATA))) {
KeyStore ks = KeyStore.getInstance("pkcs12");
ks.load(new FileInputStream(p12Path), keystorePassword.toCharArray());
String alias = ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, keystorePassword.toCharArray());
Certificate[] chain = ks.getCertificateChain(alias);
BouncyCastleProvider provider = new BouncyCastleProvider();
ITSAClient tsc = new TSAClientBouncyCastle(tsaClient, "", "");
PdfSigner signer = new PdfSigner(reader, writer.getOutputStream(), true);
PdfSignatureAppearance appearance = signer.getSignatureAppearance()
.setReason("Sign")
.setLocation("Test")
.setReuseAppearance(false);
signer.setFieldName("sig");
IExternalSignature pks = new PrivateKeySignature(pk, DigestAlgorithms.SHA256, provider.getName());
IExternalDigest digest = new BouncyCastleDigest();
System.out.println(signer.getDocument().getNumberOfPages());
addWatermark(appearance,signer);
signer.signDetached(digest, pks, chain, null, null, tsc, 0, PdfSigner.CryptoStandard.CMS);
} catch (Exception e) {
LOG.error("Error while writing to outputstream",e);
}
}
现在它已签名,有水印,但未锁定(即复制内容)iText 7中的签名和加密目前分两步完成,第一步对文件进行加密,第二步对加密文件进行签名,保持加密完整 在您的尝试中,您创建了带有加密信息的
PdfWriter
,以及带有签名信息的PdfSigner
。由于任何pdf文档都没有使用您的PdfWriter
,因此加密信息会丢失,只会进行签名
要同时加密和签名,只需先加密PDF,例如使用
void sign(InputStream original, OutputStream result, String name, CryptoStandard subfilter,
int certificationLevel, boolean isAppendMode, byte[] password) throws IOException, GeneralSecurityException {
String reason = "Just another illusionary reason";
String location = "Right around the corner";
boolean setReuseAppearance = false;
String digestAlgorithm = "SHA512";
ITSAClient tsc = null;
PdfReader reader = new PdfReader(original, new ReaderProperties().setPassword(password));
PdfSigner signer = new PdfSigner(reader, result, isAppendMode);
signer.setCertificationLevel(certificationLevel);
// Creating the appearance
signer.getSignatureAppearance()
.setReason(reason)
.setLocation(location)
.setReuseAppearance(setReuseAppearance);
signer.setFieldName(name);
// Creating the signature
IExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
signer.signDetached(new BouncyCastleDigest(), pks, chain, null, null, tsc, 0, subfilter);
}
void encrypt(InputStream源、OutputStream目标、字节[]密码)引发IOException{
PdfReader reader=新PdfReader(源);
PdfWriter writer=新PdfWriter(目标,新WriterProperties()。设置标准加密(null,密码,
EncryptionConstants.ALLOW_PRINTING,EncryptionConstants.ENCRYPTION_AES_128 | EncryptionConstants.DO_NOT_ENCRYPT_METADATA));
新PDF文档(读写器).close();
}
(一种方法)
然后在加密的PDF上签名,例如使用
void sign(InputStream original, OutputStream result, String name, CryptoStandard subfilter,
int certificationLevel, boolean isAppendMode, byte[] password) throws IOException, GeneralSecurityException {
String reason = "Just another illusionary reason";
String location = "Right around the corner";
boolean setReuseAppearance = false;
String digestAlgorithm = "SHA512";
ITSAClient tsc = null;
PdfReader reader = new PdfReader(original, new ReaderProperties().setPassword(password));
PdfSigner signer = new PdfSigner(reader, result, isAppendMode);
signer.setCertificationLevel(certificationLevel);
// Creating the appearance
signer.getSignatureAppearance()
.setReason(reason)
.setLocation(location)
.setReuseAppearance(setReuseAppearance);
signer.setFieldName(name);
// Creating the signature
IExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
signer.signDetached(new BouncyCastleDigest(), pks, chain, null, null, tsc, 0, subfilter);
}
(一种方法)
与代码中的pk
和chain
类似
然后将这些方法结合起来,例如
try ( InputStream resourceStream = ...;
OutputStream encryptedResult = new FileOutputStream(encryptedFile) ) {
encrypt(resourceStream, encryptedResult, password);
}
try ( InputStream encryptedSource = new FileInputStream(encryptedFile);
OutputStream signedResult = new FileOutputStream(signedFile)) {
sign(encryptedSource, signedResult, "Signature", CryptoStandard.CADES, 0, false, password);
}
(测试测试加密和签名lefterisbab
)
或者,如果要写入响应而不希望文件系统中存在中间文件,请执行以下操作:
byte[] encrypted = null;
try ( InputStream resourceStream = ...;
OutputStream encryptedResult = new ByteArrayOutputStream() ) {
encrypt(resourceStream, encryptedResult, password);
encrypted = encryptedResult.toByteArray();
}
try ( InputStream encryptedSource = new ByteArrayInputStream(encrypted);
OutputStream signedResult = response.getOutputStream() ) {
sign(encryptedSource, signedResult, "Signature", CryptoStandard.CADES, 0, false, password);
}
iText 7中的签名和加密目前分为两个单独的步骤,第一步对文件进行加密,第二步对加密文件进行签名,保持加密完整
在您的尝试中,您创建了带有加密信息的PdfWriter
,以及带有签名信息的PdfSigner
。由于任何pdf文档都没有使用您的PdfWriter
,因此加密信息会丢失,只会进行签名
要同时加密和签名,只需先加密PDF,例如使用
void sign(InputStream original, OutputStream result, String name, CryptoStandard subfilter,
int certificationLevel, boolean isAppendMode, byte[] password) throws IOException, GeneralSecurityException {
String reason = "Just another illusionary reason";
String location = "Right around the corner";
boolean setReuseAppearance = false;
String digestAlgorithm = "SHA512";
ITSAClient tsc = null;
PdfReader reader = new PdfReader(original, new ReaderProperties().setPassword(password));
PdfSigner signer = new PdfSigner(reader, result, isAppendMode);
signer.setCertificationLevel(certificationLevel);
// Creating the appearance
signer.getSignatureAppearance()
.setReason(reason)
.setLocation(location)
.setReuseAppearance(setReuseAppearance);
signer.setFieldName(name);
// Creating the signature
IExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
signer.signDetached(new BouncyCastleDigest(), pks, chain, null, null, tsc, 0, subfilter);
}
void encrypt(InputStream源、OutputStream目标、字节[]密码)引发IOException{
PdfReader reader=新PdfReader(源);
PdfWriter writer=新PdfWriter(目标,新WriterProperties()。设置标准加密(null,密码,
EncryptionConstants.ALLOW_PRINTING,EncryptionConstants.ENCRYPTION_AES_128 | EncryptionConstants.DO_NOT_ENCRYPT_METADATA));
新PDF文档(读写器).close();
}
(一种方法)
然后在加密的PDF上签名,例如使用
void sign(InputStream original, OutputStream result, String name, CryptoStandard subfilter,
int certificationLevel, boolean isAppendMode, byte[] password) throws IOException, GeneralSecurityException {
String reason = "Just another illusionary reason";
String location = "Right around the corner";
boolean setReuseAppearance = false;
String digestAlgorithm = "SHA512";
ITSAClient tsc = null;
PdfReader reader = new PdfReader(original, new ReaderProperties().setPassword(password));
PdfSigner signer = new PdfSigner(reader, result, isAppendMode);
signer.setCertificationLevel(certificationLevel);
// Creating the appearance
signer.getSignatureAppearance()
.setReason(reason)
.setLocation(location)
.setReuseAppearance(setReuseAppearance);
signer.setFieldName(name);
// Creating the signature
IExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
signer.signDetached(new BouncyCastleDigest(), pks, chain, null, null, tsc, 0, subfilter);
}
(一种方法)
与代码中的pk
和chain
类似
然后将这些方法结合起来,例如
try ( InputStream resourceStream = ...;
OutputStream encryptedResult = new FileOutputStream(encryptedFile) ) {
encrypt(resourceStream, encryptedResult, password);
}
try ( InputStream encryptedSource = new FileInputStream(encryptedFile);
OutputStream signedResult = new FileOutputStream(signedFile)) {
sign(encryptedSource, signedResult, "Signature", CryptoStandard.CADES, 0, false, password);
}
(测试测试加密和签名lefterisbab
)
或者,如果要写入响应而不希望文件系统中存在中间文件,请执行以下操作:
byte[] encrypted = null;
try ( InputStream resourceStream = ...;
OutputStream encryptedResult = new ByteArrayOutputStream() ) {
encrypt(resourceStream, encryptedResult, password);
encrypted = encryptedResult.toByteArray();
}
try ( InputStream encryptedSource = new ByteArrayInputStream(encrypted);
OutputStream signedResult = response.getOutputStream() ) {
sign(encryptedSource, signedResult, "Signature", CryptoStandard.CADES, 0, false, password);
}
请向我们展示代码的完整版本。您使用的编写器创建逻辑是正确的,并且应该生成密码加密的文档。啊,因此您希望同时进行签名和加密,而您将这两个任务组合在一起的方式是错误的,您的带有加密信息的PdfWriter
根本不被使用。稍后我将尝试更正代码。谢谢@mkl,我为5.x版编写了代码,现在我将其更改为7.x版,我发现这有点棘手。请注意,PdfEncryptor.encrypt()关闭了流…请向我们展示代码的完整版本。您使用的编写器创建逻辑是正确的,并且应该生成密码加密的文档。啊,因此您希望同时进行签名和加密,而您将这两个任务组合在一起的方式是错误的,您的带有加密信息的PdfWriter
根本不被使用。稍后我将尝试更正代码。谢谢@mkl,我为5.x版编写了代码,现在我将其更改为7.x版,我发现这有点棘手。请注意,PdfEncryptor.encrypt()关闭了流。。。。