Added EstimateIterationsResult to gather iteration estimate results

This commit is contained in:
Micah Silverman 2021-10-13 01:56:04 -04:00
parent 0bb95d535c
commit 10f10d0963
3 changed files with 53 additions and 3 deletions

View File

@ -0,0 +1,44 @@
package io.jsonwebtoken.security;
import java.util.ArrayList;
import java.util.List;
public class EstimateIterationsResult {
private int iterations;
private List<Integer> workFactors;
private List<Long> durations;
public EstimateIterationsResult() {
this.workFactors = new ArrayList<>();
this.durations = new ArrayList<>();
}
public EstimateIterationsResult(int numSamples) {
this.workFactors = new ArrayList<>(numSamples);
this.durations = new ArrayList<>(numSamples);
}
public int getIterations() {
return iterations;
}
public void setIterations(int iterations) {
this.iterations = iterations;
}
public List<Integer> getWorkFactors() {
return workFactors;
}
public void setWorkFactors(List<Integer> workFactors) {
this.workFactors = workFactors;
}
public List<Long> getDurations() {
return durations;
}
public void setDurations(List<Long> durations) {
this.durations = durations;
}
}

View File

@ -77,7 +77,7 @@ public final class KeyAlgorithms {
public static final RsaKeyAlgorithm RSA_OAEP = forId0("RSA-OAEP");
public static final RsaKeyAlgorithm RSA_OAEP_256 = forId0("RSA-OAEP-256");
public static int estimateIterations(KeyAlgorithm<PbeKey, SecretKey> alg, long desiredMillis) {
public static EstimateIterationsResult estimateIterations(KeyAlgorithm<PbeKey, SecretKey> alg, long desiredMillis) {
return Classes.invokeStatic(BRIDGE_CLASSNAME, "estimateIterations", ESTIMATE_ITERATIONS_ARG_TYPES, alg, desiredMillis);
}
}

View File

@ -10,6 +10,7 @@ import io.jsonwebtoken.lang.Collections;
import io.jsonwebtoken.security.AeadAlgorithm;
import io.jsonwebtoken.security.DecryptionKeyRequest;
import io.jsonwebtoken.security.EncryptionAlgorithms;
import io.jsonwebtoken.security.EstimateIterationsResult;
import io.jsonwebtoken.security.KeyAlgorithm;
import io.jsonwebtoken.security.KeyRequest;
import io.jsonwebtoken.security.KeyResult;
@ -135,7 +136,7 @@ public final class KeyAlgorithmsBridge {
return chars;
}
public static int estimateIterations(KeyAlgorithm<PbeKey, SecretKey> alg, long desiredMillis) {
public static EstimateIterationsResult estimateIterations(KeyAlgorithm<PbeKey, SecretKey> alg, long desiredMillis) {
// The number of computational samples that land in our 'sweet spot' timing range matching desiredMillis.
// These samples will be averaged and the final average will be the return value of this method
@ -155,6 +156,8 @@ public final class KeyAlgorithmsBridge {
alg = lean((Pbes2HsAkwAlgorithm) alg);
}
EstimateIterationsResult ret = new EstimateIterationsResult(NUM_SAMPLES);
int workFactor = 1000; // same as iterations for PBKDF2. Different concept for Bcrypt/Scrypt
int minWorkFactor = workFactor;
List<Point> points = new ArrayList<>(NUM_SAMPLES);
@ -185,6 +188,8 @@ public final class KeyAlgorithmsBridge {
if (collectSample) {
// For each attempt, the x axis is the workFactor, and the y axis is how long it took to compute:
points.add(new Point(workFactor, duration));
ret.getDurations().add(duration);
ret.getWorkFactors().add(workFactor);
//System.out.println("Collected point: workFactor=" + workFactor + ", duration=" + duration + " ms, %achieved=" + durationPercentAchieved);
} else {
minWorkFactor = Math.max(minWorkFactor, workFactor);
@ -227,7 +232,8 @@ public final class KeyAlgorithmsBridge {
}
double average = sumX / points.size();
//ensure our average is at least as much as the smallest work factor that got us closest to desiredMillis:
return (int) Math.max(average, minWorkFactor);
ret.setIterations((int) Math.max(average, minWorkFactor));
return ret;
}
private static class Point {