Большое спасибо! :-)
тоящее время у меня есть клиент-серверное приложение, которое, учитывая файл PDF, подписывает его (с помощью сертификата сервера), прикрепляет подпись с исходным файлом и возвращает результат обратно клиенту (все это достигается с помощью PDFBox).
У меня есть обработчик подписи, который является моей внешней поддержкой подписи (где содержимое файла PDF)
public byte[] sign(InputStream content) throws IOException {
try {
System.out.println("Generating CMS signed data");
CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
ContentSigner sha1Signer = new JcaContentSignerBuilder("Sha1WithRSA").build(privateKey);
generator.addSignerInfoGenerator(
new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build())
.build(sha1Signer, new X509CertificateHolder(certificate.getEncoded())));
CMSTypedData cmsData = new CMSProcessableByteArray(IOUtils.toByteArray(content));
CMSSignedData signedData = generator.generate(cmsData, false);
return signedData.getEncoded();
} catch (GeneralSecurityException e) {
throw new IOException(e);
} catch (CMSException e) {
throw new IOException(e);
} catch (OperatorCreationException e) {
throw new IOException(e);
}
}
Он работает нормально, но я подумал - а что, если файл PDF слишком велик для загрузки? Пример: 100 МБ ... это заняло бы вечность! Учитывая это, я пытаюсь выяснить, можно ли вместо подписи файла PDF подписать хеш (ex SHA1) этого файла, и чем клиент все это в итоге объединит?
Обновить:
Я пытался понять это, и теперь мой метод подписания:
@Override
public byte[] sign(InputStream content) throws IOException {
// testSHA1WithRSAAndAttributeTable
try {
MessageDigest md = MessageDigest.getInstance("SHA1", "BC");
List<Certificate> certList = new ArrayList<Certificate>();
CMSTypedData msg = new CMSProcessableByteArray(IOUtils.toByteArray(content));
certList.add(certificate);
Store certs = new JcaCertStore(certList);
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
Attribute attr = new Attribute(CMSAttributes.messageDigest,
new DERSet(new DEROctetString(md.digest(IOUtils.toByteArray(content)))));
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(attr);
SignerInfoGeneratorBuilder builder = new SignerInfoGeneratorBuilder(new BcDigestCalculatorProvider())
.setSignedAttributeGenerator(new DefaultSignedAttributeTableGenerator(new AttributeTable(v)));
AlgorithmIdentifier sha1withRSA = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA1withRSA");
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
InputStream in = new ByteArrayInputStream(certificate.getEncoded());
X509Certificate cert = (X509Certificate) certFactory.generateCertificate(in);
gen.addSignerInfoGenerator(builder.build(
new BcRSAContentSignerBuilder(sha1withRSA,
new DefaultDigestAlgorithmIdentifierFinder().find(sha1withRSA))
.build(PrivateKeyFactory.createKey(privateKey.getEncoded())),
new JcaX509CertificateHolder(cert)));
gen.addCertificates(certs);
CMSSignedData s = gen.generate(new CMSAbsentContent(), false);
return new CMSSignedData(msg, s.getEncoded()).getEncoded();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new IOException(e);
}
}
И я объединяю подпись с PDF с pdfbox
ExternalSigningSupport externalSigning = document.saveIncrementalForExternalSigning(output);
byte[] cmsSignature = sign(externalSigning.getContent());
externalSigning.setSignature(cmsSignature);
Проблема в том, что Adobe говорит, что подпись недействительна, потому что «документ был изменен или поврежден с момента его подписания». Кто-нибудь может помочь?