package quickfix;
import static edu.umd.cs.findbugs.plugin.eclipse.quickfix.util.ASTUtil.addImports;
import static edu.umd.cs.findbugs.plugin.eclipse.quickfix.util.ASTUtil.getASTNode;
import java.util.Map;
import javax.annotation.Nonnull;
import edu.umd.cs.findbugs.BugInstance;
import edu.umd.cs.findbugs.plugin.eclipse.quickfix.BugResolution;
import edu.umd.cs.findbugs.plugin.eclipse.quickfix.exception.BugResolutionException;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.SimpleType;
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
public class InsecureRandomResolution extends BugResolution {
public static final String GENERATE_SEED_DESC = "Initializing the seed like <br/><code>new Random(SecureRandom.getInstance().generateSeed())</code><br/>"
+ "creates a more secure starting point for the random number generation than the default.<br/><br/>"
+ "However, still using <code>java.lang.Random</code> makes this slightly less secure than using "
+ "<code>java.secure.SecureRandom</code>, but at the benefit of being faster. ";
public static final String SECURE_RENAME_DESC = "java.security.SecureRandom can be a drop-in replacement for Random, "
+ "however, calls to the object's methods (e.g. nextInt(), nextBytes()) "
+ "may be significantly slower.";
private static final String QUALIFIED_SECURE_RANDOM = "java.security.SecureRandom";
private static final String QUALIFIED_RANDOM = "java.util.Random";
private boolean useSecureRandomObject;
@Override
protected boolean resolveBindings() {
return true;
}
@Override
public void setOptions(@Nonnull Map<String, String> options) {
this.useSecureRandomObject = Boolean.parseBoolean(options.get("useSecureRandomObject"));
}
@Override
public String getDescription() {
if (useSecureRandomObject) {
return SECURE_RENAME_DESC;
}
return GENERATE_SEED_DESC;
}
@Override
protected void repairBug(ASTRewrite rewrite, CompilationUnit workingUnit, BugInstance bug) throws BugResolutionException {
ASTNode node = getASTNode(workingUnit, bug.getPrimarySourceLineAnnotation());
RandomVisitor visitor = new RandomVisitor();
node.accept(visitor);
AST ast = rewrite.getAST();
// Make a new Random ClassInstanceCreation or a SecureRandome one, depending on input
ClassInstanceCreation fixedClassInstanceCreation;
if (useSecureRandomObject) {
fixedClassInstanceCreation = makeSecureRandom(ast);
} else {
fixedClassInstanceCreation = makeRandomWithSeed(ast);
}
rewrite.replace(visitor.randomToFix, fixedClassInstanceCreation, null);
addImports(rewrite, workingUnit, QUALIFIED_SECURE_RANDOM);
}
private ClassInstanceCreation makeSecureRandom(AST ast) {
SimpleType secureRandomType = ast.newSimpleType(ast.newName("SecureRandom"));
ClassInstanceCreation newSecureRandom = ast.newClassInstanceCreation();
newSecureRandom.setType(secureRandomType);
return newSecureRandom;
}
@SuppressWarnings("unchecked")
private ClassInstanceCreation makeRandomWithSeed(AST ast) {
SimpleType randomType = ast.newSimpleType(ast.newName("Random"));
ClassInstanceCreation newRandom = ast.newClassInstanceCreation();
newRandom.setType(randomType);
ClassInstanceCreation newSecureRandom = makeSecureRandom(ast);
MethodInvocation getLong = ast.newMethodInvocation();
getLong.setExpression(newSecureRandom);
getLong.setName(ast.newSimpleName("nextLong"));
newRandom.arguments().add(getLong);
return newRandom;
}
private static class RandomVisitor extends ASTVisitor {
public ClassInstanceCreation randomToFix;
@Override
public boolean visit(ClassInstanceCreation node) {
if (QUALIFIED_RANDOM.equals(node.resolveTypeBinding().getQualifiedName())) {
this.randomToFix = node;
}
return true;
}
}
}