package scripts.bench; import br.com.cybercore.signer.core.domain.ManagedCertificate; import br.com.cybercore.signer.core.pdf.PdfSealPosition; import br.com.cybercore.signer.core.pdf.PdfSignatureOptions; import br.com.cybercore.signer.core.pdf.PdfSigningService; import br.com.cybercore.signer.core.provider.CertificateManager; import br.com.cybercore.signer.core.provider.Pkcs12CertificateProvider; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.font.PDType1Font; import org.apache.pdfbox.pdmodel.font.Standard14Fonts; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x509.BasicConstraints; import org.bouncycastle.asn1.x509.Extension; import org.bouncycastle.asn1.x509.KeyUsage; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.X509v3CertificateBuilder; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; import org.bouncycastle.operator.ContentSigner; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.math.BigInteger; import java.nio.file.Files; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.KeyStore; import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Date; import java.util.List; /** * Utilitário de benchmark para medição de latência de certificados e assinatura PAdES (100KB, 5MB e 50MB). */ public class BenchmarkRunner { private static final String TARGET_DIR = "target/bench-data"; public static void main(String[] args) throws Exception { System.out.println("==============================================================="); System.out.println(" CyberCore Signer — Benchmark de Desempenho (Certificados & PAdES)"); System.out.println("==============================================================="); File dir = new File(TARGET_DIR); if (!dir.exists()) { dir.mkdirs(); } // 1. Prepara Certificado A1 de Teste System.out.print("[1/3] Inicializando provedor e certificado A1 de teste... "); long tCertGenStart = System.currentTimeMillis(); CertificateManager certManager = new CertificateManager(); Pkcs12CertificateProvider a1Provider = new Pkcs12CertificateProvider(); KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); kpg.initialize(2048); KeyPair keyPair = kpg.generateKeyPair(); X500Name name = new X500Name("CN=BENCHMARK TESTE:12345678900, O=ICP-Brasil Teste, C=BR"); Date notBefore = Date.from(Instant.now().minus(1, ChronoUnit.DAYS)); Date notAfter = Date.from(Instant.now().plus(30, ChronoUnit.DAYS)); X509v3CertificateBuilder builder = new X509v3CertificateBuilder( name, BigInteger.ONE, notBefore, notAfter, name, SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded()) ); builder.addExtension(Extension.basicConstraints, true, new BasicConstraints(false)); builder.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.nonRepudiation)); ContentSigner signer = new JcaContentSignerBuilder("SHA256withRSA").build(keyPair.getPrivate()); X509CertificateHolder holder = builder.build(signer); X509Certificate cert = new JcaX509CertificateConverter().getCertificate(holder); KeyStore ks = KeyStore.getInstance("PKCS12"); ks.load(null, null); ks.setKeyEntry("bench-alias", keyPair.getPrivate(), "1234".toCharArray(), new Certificate[]{cert}); ByteArrayOutputStream baosKs = new ByteArrayOutputStream(); ks.store(baosKs, "1234".toCharArray()); a1Provider.loadFromBytes(baosKs.toByteArray(), "1234".toCharArray()); certManager.registerProvider(a1Provider); System.out.println("OK (" + (System.currentTimeMillis() - tCertGenStart) + " ms)"); // 2. Mede Tempo de Enumeração de Certificados System.out.print("[2/3] Medindo tempo de enumeração de certificados (discoverCertificates)... "); long tDiscStart = System.nanoTime(); List certs = certManager.discoverCertificates(); long tDiscEnd = System.nanoTime(); double discMs = (tDiscEnd - tDiscStart) / 1_000_000.0; System.out.printf("OK (%.2f ms | %d certificado(s) listado(s))\n", discMs, certs.size()); String certId = certs.get(0).id(); // 3. Prepara arquivos PDF de 100 KB, 5 MB e 50 MB System.out.println("[3/3] Preparando e assinando documentos PDF com PAdES e selo visual..."); File pdf100Kb = preparePdf(new File(dir, "doc_100kb.pdf"), 100 * 1024); File pdf5Mb = preparePdf(new File(dir, "doc_5mb.pdf"), 5 * 1024 * 1024); File pdf50Mb = preparePdf(new File(dir, "doc_50mb.pdf"), 50 * 1024 * 1024); PdfSigningService pdfService = new PdfSigningService(certManager); PdfSignatureOptions options = PdfSignatureOptions.builder(certId) .position(PdfSealPosition.BOTTOM_RIGHT) .visibleSeal(true) .reason("Homologacao de Performance") .location("Brasilia, DF") .pinOrPassword("1234".toCharArray()) .build(); // Warmup JIT (PDF pequeno) pdfService.signPdf(Files.readAllBytes(pdf100Kb.toPath()), options); // Medição 100 KB long t100Start = System.nanoTime(); byte[] signed100 = pdfService.signPdf(Files.readAllBytes(pdf100Kb.toPath()), options); long t100End = System.nanoTime(); double ms100 = (t100End - t100Start) / 1_000_000.0; // Medição 5 MB long t5mStart = System.nanoTime(); byte[] signed5m = pdfService.signPdf(Files.readAllBytes(pdf5Mb.toPath()), options); long t5mEnd = System.nanoTime(); double ms5m = (t5mEnd - t5mStart) / 1_000_000.0; // Medição 50 MB long t50mStart = System.nanoTime(); byte[] signed50m = pdfService.signPdf(Files.readAllBytes(pdf50Mb.toPath()), options); long t50mEnd = System.nanoTime(); double ms50m = (t50mEnd - t50mStart) / 1_000_000.0; System.out.println(); System.out.println("==================== RESULTADOS DE LATÊNCIA PAdES ===================="); System.out.printf(" - Enumeração de Certificados: %.2f ms\n", discMs); System.out.printf(" - Assinatura PAdES 100 KB: %.2f ms (saída: %d KB)\n", ms100, signed100.length / 1024); System.out.printf(" - Assinatura PAdES 5 MB: %.2f ms (saída: %.2f MB)\n", ms5m, signed5m.length / (1024.0 * 1024.0)); System.out.printf(" - Assinatura PAdES 50 MB: %.2f ms (saída: %.2f MB)\n", ms50m, signed50m.length / (1024.0 * 1024.0)); System.out.println("======================================================================="); } private static File preparePdf(File file, int targetSizeBytes) throws Exception { if (file.exists() && file.length() >= targetSizeBytes * 0.95) { return file; } System.out.printf(" -> Gerando %s (~%d KB)... ", file.getName(), targetSizeBytes / 1024); try (PDDocument doc = new PDDocument()) { PDPage page = new PDPage(); doc.addPage(page); try (PDPageContentStream cs = new PDPageContentStream(doc, page)) { cs.beginText(); cs.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD), 14); cs.newLineAtOffset(50, 750); cs.showText("CyberCore Signer — Documento de Benchmark de Performance"); cs.endText(); } // Para arquivos de 5MB e 50MB, adiciona páginas e streams para atingir a meta de tamanho int approxPageSize = 2500; int pagesNeeded = Math.max(1, targetSizeBytes / approxPageSize); for (int p = 1; p < pagesNeeded && p < 1200; p++) { PDPage extraPage = new PDPage(); doc.addPage(extraPage); try (PDPageContentStream cs = new PDPageContentStream(doc, extraPage)) { cs.beginText(); cs.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA), 10); cs.newLineAtOffset(50, 700); cs.showText("Pagina de teste de volume " + p + " com metadados para teste PAdES."); cs.endText(); } } // Grava documento try (FileOutputStream fos = new FileOutputStream(file)) { doc.save(fos); } } // Se ainda não atingiu o tamanho exato desejado (especialmente para 50MB), preenche comentários PDF (% padding) long currentLen = file.length(); if (currentLen < targetSizeBytes) { try (FileOutputStream fos = new FileOutputStream(file, true)) { byte[] chunk = new byte[64 * 1024]; java.util.Arrays.fill(chunk, (byte) 'A'); chunk[0] = '%'; chunk[chunk.length - 1] = '\n'; while (file.length() < targetSizeBytes) { long remaining = targetSizeBytes - file.length(); int toWrite = (int) Math.min(chunk.length, remaining); fos.write(chunk, 0, toWrite); } } } System.out.printf("OK (%d KB)\n", file.length() / 1024); return file; } }