Skip to content

Commit

Permalink
Add transformation for BigInteger constructors
Browse files Browse the repository at this point in the history
  • Loading branch information
smeyer198 committed Feb 3, 2025
1 parent c3f6daa commit d427da0
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import boomerang.DefaultBoomerangOptions;
import boomerang.scene.AllocVal;
import boomerang.scene.DeclaredMethod;
import boomerang.scene.InvokeExpr;
import boomerang.scene.Method;
import boomerang.scene.Statement;
import boomerang.scene.Type;
Expand All @@ -23,6 +25,23 @@ public ExtendedBoomerangOptions(int timeout, SparseCFGCache.SparsificationStrate

@Override
public Optional<AllocVal> getAllocationVal(Method m, Statement stmt, Val fact) {
/* Constructors are not assignments; they are simple invoke statements. Therefore, we
* have to check if we have a corresponding transformation separately.
*/
if (Transformation.isTransformationExpression(stmt)) {
InvokeExpr invokeExpr = stmt.getInvokeExpr();
DeclaredMethod declaredMethod = invokeExpr.getMethod();

if (declaredMethod.isConstructor()) {
Val base = invokeExpr.getBase();

if (base.equals(fact)) {
AllocVal allocVal = new AllocVal(base, stmt, base);
return Optional.of(allocVal);
}
}
}

if (!stmt.isAssign()) {
return Optional.empty();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
import crypto.definition.Definitions;
import crypto.extractparameter.scope.IntVal;
import crypto.extractparameter.scope.LongVal;
import java.math.BigInteger;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

Expand All @@ -19,12 +21,21 @@ public class WrapperTransformation extends Transformation {

private static final Signature INTEGER_PARSE_INT =
new Signature("java.lang.Integer", "int", "parseInt", List.of("java.lang.String"));
private static final Signature BIG_INTEGER_CONSTRUCTOR_STRING =
new Signature("java.math.BigInteger", "void", "<init>", List.of("java.lang.String"));
private static final Signature BIG_INTEGER_CONSTRUCTOR_STRING_INT =
new Signature(
"java.math.BigInteger", "void", "<init>", List.of("java.lang.String", "int"));
private static final Signature BIG_INTEGER_VALUE_OF =
new Signature(
"java.math.BigInteger", "java.math.BigInteger", "valueOf", List.of("long"));

private static final Collection<Signature> WRAPPER_SIGNATURES =
Set.of(INTEGER_PARSE_INT, BIG_INTEGER_VALUE_OF);
Set.of(
INTEGER_PARSE_INT,
BIG_INTEGER_VALUE_OF,
BIG_INTEGER_CONSTRUCTOR_STRING,
BIG_INTEGER_CONSTRUCTOR_STRING_INT);

protected static boolean isWrapperTransformation(Signature signature) {
return WRAPPER_SIGNATURES.contains(signature);
Expand All @@ -40,6 +51,14 @@ protected Multimap<Val, Type> evaluateExpression(Statement statement, Signature
return evaluateIntegerParseInt(statement);
}

if (signature.equals(BIG_INTEGER_CONSTRUCTOR_STRING)) {
return evaluateBigIntegerConstructorString(statement);
}

if (signature.equals(BIG_INTEGER_CONSTRUCTOR_STRING_INT)) {
return evaluateBigIntegerConstructorStringInt(statement);
}

if (signature.equals(BIG_INTEGER_VALUE_OF)) {
return evaluateBigIntegerValueOf(statement);
}
Expand Down Expand Up @@ -75,6 +94,80 @@ private Multimap<Val, Type> evaluateIntegerParseInt(Statement statement) {
return result;
}

private Multimap<Val, Type> evaluateBigIntegerConstructorString(Statement statement) {
InvokeExpr invokeExpr = statement.getInvokeExpr();
Val param = invokeExpr.getArg(0);

Multimap<AllocVal, Type> allocSites = computeAllocSites(statement, param);
Multimap<Val, Type> extractedParams = extractAllocValues(allocSites);

Multimap<Val, Type> result = HashMultimap.create();
for (Val extractedParam : extractedParams.keySet()) {
if (!extractedParam.isStringConstant()) {
continue;
}

BigInteger bigInteger = new BigInteger(extractedParam.getStringValue());

// Using Integer.MAX_VALUE is sufficient to model large integers
int intValue;
try {
intValue = bigInteger.intValueExact();
} catch (ArithmeticException e) {
intValue = Integer.MAX_VALUE;
}

IntVal intVal = new IntVal(intValue, statement.getMethod());
Collection<Type> types = new HashSet<>();
types.add(intVal.getType());

result.putAll(intVal, types);
}

return result;
}

private Multimap<Val, Type> evaluateBigIntegerConstructorStringInt(Statement statement) {
InvokeExpr invokeExpr = statement.getInvokeExpr();
Val param1 = invokeExpr.getArg(0);
Val param2 = invokeExpr.getArg(1);

Multimap<AllocVal, Type> param1Sites = computeAllocSites(statement, param1);
Multimap<AllocVal, Type> param2Sites = computeAllocSites(statement, param2);

Multimap<Val, Type> extractedParams1 = extractAllocValues(param1Sites);
Multimap<Val, Type> extractedParams2 = extractAllocValues(param2Sites);

Multimap<Val, Type> result = HashMultimap.create();
for (Val extractedParam1 : extractedParams1.keySet()) {
for (Val extractedParam2 : extractedParams2.keySet()) {
if (!extractedParam1.isStringConstant() || !extractedParam2.isIntConstant()) {
continue;
}

BigInteger bigInteger =
new BigInteger(
extractedParam1.getStringValue(), extractedParam2.getIntValue());

// Using Integer.MAX_VALUE is sufficient to model large integers
int intValue;
try {
intValue = bigInteger.intValueExact();
} catch (ArithmeticException e) {
intValue = Integer.MAX_VALUE;
}

IntVal intVal = new IntVal(intValue, statement.getMethod());
Collection<Type> types = new HashSet<>();
types.add(intVal.getType());

result.putAll(intVal, types);
}
}

return result;
}

private Multimap<Val, Type> evaluateBigIntegerValueOf(Statement statement) {
InvokeExpr invokeExpr = statement.getInvokeExpr();
Val param = invokeExpr.getArg(0);
Expand Down
55 changes: 35 additions & 20 deletions CryptoAnalysis/src/test/java/tests/jca/BouncyCastleTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import org.bouncycastle.math.ec.ECConstants;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.util.encoders.Hex;
import org.junit.Ignore;
import org.junit.Test;
import test.TestConstants;
import test.UsagePatternTestingFramework;
Expand All @@ -34,14 +33,13 @@ protected String getRulesetPath() {
return TestConstants.BOUNCY_CASTLE_RULESET_PATH;
}

@Ignore("Currently cannot handle BigIntegers")
@Test
public void testEncryptTwo() throws InvalidCipherTextException {
String edgeInput = "ff6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e";
byte[] data = Hex.decode(edgeInput);

RSAKeyParameters pubParameters = new RSAKeyParameters(false, null, null);
Assertions.hasEnsuredPredicate(pubParameters);
Assertions.notHasEnsuredPredicate(pubParameters);

AsymmetricBlockCipher eng = new RSAEngine();
// missing init()
Expand All @@ -51,12 +49,11 @@ public void testEncryptTwo() throws InvalidCipherTextException {
Assertions.notHasEnsuredPredicate(cipherText);
}

@Ignore("Currently cannot handle BigIntegers")
@Test
public void rsaKeyParameters() {
BigInteger mod = new BigInteger("a0b8e8321b041acd40b7", 16);
BigInteger pub = new BigInteger("9f0783a49...da", 16);
BigInteger pri = new BigInteger("21231...cda7", 16);
BigInteger pub = new BigInteger("499602D2", 16); // 1234567890
BigInteger pri = new BigInteger("24CB016EA", 16); // 9876543210

RSAKeyParameters privateParameters = new RSAKeyParameters(true, mod, pri);
Assertions.mustBeInAcceptingState(privateParameters);
Expand All @@ -67,12 +64,11 @@ public void rsaKeyParameters() {
Assertions.hasEnsuredPredicate(publicParameters);
}

@Ignore("Currently cannot handle BigIntegers")
@Test
public void testORingTwoPredicates1() throws GeneralSecurityException {
BigInteger mod = new BigInteger("a0b8e8321b041acd40b7", 16);
BigInteger pub = new BigInteger("9f0783a49...da", 16);
BigInteger prv = new BigInteger("92e08f83...19", 16);
BigInteger pub = new BigInteger("499602D2", 16); // 1234567890
BigInteger prv = new BigInteger("24CB016EA", 16); // 9876543210

RSAKeyParameters params = new RSAKeyParameters(false, mod, pub);
Assertions.mustBeInAcceptingState(params);
Expand All @@ -88,9 +84,18 @@ public void testORingTwoPredicates1() throws GeneralSecurityException {

BigInteger p = new BigInteger(1024, randomGenerator);
BigInteger q = new BigInteger(1024, randomGenerator);
BigInteger pExp = new BigInteger("1d1a2d3ca8...b5", 16);
BigInteger qExp = new BigInteger("6c929e4e816...ed", 16);
BigInteger crtCoefficient = new BigInteger("dae7651ee...39", 16);
BigInteger pExp =
new BigInteger(
"1d1a2d3ca8e52068b3094d501c9a842fec37f54db16e9a67070a8b3f53cc03d4257ad252a1a640eadd603724d7bf3737914b544ae332eedf4f34436cac25ceb5",
16);
BigInteger qExp =
new BigInteger(
"6c929e4e81672fef49d9c825163fec97c4b7ba7acb26c0824638ac22605d7201c94625770984f78a56e6e25904fe7db407099cad9b14588841b94f5ab498dded",
16);
BigInteger crtCoefficient =
new BigInteger(
"dae7651ee69ad1d081ec5e7188ae126f6004ff39556bde90e0b870962fa7b926d070686d8244fe5a9aa709a95686a104614834b0ada4b10f53197a5cb4c97339",
16);

RSAPrivateCrtKeyParameters privateParam =
new RSAPrivateCrtKeyParameters(mod, pub, prv, p, q, pExp, qExp, crtCoefficient);
Expand Down Expand Up @@ -144,26 +149,37 @@ public void testORingTwoPredicates2() throws IllegalStateException, InvalidCiphe
Assertions.mustNotBeInAcceptingState(cipher2);
}

@Ignore("Currently cannot handle BigIntegers")
@Test
public void testORingThreePredicates1() throws GeneralSecurityException {
BigInteger mod = new BigInteger("a0b8e8321b041acd40b7", 16);
BigInteger pub = new BigInteger("9f0783a49...da", 16);
BigInteger pub = new BigInteger("499602D2", 16);
RSAKeyParameters params = new RSAKeyParameters(false, mod, pub);

ParametersWithRandom randomParam1 = new ParametersWithRandom(params);
Assertions.mustBeInAcceptingState(randomParam1);
Assertions.hasEnsuredPredicate(randomParam1);

BigInteger prv = new BigInteger("92e08f83...19", 16);
BigInteger prv =
new BigInteger(
"92e08f83cc9920746989ca5034dcb384a094fb9c5a6288fcc4304424ab8f56388f72652d8fafc65a4b9020896f2cde297080f2a540e7b7ce5af0b3446e1258d1dd7f245cf54124b4c6e17da21b90a0ebd22605e6f45c9f136d7a13eaac1c0f7487de8bd6d924972408ebb58af71e76fd7b012a8d0e165f3ae2e5077a8648e619",
16);
Random randomGenerator = SecureRandom.getInstance("SHA1PRNG");
Assertions.mustBeInAcceptingState(randomGenerator);
Assertions.hasEnsuredPredicate(randomGenerator);
BigInteger p = new BigInteger(1024, randomGenerator);
BigInteger q = new BigInteger(1024, randomGenerator);
BigInteger pExp = new BigInteger("1d1a2d3ca8...b5", 16);
BigInteger qExp = new BigInteger("6c929e4e816...ed", 16);
BigInteger crtCoefficient = new BigInteger("dae7651ee...39", 16);
BigInteger pExp =
new BigInteger(
"1d1a2d3ca8e52068b3094d501c9a842fec37f54db16e9a67070a8b3f53cc03d4257ad252a1a640eadd603724d7bf3737914b544ae332eedf4f34436cac25ceb5",
16);
BigInteger qExp =
new BigInteger(
"6c929e4e81672fef49d9c825163fec97c4b7ba7acb26c0824638ac22605d7201c94625770984f78a56e6e25904fe7db407099cad9b14588841b94f5ab498dded",
16);
BigInteger crtCoefficient =
new BigInteger(
"dae7651ee69ad1d081ec5e7188ae126f6004ff39556bde90e0b870962fa7b926d070686d8244fe5a9aa709a95686a104614834b0ada4b10f53197a5cb4c97339",
16);
RSAPrivateCrtKeyParameters privateParam =
new RSAPrivateCrtKeyParameters(mod, pub, prv, p, q, pExp, qExp, crtCoefficient);
Assertions.mustBeInAcceptingState(privateParam);
Expand Down Expand Up @@ -201,11 +217,10 @@ public void testORingThreePredicates1() throws GeneralSecurityException {
Assertions.hasEnsuredPredicate(randomParam3);
}

@Ignore("Currently cannot handle BigIntegers")
@Test
public void testORingThreePredicates2() {
BigInteger mod = new BigInteger("a0b8e8321b041acd40b7", 16);
BigInteger pub = new BigInteger("9f0783a49...da", 16);
BigInteger pub = new BigInteger("499602D2", 16);
RSAKeyParameters params = new RSAKeyParameters(false, mod, pub);
Assertions.mustBeInAcceptingState(params);
Assertions.hasEnsuredPredicate(params);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ public class WrapperConstraint {

public WrapperConstraint() {}

public void integerParseIntConstraint(int value) {}
public void integerParseIntConstraint(@SuppressWarnings("unused") int value) {}

public void bigIntegerValueOfConstraint(BigInteger value) {}
public void bigIntegerConstructor(@SuppressWarnings("unused") BigInteger value) {}

public void bigIntegerValueOfConstraint(@SuppressWarnings("unused") BigInteger value) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,40 @@ public void branchingIntegerParseIntTest() {
Assertions.constraintErrors(constraint, 1);
}

@Test
public void positiveBigIntegerConstructorTest() {
BigInteger correctValue1 = new BigInteger("999999");

WrapperConstraint constraint1 = new WrapperConstraint();
constraint1.bigIntegerConstructor(correctValue1);
Assertions.extValue(0);
Assertions.constraintErrors(constraint1, 0);

BigInteger correctValue2 = new BigInteger("F423F", 16); // 999.999

WrapperConstraint constraint2 = new WrapperConstraint();
constraint2.bigIntegerConstructor(correctValue2);
Assertions.extValue(0);
Assertions.constraintErrors(constraint2, 0);
}

@Test
public void negativeBigIntegerConstructorTest() {
BigInteger incorrectValue1 = new BigInteger("111111");

WrapperConstraint constraint1 = new WrapperConstraint();
constraint1.bigIntegerConstructor(incorrectValue1);
Assertions.extValue(0);
Assertions.constraintErrors(constraint1, 1);

BigInteger correctValue2 = new BigInteger("3640E", 16); // 222.222

WrapperConstraint constraint2 = new WrapperConstraint();
constraint2.bigIntegerConstructor(correctValue2);
Assertions.extValue(0);
Assertions.constraintErrors(constraint2, 1);
}

@Test
public void positiveBigIntegerValueOfTest() {
BigInteger correctValue = BigInteger.valueOf(100000);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ SPEC tests.misc.transformation.WrapperConstraint

OBJECTS
int intValue;
java.math.BigInteger bigInteger;
java.math.BigInteger bigIntegerConstructor;
java.math.BigInteger bigIntegerValueOf;

EVENTS
Con: WrapperConstraint();
IntParseInt: integerParseIntConstraint(intValue);
BigIntValueOf: bigIntegerValueOfConstraint(bigInteger);
BigIntCon: bigIntegerConstructor(bigIntegerConstructor);
BigIntValueOf: bigIntegerValueOfConstraint(bigIntegerValueOf);

CONSTRAINTS
intValue in {10};
bigInteger in {100000};
bigIntegerConstructor > 555555;
bigIntegerValueOf in {100000};
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,6 @@ public void testBCSignerExamples() {
addErrorSpecification(
new ErrorSpecification.Builder(
"gwt_crypto.ISO9796SignerTest", "doShortPartialTest", 0)
.withTPs(ImpreciseValueExtractionError.class, 1)
.withTPs(IncompleteOperationError.class, 1)
.build());
addErrorSpecification(
Expand All @@ -322,7 +321,6 @@ public void testBCSignerExamples() {
addErrorSpecification(
new ErrorSpecification.Builder(
"gwt_crypto.X931SignerTest", "shouldPassSignatureTestOne", 0)
.withTPs(ImpreciseValueExtractionError.class, 1)
.withTPs(IncompleteOperationError.class, 1)
.build());
addErrorSpecification(
Expand Down Expand Up @@ -416,11 +414,9 @@ public void testBCEllipticCurveExamples() {
addErrorSpecification(
new ErrorSpecification.Builder("params.ECPrivateKeyParametersTest", "testOne", 1)
.withTPs(RequiredPredicateError.class, 2)
.withTPs(ConstraintError.class, 1)
.build());
addErrorSpecification(
new ErrorSpecification.Builder("params.ECPrivateKeyParametersTest", "testTwo", 1)
.withTPs(ConstraintError.class, 1)
.build());
addErrorSpecification(
new ErrorSpecification.Builder("params.ParametersWithRandomTest", "testOne", 1)
Expand Down

0 comments on commit d427da0

Please sign in to comment.