Skip to content

Commit

Permalink
move sanity check prog into logicsig def
Browse files Browse the repository at this point in the history
  • Loading branch information
ahangsu committed Aug 25, 2022
1 parent 7cae4f5 commit ecd5ec5
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 60 deletions.
59 changes: 57 additions & 2 deletions src/main/java/com/algorand/algosdk/crypto/LogicsigSignature.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import org.apache.commons.codec.binary.Base64;

/**
* Serializable logicsig class.
Expand All @@ -39,6 +40,60 @@ public class LogicsigSignature {
@JsonProperty("msig")
public MultisigSignature msig;


private static boolean isAsciiPrintable(final byte symbol) {
char symbolChar = (char) (symbol & 0xFF);
// linebreak existence check in program byte
boolean isBreakLine = symbolChar == '\n';
// printable ascii between range 32 (space) and 126 (tilde ~)
boolean isStdPrintable = symbolChar >= ' ' && symbolChar <= '~';
return isBreakLine || isStdPrintable;
}

private static boolean isAsciiPrintable(final byte[] program) {
for (byte b : program) {
if (!isAsciiPrintable(b))
return false;
}
return true;
}

/**
* Performs heuristic program validation:
* check if passed in bytes are Algorand address or is B64 encoded, rather than Teal bytes
* @param program
*/
private static void sanityCheckProgram(final byte[] program) {
if (program == null || program.length == 0)
throw new IllegalArgumentException("empty program");
// in any case, if a slice of "program-bytes" is full of ASCII printable,
// then the slice of bytes can't be Teal program bytes.
// need to check what possible kind of bytes are passed in.
if (isAsciiPrintable(program)) {
// maybe the bytes passed in are representing an Algorand address
boolean isAddress = false;
try {
new Address(new String(program));
isAddress = true;
} catch (NoSuchAlgorithmException | IllegalArgumentException e) {
// if exception is IllegalArgException, it means bytes are not Algorand address
if (e instanceof NoSuchAlgorithmException)
throw new IllegalArgumentException("cannot check if program bytes are Algorand address" + e);
}
if (isAddress)
throw new IllegalArgumentException("requesting program bytes, get Algorand address");

// or maybe these bytes are some B64 encoded bytes representation
if (Base64.isBase64(program))
throw new IllegalArgumentException("program should not be b64 encoded");

// can't further analyze, but it is more than just B64 encoding at this point
throw new IllegalArgumentException(
"program bytes are all ASCII printable characters, not looking like Teal byte code"
);
}
}

@JsonCreator
public LogicsigSignature(
@JsonProperty("l") byte[] logic,
Expand All @@ -49,7 +104,7 @@ public LogicsigSignature(
this.logic = Objects.requireNonNull(logic, "program must not be null");
this.args = args;

Logic.sanityCheckProgram(this.logic);
sanityCheckProgram(this.logic);

if (sig != null) this.sig = new Signature(sig);
this.msig = msig;
Expand Down Expand Up @@ -118,7 +173,7 @@ public boolean verify(Address singleSigner) throws NoSuchAlgorithmException {
return false;
}

Logic.sanityCheckProgram(this.logic);
sanityCheckProgram(this.logic);

PublicKey pk;
try {
Expand Down
60 changes: 4 additions & 56 deletions src/main/java/com/algorand/algosdk/logic/Logic.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,23 @@

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.algorand.algosdk.crypto.Address;
import org.apache.commons.codec.binary.Base64;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
* Logic class provides static checkProgram function
* that can be used for client-side program validation for size and execution cost.
*
* @deprecated this class is deprecated for relying on metadata (`langspec.json`) that
* does not accurately represent opcode behavior across program versions.
*/
@Deprecated
public class Logic {

@Deprecated
Expand Down Expand Up @@ -164,59 +165,6 @@ public static VarintResult getUVarint(byte [] buffer, int bufferOffset) {
return new VarintResult();
}

private static boolean isAsciiPrintable(final byte symbol) {
char symbolChar = (char) (symbol & 0xFF);
// linebreak existence check in program byte
boolean isBreakLine = symbolChar == '\n';
// printable ascii between range 32 (space) and 126 (tilde ~)
boolean isStdPrintable = symbolChar >= ' ' && symbolChar <= '~';
return isBreakLine || isStdPrintable;
}

private static boolean isAsciiPrintable(final byte[] program) {
for (byte b : program) {
if (!isAsciiPrintable(b))
return false;
}
return true;
}

/**
* Performs heuristic program validation:
* check if passed in bytes are Algorand address or is B64 encoded, rather than Teal bytes
* @param program
*/
public static void sanityCheckProgram(final byte[] program) {
if (program == null || program.length == 0)
throw new IllegalArgumentException("empty program");
// in any case, if a slice of "program-bytes" is full of ASCII printable,
// then the slice of bytes can't be Teal program bytes.
// need to check what possible kind of bytes are passed in.
if (isAsciiPrintable(program)) {
// maybe the bytes passed in are representing an Algorand address
boolean isAddress = false;
try {
new Address(new String(program));
isAddress = true;
} catch (NoSuchAlgorithmException | IllegalArgumentException e) {
// if exception is IllegalArgException, it means bytes are not Algorand address
if (e instanceof NoSuchAlgorithmException)
throw new IllegalArgumentException("cannot check if program bytes are Algorand address" + e);
}
if (isAddress)
throw new IllegalArgumentException("requesting program bytes, get Algorand address");

// or maybe these bytes are some B64 encoded bytes representation
if (Base64.isBase64(program))
throw new IllegalArgumentException("program should not be b64 encoded");

// can't further analyze, but it is more than just B64 encoding at this point
throw new IllegalArgumentException(
"program bytes are all ASCII printable characters, not looking like Teal byte code"
);
}
}

@Deprecated
private static LangSpec langSpec;
@Deprecated
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.algorand.algosdk.unit;

import com.algorand.algosdk.logic.Logic;
import com.algorand.algosdk.crypto.LogicsigSignature;
import com.algorand.algosdk.util.Encoder;

import io.cucumber.java.en.Given;
Expand All @@ -21,7 +21,7 @@ public void takeB64encodedBytes(String b64encodedBytes) {
@When("I start heuristic sanity check over the bytes")
public void heuristicCheckOverBytes() {
try {
Logic.sanityCheckProgram(seeminglyProgram);
new LogicsigSignature(seeminglyProgram);
} catch (Exception e) {
actualErrMsg = e.getMessage();
}
Expand Down

0 comments on commit ecd5ec5

Please sign in to comment.