Merge pull request #94 from jackctj117/wolfJSSE_Benchmark
JCE: Implements DES algorithm, results comparison table and provider version informationpull/96/head
commit
e717ef543c
|
@ -1,5 +1,4 @@
|
|||
import javax.crypto.Cipher;
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.GCMParameterSpec;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
|
@ -8,21 +7,40 @@ import java.security.Provider;
|
|||
import java.security.SecureRandom;
|
||||
import java.security.Security;
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
import java.util.Arrays;
|
||||
import java.util.*;
|
||||
|
||||
import com.wolfssl.provider.jce.WolfCryptProvider;
|
||||
import com.wolfssl.wolfcrypt.FeatureDetect;
|
||||
|
||||
public class CryptoBenchmark {
|
||||
/* Constants for benchmark configuration */
|
||||
private static final int WARMUP_ITERATIONS = 5;
|
||||
private static final int TEST_ITERATIONS = 5; /* Number of iterations */
|
||||
private static final int TEST_ITERATIONS = 5;
|
||||
private static final int DATA_SIZE = 1024 * 1024;
|
||||
private static final int AES_BLOCK_SIZE = 16;
|
||||
private static final int GCM_TAG_LENGTH = 128; /* GCM auth tag length in bits */
|
||||
private static final int AES_KEY_SIZE = 256;
|
||||
private static final int DES3_BLOCK_SIZE = 8;
|
||||
private static final int GCM_TAG_LENGTH = 128;
|
||||
|
||||
/* Static key buffer */
|
||||
private static final byte[] STATIC_KEY = new byte[] {
|
||||
/* Class to store benchmark results */
|
||||
private static class BenchmarkResult {
|
||||
/* Result fields */
|
||||
String provider;
|
||||
String operation;
|
||||
double throughput;
|
||||
|
||||
/* Constructor */
|
||||
BenchmarkResult(String provider, String operation, double throughput) {
|
||||
this.provider = provider;
|
||||
this.operation = operation;
|
||||
this.throughput = throughput;
|
||||
}
|
||||
}
|
||||
|
||||
/* List to store all benchmark results */
|
||||
private static final List<BenchmarkResult> results = new ArrayList<>();
|
||||
|
||||
/* Static AES key buffer */
|
||||
private static final byte[] STATIC_AES_KEY = new byte[] {
|
||||
(byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67,
|
||||
(byte)0x89, (byte)0xab, (byte)0xcd, (byte)0xef,
|
||||
(byte)0xfe, (byte)0xde, (byte)0xba, (byte)0x98,
|
||||
|
@ -33,25 +51,83 @@ public class CryptoBenchmark {
|
|||
(byte)0xf4, (byte)0xf5, (byte)0xf6, (byte)0xf7
|
||||
};
|
||||
|
||||
/* Static DESede (Triple DES) key buffer */
|
||||
private static final byte[] STATIC_DES3_KEY = new byte[] {
|
||||
(byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67,
|
||||
(byte)0x89, (byte)0xab, (byte)0xcd, (byte)0xef,
|
||||
(byte)0xfe, (byte)0xdc, (byte)0xba, (byte)0x98,
|
||||
(byte)0x76, (byte)0x54, (byte)0x32, (byte)0x10,
|
||||
(byte)0x89, (byte)0xab, (byte)0xcd, (byte)0xef,
|
||||
(byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67
|
||||
};
|
||||
|
||||
private static byte[] generateTestData(int size) {
|
||||
return new byte[size]; /* Creates array initialized with zeros */
|
||||
return new byte[size];
|
||||
}
|
||||
|
||||
private static void runBenchmark(String algorithm, String mode, String providerName) throws Exception {
|
||||
/* Key generation variables */
|
||||
private static void printProviderInfo(Provider provider) {
|
||||
System.out.printf("%s version: %.1f%n", provider.getName(), provider.getVersion());
|
||||
}
|
||||
|
||||
private static void printDeltaTable() {
|
||||
/* Variables for table generation */
|
||||
Map<String, Map<String, Double>> groupedResults;
|
||||
String operation;
|
||||
Map<String, Double> providerResults;
|
||||
double wolfSpeed;
|
||||
String provider;
|
||||
double otherSpeed;
|
||||
double deltaMiBs;
|
||||
double deltaPercent;
|
||||
|
||||
System.out.println("\nPerformance Delta (compared to wolfJCE)");
|
||||
System.out.println("-----------------------------------------------------------------------------");
|
||||
System.out.println("| Operation | Provider | Delta | Delta |");
|
||||
System.out.println("| | | (MiB/s) | (%) |");
|
||||
System.out.println("|------------------------------------------|----------|----------|----------|");
|
||||
|
||||
/* Group results by operation */
|
||||
groupedResults = new HashMap<>();
|
||||
for (BenchmarkResult result : results) {
|
||||
groupedResults
|
||||
.computeIfAbsent(result.operation, k -> new HashMap<>())
|
||||
.put(result.provider, result.throughput);
|
||||
}
|
||||
|
||||
/* Calculate and print deltas */
|
||||
for (Map.Entry<String, Map<String, Double>> entry : groupedResults.entrySet()) {
|
||||
operation = entry.getKey();
|
||||
providerResults = entry.getValue();
|
||||
wolfSpeed = providerResults.getOrDefault("wolfJCE", 0.0);
|
||||
|
||||
for (Map.Entry<String, Double> providerEntry : providerResults.entrySet()) {
|
||||
provider = providerEntry.getKey();
|
||||
if (!provider.equals("wolfJCE")) {
|
||||
otherSpeed = providerEntry.getValue();
|
||||
deltaMiBs = wolfSpeed - otherSpeed;
|
||||
deltaPercent = ((wolfSpeed / otherSpeed) - 1.0) * 100;
|
||||
|
||||
System.out.printf("| %-40s | %-8s | %+8.2f | %+8.1f |%n",
|
||||
operation,
|
||||
provider,
|
||||
deltaMiBs,
|
||||
deltaPercent);
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("-----------------------------------------------------------------------------");
|
||||
}
|
||||
|
||||
private static void runBenchmark(String algorithm, String mode, String padding,
|
||||
String providerName) throws Exception {
|
||||
SecretKey key;
|
||||
|
||||
/* IV/Nonce generation variables */
|
||||
byte[] ivBytes;
|
||||
/* Using specific type instead of Object */
|
||||
AlgorithmParameterSpec params;
|
||||
/* Test data variables */
|
||||
byte[] testData;
|
||||
byte[] encryptedData = null;
|
||||
double dataSizeMiB;
|
||||
|
||||
/* Cipher variables */
|
||||
Cipher cipher;
|
||||
String cipherName = algorithm + "/" + mode + "/" + padding;
|
||||
|
||||
/* Timing variables */
|
||||
long startTime;
|
||||
|
@ -63,13 +139,26 @@ public class CryptoBenchmark {
|
|||
double encryptTimeMS;
|
||||
double decryptTimeMS;
|
||||
|
||||
/* Use static pre-made key */
|
||||
key = new SecretKeySpec(STATIC_KEY, "AES");
|
||||
|
||||
/* Use appropriate key based on algorithm */
|
||||
if (algorithm.equals("AES")) {
|
||||
key = new SecretKeySpec(STATIC_AES_KEY, "AES");
|
||||
} else if (algorithm.equals("DESede")) {
|
||||
key = new SecretKeySpec(STATIC_DES3_KEY, "DESede");
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported algorithm: " + algorithm);
|
||||
}
|
||||
|
||||
/* Generate random IV */
|
||||
SecureRandom secureRandom = new SecureRandom();
|
||||
ivBytes = new byte[AES_BLOCK_SIZE];
|
||||
secureRandom.nextBytes(ivBytes);
|
||||
if (algorithm.equals("AES")){
|
||||
ivBytes = new byte[AES_BLOCK_SIZE];
|
||||
secureRandom.nextBytes(ivBytes);
|
||||
} else if (algorithm.equals("DESede")) {
|
||||
ivBytes = new byte[DES3_BLOCK_SIZE];
|
||||
secureRandom.nextBytes(ivBytes);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported algorithm: " + algorithm);
|
||||
}
|
||||
|
||||
if (mode.equals("GCM")) {
|
||||
params = new GCMParameterSpec(GCM_TAG_LENGTH, ivBytes);
|
||||
|
@ -77,15 +166,13 @@ public class CryptoBenchmark {
|
|||
params = new IvParameterSpec(ivBytes);
|
||||
}
|
||||
|
||||
/* Generate test data filled with zeros */
|
||||
testData = generateTestData(DATA_SIZE);
|
||||
|
||||
/* Initialize cipher with specific provider */
|
||||
cipher = Cipher.getInstance(algorithm, providerName);
|
||||
cipher = Cipher.getInstance(cipherName, providerName);
|
||||
|
||||
/* Warm up phase */
|
||||
for (int i = 0; i < WARMUP_ITERATIONS; i++) {
|
||||
/* Generate fresh IV for each warmup iteration when using GCM */
|
||||
if (mode.equals("GCM")) {
|
||||
secureRandom.nextBytes(ivBytes);
|
||||
params = new GCMParameterSpec(GCM_TAG_LENGTH, ivBytes);
|
||||
|
@ -93,7 +180,6 @@ public class CryptoBenchmark {
|
|||
cipher.init(Cipher.ENCRYPT_MODE, key, params);
|
||||
encryptedData = cipher.doFinal(testData);
|
||||
|
||||
/* Use the same params for decryption since we're decrypting what we just encrypted */
|
||||
cipher.init(Cipher.DECRYPT_MODE, key, params);
|
||||
cipher.doFinal(encryptedData);
|
||||
}
|
||||
|
@ -101,7 +187,6 @@ public class CryptoBenchmark {
|
|||
/* Benchmark encryption */
|
||||
startTime = System.nanoTime();
|
||||
for (int i = 0; i < TEST_ITERATIONS; i++) {
|
||||
/* Generate fresh IV for each iteration when using GCM */
|
||||
if (mode.equals("GCM")) {
|
||||
secureRandom.nextBytes(ivBytes);
|
||||
params = new GCMParameterSpec(GCM_TAG_LENGTH, ivBytes);
|
||||
|
@ -112,40 +197,33 @@ public class CryptoBenchmark {
|
|||
endTime = System.nanoTime();
|
||||
encryptTime = (endTime - startTime) / TEST_ITERATIONS;
|
||||
|
||||
/* Calculate data size in MiB */
|
||||
dataSizeMiB = (DATA_SIZE * TEST_ITERATIONS) / (1024.0 * 1024.0);
|
||||
|
||||
/* Calculate time in milliseconds */
|
||||
encryptTimeMS = encryptTime / 1000000.0;
|
||||
|
||||
/* Calculate throughput using seconds for MiB/s */
|
||||
encryptThroughput = (DATA_SIZE / (encryptTime / 1000000000.0)) / (1024.0 * 1024.0);
|
||||
|
||||
/* Store encryption results */
|
||||
String testName = String.format("AES-256-%s (%s)", mode, providerName);
|
||||
String testName = String.format("%s (%s)", cipherName, providerName);
|
||||
System.out.printf("| %-40s | %8.3f | %8.3f | %8.3f |%n",
|
||||
testName + " enc", dataSizeMiB, encryptTimeMS, encryptThroughput);
|
||||
|
||||
/* Benchmark decryption using the encrypted data from encryption benchmark */
|
||||
results.add(new BenchmarkResult(providerName, cipherName + " enc", encryptThroughput));
|
||||
|
||||
/* Benchmark decryption */
|
||||
startTime = System.nanoTime();
|
||||
for (int i = 0; i < TEST_ITERATIONS; i++) {
|
||||
/* Note: For decryption, we use the last IV/params from encryption
|
||||
since we're decrypting the last encrypted data */
|
||||
cipher.init(Cipher.DECRYPT_MODE, key, params);
|
||||
cipher.doFinal(encryptedData);
|
||||
}
|
||||
endTime = System.nanoTime();
|
||||
decryptTime = (endTime - startTime) / TEST_ITERATIONS;
|
||||
|
||||
/* Calculate time in milliseconds */
|
||||
decryptTimeMS = decryptTime / 1000000.0;
|
||||
|
||||
/* Calculate throughput using seconds for MiB/s */
|
||||
decryptThroughput = (DATA_SIZE / (decryptTime / 1000000000.0)) / (1024.0 * 1024.0);
|
||||
|
||||
/* Store decryption results */
|
||||
System.out.printf("| %-40s | %8.3f | %8.3f | %8.3f |%n",
|
||||
testName + " dec", dataSizeMiB, decryptTimeMS, decryptThroughput);
|
||||
|
||||
/* Store decryption result */
|
||||
results.add(new BenchmarkResult(providerName, cipherName + " dec", decryptThroughput));
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
@ -158,36 +236,37 @@ public class CryptoBenchmark {
|
|||
bcProvider = (Provider) bcClass.getDeclaredConstructor().newInstance();
|
||||
hasBouncyCastle = true;
|
||||
} catch (Exception e) {
|
||||
// Bouncy Castle not available
|
||||
/* Bouncy Castle not available */
|
||||
}
|
||||
|
||||
/* Create provider list based on availability */
|
||||
java.util.List<Provider> providerList = new java.util.ArrayList<>();
|
||||
java.util.List<String> providerNameList = new java.util.ArrayList<>();
|
||||
|
||||
/* Always add wolfJCE first */
|
||||
providerList.add(new WolfCryptProvider());
|
||||
providerNameList.add("wolfJCE");
|
||||
|
||||
/* Always add SunJCE second */
|
||||
providerList.add(new com.sun.crypto.provider.SunJCE());
|
||||
providerNameList.add("SunJCE");
|
||||
|
||||
/* Add Bouncy Castle if available */
|
||||
if (hasBouncyCastle && bcProvider != null) {
|
||||
providerList.add(bcProvider);
|
||||
providerNameList.add("BC");
|
||||
}
|
||||
|
||||
|
||||
Provider[] providers = providerList.toArray(new Provider[0]);
|
||||
String[] providerNames = providerNameList.toArray(new String[0]);
|
||||
|
||||
/* Print provider versions */
|
||||
for (Provider provider : providers) {
|
||||
printProviderInfo(provider);
|
||||
}
|
||||
|
||||
System.out.println("-----------------------------------------------------------------------------");
|
||||
System.out.println(" JCE Crypto Provider Benchmark");
|
||||
System.out.println("-----------------------------------------------------------------------------");
|
||||
|
||||
/* Print table header */
|
||||
System.out.println("| Operation | Size MiB | ms | MiB/s |");
|
||||
System.out.println("| Operation | Size MiB | ms | MiB/s |");
|
||||
System.out.println("|------------------------------------------|----------|----------|----------|");
|
||||
|
||||
/* Test each provider */
|
||||
|
@ -195,20 +274,25 @@ public class CryptoBenchmark {
|
|||
Security.insertProviderAt(providers[i], 1);
|
||||
|
||||
/* Run benchmarks for different algorithms */
|
||||
runBenchmark("AES/CBC/PKCS5Padding", "CBC", providerNames[i]);
|
||||
runBenchmark("AES/GCM/NoPadding", "GCM", providerNames[i]);
|
||||
runBenchmark("AES", "CBC", "NoPadding", providerNames[i]);
|
||||
runBenchmark("AES", "CBC", "PKCS5Padding", providerNames[i]);
|
||||
runBenchmark("AES", "GCM", "NoPadding", providerNames[i]);
|
||||
/* Only run DES3 benchmark if it's enabled */
|
||||
if (FeatureDetect.Des3Enabled()) {
|
||||
runBenchmark("DESede", "CBC", "NoPadding", providerNames[i]);
|
||||
}
|
||||
|
||||
/* Add separator between providers */
|
||||
if (i < providers.length - 1) {
|
||||
System.out.println("|------------------------------------------|----------|----------|----------|");
|
||||
}
|
||||
|
||||
/* Reset provider after each test */
|
||||
Security.removeProvider(providers[i].getName());
|
||||
}
|
||||
|
||||
System.out.println("-----------------------------------------------------------------------------");
|
||||
|
||||
printDeltaTable();
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println("Benchmark failed: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
|
|
|
@ -80,10 +80,10 @@ fi
|
|||
# Run the benchmark
|
||||
java -classpath $CLASSPATH -Dsun.boot.library.path=../../../lib/ CryptoBenchmark $@
|
||||
|
||||
# After benchmark completion, ask about cleanup if we downloaded the files
|
||||
if [ "$BC_DOWNLOADED" = true ]; then
|
||||
# Always prompt for cleanup after benchmark completion if Bouncy Castle files exist
|
||||
if [ -f "../../../lib/bcprov-jdk18on-1.79.jar" ] && [ -f "../../../lib/bctls-jdk18on-1.79.jar" ]; then
|
||||
echo
|
||||
read -p "Would you like to remove the downloaded Bouncy Castle JARs? (y/n) " -n 1 -r
|
||||
read -p "Would you like to remove the Bouncy Castle JARs? (y/n) " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
cleanup_bc_jars
|
||||
|
|
Loading…
Reference in New Issue