Рассчитайте хэш SHA-256 полного подготовленного PDF-файла и отправьте его в Swisscom. < /p>
[*]. SignatureObject.cms Из Swisscom я снова открыл подготовленный PDF, снова проверил хэш и попытался внедрить подпись, используя SignDeferred.import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.*;
import com.itextpdf.layout.Canvas;
import com.itextpdf.layout.element.Image;
import com.itextpdf.signatures.*;
import java.io.*;
import java.security.MessageDigest;
import java.util.*;
public class PrepareHash {
public static void main(String[] args) {
if (args.length < 3) {
System.err.println("Usage: java PrepareHash ...");
return;
}
String inputPDF = args[0];
String outputPDF = args[1];
String[] signatureImagePaths = Arrays.copyOfRange(args, 2, args.length);
try {
// Step 1: Add signature images
System.out.println("Opening PDF for signature images: " + inputPDF);
PdfDocument pdfDoc = new PdfDocument(new PdfReader(inputPDF), new PdfWriter(outputPDF));
System.out.println("PDF opened successfully. Ready to add signature images.");
for (int i = 0; i < signatureImagePaths.length; i++) {
String imagePath = signatureImagePaths;
int pageNumber = i + 1;
ImageData imageData = ImageDataFactory.create(imagePath);
Image image = new Image(imageData);
Rectangle pageSize = pdfDoc.getPage(pageNumber).getPageSize();
image.setFixedPosition(pageNumber, 0, 0);
image.setWidth(pageSize.getWidth());
image.setHeight(pageSize.getHeight());
new Canvas(pdfDoc.getPage(pageNumber), pageSize).add(image);
System.out.println("Signature image added to page " + pageNumber + ": " + imagePath);
}
pdfDoc.close();
System.out.println("Visualized PDF saved to: " + outputPDF);
// Step 2: Generate hash from signed byte ranges
System.out.println("
PdfReader reader = new PdfReader(outputPDF);
ByteArrayOutputStream dummyOut = new ByteArrayOutputStream();
PdfSigner signer = new PdfSigner(reader, dummyOut, new StampingProperties().useAppendMode());
signer.setFieldName("Signature1");
signer.getSignatureAppearance()
.setReason("Visual signature only for hash calculation")
.setLocation("DS | SIGN")
.setReuseAppearance(false);
// Log signature field name and appearance properties
System.out.println("Signature field set to: " + signer.getFieldName());
System.out.println("Signature appearance reason: " + signer.getSignatureAppearance().getReason());
// Create the dummy signature container for the hash calculation
IExternalSignatureContainer dummySigContainer = new IExternalSignatureContainer() {
public byte[] sign(InputStream is) {
try {
// Calculate the SHA-256 hash from the input stream (signed byte ranges)
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] buffer = new byte[8192];
int n;
while ((n = is.read(buffer)) != -1) {
digest.update(buffer, 0, n);
}
byte[] hash = digest.digest();
String base64 = Base64.getEncoder().encodeToString(hash);
// Log the generated hash
System.out.println("SHA-256 hash generated (Base64): " + base64);
} catch (Exception e) {
// Log any exception that occurs during hash calculation
System.err.println("Error while calculating hash: " + e.getMessage());
e.printStackTrace();
}
return new byte[0]; // Not signing here
}
public void modifySigningDictionary(PdfDictionary signDic) {
signDic.put(PdfName.Filter, PdfName.Adobe_PPKLite);
signDic.put(PdfName.SubFilter, PdfName.Adbe_pkcs7_detached);
signDic.put(PdfName.M, new PdfString(new PdfDate().toString()));
signDic.put(PdfName.Reason, new PdfString("Hash generation"));
signDic.put(PdfName.Location, new PdfString("DS | SIGN"));
}
};
// Perform the signing operation (hash calculation in this case)
System.out.println("Starting the signing process (hash calculation)...");
signer.signExternalContainer(dummySigContainer, 8192 * 2);
System.out.println("Signing process completed successfully.");
} catch (Exception e) {
// Log any exception that occurs during the process
System.err.println("Error occurred: " + e.getMessage());
e.printStackTrace();
}
}
}
< /code>
import com.itextpdf.forms.PdfAcroForm;
import com.itextpdf.forms.fields.PdfFormField;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.Security;
import java.util.Base64;
import com.itextpdf.kernel.pdf.*;
import com.itextpdf.signatures.*;
import com.itextpdf.kernel.geom.Rectangle;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class SignQES {
public static void main(String[] args) {
if (args.length < 6) {
System.err.println("Usage: java SignQES ");
System.exit(1);
}
String inputPdf = args[0];
String outputPdf = args[1];
String signatureCmsPath = args[2];
String reason = args[3];
String expectedHash = args[5];
try {
// Add the BouncyCastleProvider for cryptographic operations
Security.addProvider(new BouncyCastleProvider());
// Read the CMS signature
byte[] signatureBytes = Files.readAllBytes(Paths.get(signatureCmsPath));
// Create PdfReader for the input PDF
PdfReader reader = new PdfReader(inputPdf);
PdfWriter writer = new PdfWriter(outputPdf);
// Create PdfSigner for signing using PdfReader and PdfWriter
PdfSigner signer = new PdfSigner(reader, writer, new StampingProperties().useAppendMode());
// Set signature appearance
PdfSignatureAppearance appearance = signer.getSignatureAppearance();
appearance.setReason(reason);
appearance.setLocation("DS | SIGN");
// Define the position and size of the signature field
Rectangle rect = new Rectangle(36, 748, 200, 100); // Coordinates: x, y, width, height
// Create the signature field
PdfFormField signatureField = PdfFormField.createSignature(signer.getDocument());
// Get the first page from the PdfDocument
PdfPage page = signer.getDocument().getPage(1); // Getting the first page
// Log signature field and appearance properties
System.out.println("Signature field set to: Signature1");
System.out.println("Signature appearance reason: " + appearance.getReason());
// Create the dummy signature container for the hash calculation
IExternalSignatureContainer dummySigContainer = new IExternalSignatureContainer() {
public byte[] sign(InputStream is) {
try {
// Calculate the SHA-256 hash from the input stream
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] buffer = new byte[8192];
int n;
while ((n = is.read(buffer)) != -1) {
digest.update(buffer, 0, n);
}
byte[] hash = digest.digest();
String base64 = Base64.getEncoder().encodeToString(hash);
// Log the generated hash
System.out.println("SHA-256 hash generated (Base64): " + base64);
// Compare the hashes
if (!base64.equals(expectedHash)) {
throw new RuntimeException("Hash mismatch! Expected: " + expectedHash + ", Got: " + base64);
}
} catch (Exception e) {
// Log any exception that occurs during hash calculation
System.err.println("Error while calculating hash: " + e.getMessage());
e.printStackTrace();
}
return new byte[0]; // Not signing here
}
public void modifySigningDictionary(PdfDictionary signDic) {
signDic.put(PdfName.Filter, PdfName.Adobe_PPKLite);
signDic.put(PdfName.SubFilter, PdfName.Adbe_pkcs7_detached);
signDic.put(PdfName.M, new PdfString(new PdfDate().toString()));
signDic.put(PdfName.Reason, new PdfString("Hash generation"));
signDic.put(PdfName.Location, new PdfString("DS | SIGN"));
}
};
// Perform the signing operation (hash calculation in this case)
signer.signExternalContainer(dummySigContainer, 8192 * 2);
System.out.println("Signing process completed successfully.");
} catch (Exception e) {
// Log any exception that occurs during the process
System.err.println("Error occurred: " + e.getMessage());
e.printStackTrace();
System.exit(2);
}
}
}
< /code>
update2.0:
Я пробовал: < /p>
Проверенный useappendmode () устанавливается во время подготовки и подписи. < /p>
Закрыт документ после SignexternalContainer (...) (signer.getdocument (). Тот же output_prepared.pdf для хэширования и подписи. < /p>
Пробое было вычислять хэш из файлового файла подготовленного файла, а также из байтовой версии файла. Оба места (Java и PHP). < /p>
обеспечивают визуальные сигнатуры (изображения, логотипы) добавляются перед хэшированием, а не после. Контейнер).
Не могли бы вы уточнить, как правильно идентифицировать и исключить подпись заполнителя из хэш -расчета? В частности, как мы гарантируем, что только контент, который на самом деле будет подписан, включен в хэш? Расчет
В подходе Signdeferred () подпись добавляется позже, и документ должен быть подготовлен в первую очередь. Поскольку мы хэшируем только контент, который будет подписан, как мы правильно обрабатываем процесс в ITEXT 7, чтобы генерировать хэш только для подписанных байтовых диапазонов?
Не могли бы вы объяснить, как мы должны управлять подготовкой PDF, прежде чем вызовать Signdeferred (), чтобы гарантировать, что хэш -расчет является правильным и не включает в себя подпись заполнителя или любой Unmodified Content? /> Влияние визуальной подписи и внешнего вида подписи на хэш
Во время процесса подписания QE изображения визуальной подписи добавляются в PDF. Поскольку вы упомянули, что они не должны влиять на хэш, не могли бы вы прояснить, как правильно обрабатывать изображения визуальной сигнатуры в процессе signdeferred () без их межоборудования с хэш -вычислением?
Правильно ли предполагать, что изображения визуальной сигнатуры добавляются после того, как хэш вычисляется и не должно быть частью подписанного контента, используемого для процесса хешина? /> Зависимости: < /p>
itext 7.2.5 < /p>
< /li>
bouncycastle 1.70 < /p>
< /li>
swisscom qes api api (ets -формат)
Подробнее здесь: https://stackoverflow.com/questions/795 ... smatch-exp