Files
cybercore-signer/scripts/bench/BenchmarkRunner.java
T

201 lines
9.6 KiB
Java

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<ManagedCertificate> 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;
}
}