package org.ovirt.engine.benchmarks; import static java.nio.file.attribute.PosixFilePermissions.asFileAttribute; import static java.nio.file.attribute.PosixFilePermissions.fromString; import java.io.IOException; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.security.GeneralSecurityException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.TearDown; import org.openjdk.jmh.annotations.Warmup; import org.openjdk.jmh.infra.Blackhole; import org.ovirt.engine.core.utils.EngineLocalConfig; import org.ovirt.engine.core.utils.crypt.EngineEncryptionUtils; /** * <p> Benchmark's ovirt engine's encryption utility {@link EngineEncryptionUtils}.</p> * <p> There is a separate benchmarks per functionality - one for <b>encrypt</b> and one for <b>decrypt</b>. * <p> The methods are as close as they can to a real invocation, meaning no extra objects,<br/> * aside for {@link Blackhole}, or loops or preparations in the block, just the method invocation.<br/> * The benchmarks is avoiding loops on purpose, to not get optimized by the jvm in any way.<br/> * The result should be a good index for the the actual runtime performance of a code block.</p> * * @see EngineEncryptionUtils */ @BenchmarkMode(Mode.All) @Warmup(iterations = 2) @Measurement(iterations = 5) @OutputTimeUnit(TimeUnit.MILLISECONDS) public class EncryptionDecryptionBenchmark { @Benchmark public void encryption(BenchmarkState state, Blackhole blackhole) throws Exception { blackhole.consume(EngineEncryptionUtils.encrypt(state.password)); } @Benchmark public void decryption(BenchmarkState state, Blackhole blackhole) throws Exception { blackhole.consume(EngineEncryptionUtils.decrypt(state.encryptedPassword)); } @State(Scope.Benchmark) public static class BenchmarkState { private String password = "%A2A&wQX8xdx1hTg"; private String encryptedPassword; private Path tmpKey; @Setup public void setup() throws IOException, GeneralSecurityException { Map<String, String> config = new HashMap<>(); URL systemResource = ClassLoader.getSystemResource("key.p12"); tmpKey = Files.createTempFile("benchmarktmp", "", asFileAttribute(fromString("rw-------"))); Files.copy(systemResource.openStream(), tmpKey, StandardCopyOption.REPLACE_EXISTING); config.put("ENGINE_PKI_TRUST_STORE", tmpKey.toString()); config.put("ENGINE_PKI_TRUST_STORE_TYPE", "JKS"); config.put("ENGINE_PKI_TRUST_STORE_PASSWORD", "NoSoup4U"); config.put("ENGINE_PKI_ENGINE_STORE", tmpKey.toString()); config.put("ENGINE_PKI_ENGINE_STORE_TYPE", "PKCS12"); config.put("ENGINE_PKI_ENGINE_STORE_PASSWORD", "NoSoup4U"); config.put("ENGINE_PKI_ENGINE_STORE_ALIAS", "1"); EngineLocalConfig.getInstance(config); // paranoia check encryptedPassword = EngineEncryptionUtils.encrypt(password); if (!password.equals(EngineEncryptionUtils.decrypt(encryptedPassword))) { throw new IllegalStateException("This benchmark is illegal because " + " encrypt/decrypt yields a string which is different than the source"); } } @TearDown public void teardown() throws IOException { Files.delete(tmpKey); EngineLocalConfig.clearInstance(); } } }