diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..19c84b3
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,7 @@
+version: 2
+updates:
+ - package-ecosystem: "java:maven"
+ directory: "/"
+ target_branch: "develop"
+ schedule:
+ interval: "daily"
diff --git a/.github/workflows/develop.yml b/.github/workflows/develop.yml
new file mode 100644
index 0000000..0a9e3cd
--- /dev/null
+++ b/.github/workflows/develop.yml
@@ -0,0 +1,30 @@
+name: develop maven CI
+
+on:
+ push:
+ branches:
+ - develop
+ pull_request:
+ branches:
+ - develop
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up JDK 1.8
+ uses: actions/setup-java@v1
+ with:
+ java-version: 1.8
+ - name: Cache local Maven repository
+ uses: actions/cache@v2
+ with:
+ path: ~/.m2/repository
+ key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ ${{ runner.os }}-maven-
+ - name: Build with Maven
+ run: mvn -B package --file pom.xml
diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml
new file mode 100644
index 0000000..7552e72
--- /dev/null
+++ b/.github/workflows/master.yml
@@ -0,0 +1,30 @@
+name: master maven CI
+
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+ branches:
+ - master
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up JDK 1.8
+ uses: actions/setup-java@v1
+ with:
+ java-version: 1.8
+ - name: Cache local Maven repository
+ uses: actions/cache@v2
+ with:
+ path: ~/.m2/repository
+ key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ ${{ runner.os }}-maven-
+ - name: Build with Maven
+ run: mvn -B package --file pom.xml
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a330fed..450017f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,32 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [1.2.0] - 2020-06-28
+
+### Added
+
+* Add additional operations:
+ * *HTMLEncode* (Encode HTML special characters)
+ * *HTMLDecode* (Decode HTML special characters)
+ * *RsaEncrypt* (Encrypt data by using a public key)
+ * *RsaDecrypt* (Decrypt data using a private key)
+ * *RsaSignature* (Create an RSA signature)
+ * *NoOperation* (Does nothing :D)
+* Add *conditionals* operation class:
+ * *StringContains* (Skip if input contains a string)
+ * *StringMatch* (Skip if input matches a string)
+ * *RegexMatch* (Skip if input matches the specified regex)
+ * *NumberCompare* (Skip if comparison is true)
+* Add *Maven CI* for the master and development branch
+* Add *dependabot* config to prevent pushes to master
+
+### Changed
+
+* Byte operations now also allow multiple variables in one input field
+* *jackson-core* and *jackson-databind* updated to current version
+* Breakpoint operations now assign variables
+
+
## [1.1.1] - 2020-05-20
### Changed
diff --git a/README.md b/README.md
index 6236c0e..979042a 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,4 @@
+
*Copyright 2017-2020 usd AG*
Licensed under the *GNU General Public License, Version 3.0* (the "License"). You may not use this tool except in compliance with the License.
@@ -5,6 +6,9 @@ You may obtain a copy of the License at https://www.gnu.org/licenses/gpl-3.0.htm

+
+
+
# Cyber Security Transformation Chef
*The Cyber Security Transformation Chef* (*CSTC*) is a *Burp Suite* extension. It is build for security experts to
diff --git a/example/example-server.py b/example/example-server.py
index b9fe54a..8fddf5a 100644
--- a/example/example-server.py
+++ b/example/example-server.py
@@ -40,7 +40,7 @@ def do_POST(self):
self.wfile.write(b"
Processing Input: '" + result + b"'...
")
-def run(server_class=HTTPServer, handler_class=S, port=8080):
+def run(server_class=HTTPServer, handler_class=S, port=8000):
logging.basicConfig(level=logging.INFO)
server_address = ('', port)
httpd = server_class(server_address, handler_class)
diff --git a/pom.xml b/pom.xml
index b5cd080..1eba8d1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,7 +2,7 @@
4.0.0
de.usd.CSTC
CSTC
- 1.1.1
+ 1.2.0
CSTC
CSTC
@@ -71,13 +71,18 @@
com.fasterxml.jackson.core
jackson-core
- 2.9.9
+ 2.11.1
com.fasterxml.jackson.core
jackson-databind
- 2.9.10.4
+ 2.11.1
+
+ org.apache.commons
+ commons-text
+ 1.8
+
diff --git a/src/de/usd/cstchef/Utils.java b/src/de/usd/cstchef/Utils.java
index c6116f0..065cbd5 100644
--- a/src/de/usd/cstchef/Utils.java
+++ b/src/de/usd/cstchef/Utils.java
@@ -14,6 +14,8 @@
import java.util.zip.ZipInputStream;
import burp.BurpUtils;
+import burp.IBurpExtenderCallbacks;
+import burp.IExtensionHelpers;
import burp.Logger;
import de.usd.cstchef.operations.Operation;
import de.usd.cstchef.operations.arithmetic.Addition;
@@ -33,8 +35,14 @@
import de.usd.cstchef.operations.compression.GUnzip;
import de.usd.cstchef.operations.compression.Gzip;
import de.usd.cstchef.operations.compression.Inflate;
+import de.usd.cstchef.operations.conditional.NumberCompare;
+import de.usd.cstchef.operations.conditional.RegexMatch;
+import de.usd.cstchef.operations.conditional.StringContains;
+import de.usd.cstchef.operations.conditional.StringMatch;
import de.usd.cstchef.operations.dataformat.FromBase64;
import de.usd.cstchef.operations.dataformat.FromHex;
+import de.usd.cstchef.operations.dataformat.HtmlDecode;
+import de.usd.cstchef.operations.dataformat.HtmlEncode;
import de.usd.cstchef.operations.dataformat.ToBase64;
import de.usd.cstchef.operations.dataformat.ToHex;
import de.usd.cstchef.operations.dataformat.UrlDecode;
@@ -45,6 +53,8 @@
import de.usd.cstchef.operations.encryption.AesEncryption;
import de.usd.cstchef.operations.encryption.DesDecryption;
import de.usd.cstchef.operations.encryption.DesEncryption;
+import de.usd.cstchef.operations.encryption.RsaDecryption;
+import de.usd.cstchef.operations.encryption.RsaEncryption;
import de.usd.cstchef.operations.extractors.HttpBodyExtractor;
import de.usd.cstchef.operations.extractors.HttpCookieExtractor;
import de.usd.cstchef.operations.extractors.HttpGetExtractor;
@@ -84,6 +94,7 @@
import de.usd.cstchef.operations.setter.HttpXmlSetter;
import de.usd.cstchef.operations.setter.JsonSetter;
import de.usd.cstchef.operations.setter.LineSetter;
+import de.usd.cstchef.operations.signature.RsaSignature;
import de.usd.cstchef.operations.signature.XmlFullSignature;
import de.usd.cstchef.operations.signature.XmlMultiSignature;
import de.usd.cstchef.operations.string.Length;
@@ -94,6 +105,7 @@
import de.usd.cstchef.operations.string.Substring;
import de.usd.cstchef.operations.string.Suffix;
import de.usd.cstchef.operations.utils.GetVariable;
+import de.usd.cstchef.operations.utils.NoOperation;
import de.usd.cstchef.operations.utils.RandomNumber;
import de.usd.cstchef.operations.utils.SetIfEmpty;
import de.usd.cstchef.operations.utils.StoreVariable;
@@ -133,18 +145,36 @@ public static String replaceVariables(String text) {
public static byte[] replaceVariablesByte(byte[] bytes) {
HashMap variables = VariableStore.getInstance().getVariables();
+ IBurpExtenderCallbacks callbacks = BurpUtils.getInstance().getCallbacks();
+ IExtensionHelpers helpers = callbacks.getHelpers();
+
byte[] currentKey;
for (Entry entry : variables.entrySet()) {
+ int offset = 0;
currentKey = ("$" + entry.getKey()).getBytes();
- if( Arrays.equals(currentKey, bytes) ) {
- bytes = entry.getValue();
- }
+ while( offset >= 0 ) {
+ offset = helpers.indexOf(bytes, currentKey, true, offset, bytes.length);
+ if( offset >= 0 )
+ bytes = insertAtOffset(bytes, offset, offset + currentKey.length, entry.getValue());
+ }
}
return bytes;
}
+ public static byte[] insertAtOffset(byte[] input, int start, int end, byte[] newValue) {
+ byte[] prefix = Arrays.copyOfRange(input, 0, start);
+ byte[] rest = Arrays.copyOfRange(input, end, input.length);
+
+ byte[] output = new byte[prefix.length + newValue.length + rest.length];
+ System.arraycopy(prefix, 0, output, 0, prefix.length);
+ System.arraycopy(newValue, 0, output, prefix.length, newValue.length);
+ System.arraycopy(rest, 0, output, prefix.length + newValue.length, rest.length);
+
+ return output;
+ }
+
public static Class extends Operation>[] getOperationsBurp() {
ZipInputStream zip = null;
List> operations = new ArrayList>();
@@ -191,18 +221,24 @@ public static Class extends Operation>[] getOperationsDev() {
Blake.class, DateTime.class, Deflate.class, DesDecryption.class, DesEncryption.class,
Divide.class, DivideList.class, DSTU7564.class, FromBase64.class, FromHex.class,
GetVariable.class, Gost.class, GUnzip.class, Gzip.class, Hmac.class,
- HttpBodyExtractor.class, HttpCookieExtractor.class, HttpGetExtractor.class, HttpGetSetter.class, HttpHeaderExtractor.class,
- HttpHeaderSetter.class, HttpJsonExtractor.class, HttpJsonSetter.class, HttpMethodExtractor.class, HttpPostExtractor.class,
- HttpPostSetter.class, HTTPRequest.class, HttpSetBody.class, HttpSetCookie.class, HttpSetUri.class,
- HttpUriExtractor.class, HttpXmlExtractor.class, HttpXmlSetter.class, Inflate.class, JsonExtractor.class,
- JsonSetter.class, Length.class, LineExtractor.class, LineSetter.class, MD2.class, MD4.class, MD5.class,
- Mean.class, Median.class, Multiply.class, MultiplyList.class, Prefix.class, RandomNumber.class,
- ReadFile.class, RegexExtractor.class, Replace.class, RIPEMD.class, SetIfEmpty.class, SHA1.class,
- SHA2.class, SHA3.class, Skein.class, SplitAndSelect.class, StaticString.class, StoreVariable.class,
- Sub.class, Substring.class, Subtraction.class, Suffix.class, Sum.class,
- Tiger.class, ToBase64.class, ToHex.class, UnixTimestamp.class, UrlDecode.class,
- UrlEncode.class, Whirlpool.class, WriteFile.class, XmlFullSignature.class, XmlMultiSignature.class,
- Xor.class };
+ HttpBodyExtractor.class, HttpCookieExtractor.class, HttpGetExtractor.class,
+ HttpGetSetter.class, HttpHeaderExtractor.class, HttpHeaderSetter.class,
+ HttpJsonExtractor.class, HttpJsonSetter.class, HttpMethodExtractor.class,
+ HttpPostExtractor.class, HttpPostSetter.class, HTTPRequest.class, HttpSetBody.class,
+ HttpSetCookie.class, HttpSetUri.class, HttpUriExtractor.class, HttpXmlExtractor.class,
+ HttpXmlSetter.class, HtmlEncode.class, HtmlDecode.class, Inflate.class,
+ JsonExtractor.class, JsonSetter.class, Length.class, LineExtractor.class,
+ LineSetter.class, MD2.class, MD4.class, MD5.class, Mean.class, Median.class,
+ Multiply.class, MultiplyList.class, NoOperation.class, NumberCompare.class, Prefix.class,
+ RandomNumber.class, ReadFile.class, RegexExtractor.class, Replace.class, RIPEMD.class,
+ RsaDecryption.class, RsaEncryption.class, RsaSignature.class, RegexMatch.class,
+ SetIfEmpty.class, SHA1.class, SHA2.class, SHA3.class, Skein.class, SplitAndSelect.class,
+ StaticString.class, StoreVariable.class, Sub.class, Substring.class, Subtraction.class,
+ Suffix.class, Sum.class, StringContains.class, StringMatch.class, Tiger.class,
+ ToBase64.class, ToHex.class, UnixTimestamp.class, UrlDecode.class, UrlEncode.class,
+ Whirlpool.class, WriteFile.class, XmlFullSignature.class, XmlMultiSignature.class,
+ Xor.class
+ };
}
public static Class extends Operation>[] getOperations() {
diff --git a/src/de/usd/cstchef/operations/Operation.java b/src/de/usd/cstchef/operations/Operation.java
index 1cec608..861bf56 100644
--- a/src/de/usd/cstchef/operations/Operation.java
+++ b/src/de/usd/cstchef/operations/Operation.java
@@ -70,6 +70,9 @@ public abstract class Operation extends JPanel {
private Box contentBox;
private Map uiElements;
+ private int operationSkip = 0;
+ private int laneSkip = 0;
+
public Operation() {
super();
this.uiElements = new HashMap<>();
@@ -190,7 +193,9 @@ private Object getUiValues(Component comp) {
} else if (comp instanceof JSpinner) {
result = ((JSpinner) comp).getValue();
} else if (comp instanceof JComboBox) {
- result = ((JComboBox>) comp).getSelectedItem().toString();
+ result = ((JComboBox>) comp).getSelectedItem();
+ if( result != null )
+ result = result.toString();
} else if (comp instanceof JCheckBox) {
result = ((JCheckBox) comp).isSelected();
} else if (comp instanceof FormatTextField) {
@@ -391,6 +396,26 @@ public void setError(boolean error) {
this.error = error;
}
+ public void setOperationSkip(int count) {
+ if( count < 0 )
+ count = 0;
+ this.operationSkip = count;
+ }
+
+ public int getOperationSkip() {
+ return this.operationSkip;
+ }
+
+ public void setLaneSkip(int count) {
+ if( count < 0 )
+ count = 0;
+ this.laneSkip = count;
+ }
+
+ public int getLaneSkip() {
+ return this.laneSkip;
+ }
+
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface OperationInfos {
diff --git a/src/de/usd/cstchef/operations/OperationCategory.java b/src/de/usd/cstchef/operations/OperationCategory.java
index e9e87b9..10abe79 100644
--- a/src/de/usd/cstchef/operations/OperationCategory.java
+++ b/src/de/usd/cstchef/operations/OperationCategory.java
@@ -4,6 +4,7 @@ public enum OperationCategory {
ARITHMETIC("Arithmetic"),
BYTEOPERATION("Byte Operations"),
COMPRESSION("Compression"),
+ CONDITIONALS("Conditionals"),
DATAFORMAT("Data format"),
DATES("Date / Time"),
ENCRYPTION("Encryption / Encoding"),
diff --git a/src/de/usd/cstchef/operations/conditional/ConditionalOperation.java b/src/de/usd/cstchef/operations/conditional/ConditionalOperation.java
new file mode 100644
index 0000000..a928361
--- /dev/null
+++ b/src/de/usd/cstchef/operations/conditional/ConditionalOperation.java
@@ -0,0 +1,52 @@
+package de.usd.cstchef.operations.conditional;
+
+import javax.swing.JTextField;
+
+import de.usd.cstchef.operations.Operation;
+import de.usd.cstchef.view.ui.VariableTextField;
+
+public abstract class ConditionalOperation extends Operation {
+
+ protected VariableTextField expr;
+ private JTextField operationSkipField;
+ private JTextField laneSkipField;
+
+ public void setOperationSkip() {
+
+ try {
+ int operationSkip = Integer.valueOf(operationSkipField.getText());
+ this.setOperationSkip(operationSkip);
+ } catch( Exception e ) {
+ throw new IllegalArgumentException("Input is not a number.");
+ }
+ }
+
+ public void setLaneSkip() {
+
+ try {
+ int laneSkip = Integer.valueOf(laneSkipField.getText());
+ this.setLaneSkip(laneSkip);
+ } catch( Exception e ) {
+ throw new IllegalArgumentException("Input is not a number.");
+ }
+ }
+
+ public void resetSkips() {
+ this.setOperationSkip(0);
+ this.setLaneSkip(0);
+ }
+
+ @Override
+ public void createUI() {
+ this.expr = new VariableTextField();
+ this.addUIElement("Expr", this.expr);
+
+ this.operationSkipField = new JTextField("0");
+ this.addUIElement("Skip Operations", this.operationSkipField);
+
+ this.laneSkipField = new JTextField("0");
+ this.addUIElement("Skip Lanes", this.laneSkipField);
+
+ }
+
+}
diff --git a/src/de/usd/cstchef/operations/conditional/NumberCompare.java b/src/de/usd/cstchef/operations/conditional/NumberCompare.java
new file mode 100644
index 0000000..f336d85
--- /dev/null
+++ b/src/de/usd/cstchef/operations/conditional/NumberCompare.java
@@ -0,0 +1,73 @@
+package de.usd.cstchef.operations.conditional;
+
+import javax.swing.JComboBox;
+
+import de.usd.cstchef.operations.Operation.OperationInfos;
+import de.usd.cstchef.operations.OperationCategory;
+
+@OperationInfos(name = "Number Compare", category = OperationCategory.CONDITIONALS, description = "Skip if evaluates to true")
+public class NumberCompare extends ConditionalOperation {
+
+ private JComboBox operationBox;
+
+ @Override
+ protected byte[] perform(byte[] input) throws Exception {
+
+ Double inputNumber;
+ Double userNumber;
+
+ try {
+ String tmp = new String(input);
+ inputNumber = Double.valueOf(tmp);
+ userNumber = Double.valueOf(this.expr.getText());
+ } catch( Exception e ) {
+ throw new IllegalArgumentException("Input is not a number.");
+ }
+
+ boolean condition = false;
+ switch ((String)this.operationBox.getSelectedItem()) {
+ case "equal":
+ if( inputNumber.compareTo(userNumber) == 0 )
+ condition = true;
+ break;
+ case "not equal":
+ if( inputNumber.compareTo(userNumber) != 0 )
+ condition = true;
+ break;
+ case "greater":
+ if( inputNumber < userNumber )
+ condition = true;
+ break;
+ case "lower":
+ if( inputNumber > userNumber )
+ condition = true;
+ break;
+ case "greater equal":
+ if( inputNumber <= userNumber )
+ condition = true;
+ break;
+ case "lower equal":
+ if( inputNumber >= userNumber )
+ condition = true;
+ break;
+ }
+
+ if( condition ) {
+ this.setOperationSkip();
+ this.setLaneSkip();
+ } else {
+ this.resetSkips();
+ }
+
+ return input;
+ }
+
+ @Override
+ public void createUI() {
+ super.createUI();
+ this.operationBox = new JComboBox<>(new String[] {"equal", "not equal", "lower", "greater", "lower equal", "greater equal"});
+ this.operationBox.setSelectedItem("equal");
+ this.addUIElement("Lineseperator", this.operationBox);
+ }
+
+}
diff --git a/src/de/usd/cstchef/operations/conditional/RegexMatch.java b/src/de/usd/cstchef/operations/conditional/RegexMatch.java
new file mode 100644
index 0000000..2f156af
--- /dev/null
+++ b/src/de/usd/cstchef/operations/conditional/RegexMatch.java
@@ -0,0 +1,51 @@
+package de.usd.cstchef.operations.conditional;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.swing.JCheckBox;
+
+import de.usd.cstchef.operations.Operation.OperationInfos;
+import de.usd.cstchef.operations.OperationCategory;
+
+@OperationInfos(name = "Regex Match", category = OperationCategory.CONDITIONALS, description = "Skip if regex matches")
+public class RegexMatch extends ConditionalOperation {
+
+ private JCheckBox invert;
+ private JCheckBox find;
+
+ @Override
+ protected byte[] perform(byte[] input) throws Exception {
+
+ Pattern p = Pattern.compile(this.expr.getText());
+ Matcher m = p.matcher(new String(input));
+
+ boolean condition = false;
+ if( find.isSelected() ) {
+ condition = m.find();
+ } else {
+ condition = m.matches();
+ }
+
+ if( condition ^ invert.isSelected() ) {
+ this.setOperationSkip();
+ this.setLaneSkip();
+ } else {
+ this.resetSkips();
+ }
+
+ return input;
+ }
+
+ @Override
+ public void createUI() {
+ super.createUI();
+
+ this.invert = new JCheckBox();
+ this.addUIElement("Invert Match", this.invert);
+
+ this.find = new JCheckBox();
+ this.addUIElement("Find anywhere", this.find);
+ }
+
+}
diff --git a/src/de/usd/cstchef/operations/conditional/StringContains.java b/src/de/usd/cstchef/operations/conditional/StringContains.java
new file mode 100644
index 0000000..d29ee8a
--- /dev/null
+++ b/src/de/usd/cstchef/operations/conditional/StringContains.java
@@ -0,0 +1,45 @@
+package de.usd.cstchef.operations.conditional;
+
+import javax.swing.JCheckBox;
+
+import burp.BurpUtils;
+import burp.IBurpExtenderCallbacks;
+import burp.IExtensionHelpers;
+import de.usd.cstchef.operations.Operation.OperationInfos;
+import de.usd.cstchef.operations.OperationCategory;
+
+@OperationInfos(name = "String Contains", category = OperationCategory.CONDITIONALS, description = "Skip if input contains")
+public class StringContains extends ConditionalOperation {
+
+ private JCheckBox invert;
+ private JCheckBox caseSensitive;
+
+ @Override
+ protected byte[] perform(byte[] input) throws Exception {
+
+ IBurpExtenderCallbacks cbs = BurpUtils.getInstance().getCallbacks();
+ IExtensionHelpers helpers = cbs.getHelpers();
+ int start = helpers.indexOf(input, this.expr.getBytes(), caseSensitive.isSelected(), 0, input.length);
+
+ if( (start >= 0) ^ invert.isSelected() ) {
+ this.setOperationSkip();
+ this.setLaneSkip();
+ } else {
+ this.resetSkips();
+ }
+
+ return input;
+ }
+
+ @Override
+ public void createUI() {
+ super.createUI();
+
+ this.invert = new JCheckBox();
+ this.addUIElement("Invert Match", this.invert);
+
+ this.caseSensitive = new JCheckBox();
+ this.addUIElement("Case Sensitive", this.caseSensitive);
+ }
+
+}
diff --git a/src/de/usd/cstchef/operations/conditional/StringMatch.java b/src/de/usd/cstchef/operations/conditional/StringMatch.java
new file mode 100644
index 0000000..56cfbf0
--- /dev/null
+++ b/src/de/usd/cstchef/operations/conditional/StringMatch.java
@@ -0,0 +1,56 @@
+package de.usd.cstchef.operations.conditional;
+
+import javax.swing.JCheckBox;
+
+import burp.BurpUtils;
+import burp.IBurpExtenderCallbacks;
+import burp.IExtensionHelpers;
+import de.usd.cstchef.operations.Operation.OperationInfos;
+import de.usd.cstchef.operations.OperationCategory;
+
+@OperationInfos(name = "String Match", category = OperationCategory.CONDITIONALS, description = "Skip if input matches")
+public class StringMatch extends ConditionalOperation {
+
+ private JCheckBox invert;
+ private JCheckBox caseSensitive;
+
+ @Override
+ protected byte[] perform(byte[] input) throws Exception {
+
+ byte[] search = this.expr.getBytes();
+ if( search.length != input.length ) {
+ if( invert.isSelected() ) {
+ this.setOperationSkip();
+ this.setLaneSkip();
+ } else {
+ this.resetSkips();
+ }
+ return input;
+ }
+
+ IBurpExtenderCallbacks cbs = BurpUtils.getInstance().getCallbacks();
+ IExtensionHelpers helpers = cbs.getHelpers();
+ int start = helpers.indexOf(input, search, caseSensitive.isSelected(), 0, input.length);
+
+ if( (start >= 0) ^ invert.isSelected() ) {
+ this.setOperationSkip();
+ this.setLaneSkip();
+ } else {
+ this.resetSkips();
+ }
+
+ return input;
+ }
+
+ @Override
+ public void createUI() {
+ super.createUI();
+
+ this.invert = new JCheckBox();
+ this.addUIElement("Invert Match", this.invert);
+
+ this.caseSensitive = new JCheckBox();
+ this.addUIElement("Case Sensitive", this.caseSensitive);
+ }
+
+}
diff --git a/src/de/usd/cstchef/operations/dataformat/HtmlDecode.java b/src/de/usd/cstchef/operations/dataformat/HtmlDecode.java
new file mode 100644
index 0000000..918d0d1
--- /dev/null
+++ b/src/de/usd/cstchef/operations/dataformat/HtmlDecode.java
@@ -0,0 +1,22 @@
+package de.usd.cstchef.operations.dataformat;
+
+import java.nio.charset.StandardCharsets;
+
+import org.apache.commons.text.StringEscapeUtils;
+
+import de.usd.cstchef.operations.Operation;
+import de.usd.cstchef.operations.Operation.OperationInfos;
+import de.usd.cstchef.operations.OperationCategory;
+
+@OperationInfos(name = "HTML Decode", category = OperationCategory.DATAFORMAT, description = "HTML Decode")
+public class HtmlDecode extends Operation {
+
+ @Override
+ protected byte[] perform(byte[] input) throws Exception {
+
+ String tmp = new String(input, StandardCharsets.ISO_8859_1);
+ tmp = StringEscapeUtils.unescapeHtml4(tmp);
+ return tmp.getBytes(StandardCharsets.ISO_8859_1);
+ }
+
+}
diff --git a/src/de/usd/cstchef/operations/dataformat/HtmlEncode.java b/src/de/usd/cstchef/operations/dataformat/HtmlEncode.java
new file mode 100644
index 0000000..716030e
--- /dev/null
+++ b/src/de/usd/cstchef/operations/dataformat/HtmlEncode.java
@@ -0,0 +1,54 @@
+package de.usd.cstchef.operations.dataformat;
+
+import java.io.ByteArrayOutputStream;
+
+import javax.swing.JCheckBox;
+
+import org.apache.commons.text.StringEscapeUtils;
+
+import de.usd.cstchef.operations.Operation;
+import de.usd.cstchef.operations.Operation.OperationInfos;
+import de.usd.cstchef.operations.OperationCategory;
+
+@OperationInfos(name = "HTML Encode", category = OperationCategory.DATAFORMAT, description = "HTML Encode")
+public class HtmlEncode extends Operation {
+
+ private JCheckBox checkbox;
+
+ @Override
+ protected byte[] perform(byte[] input) throws Exception {
+
+ byte[] result = null;
+ if( checkbox.isSelected() ) {
+
+ byte[] delimiter = "".getBytes();
+ byte[] closer = ";".getBytes();
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+ out.write(delimiter);
+ for (int i = 0; i < input.length - 1; i++) {
+ out.write(String.valueOf(Byte.toUnsignedInt(input[i])).getBytes());
+ out.write(closer);
+ out.write(delimiter);
+ }
+
+ out.write(String.valueOf(Byte.toUnsignedInt(input[input.length - 1])).getBytes());
+ out.write(closer);
+ result = out.toByteArray();
+
+ } else {
+ String tmp = new String(input);
+ tmp = StringEscapeUtils.escapeHtml4(tmp);
+ result = tmp.getBytes();
+ }
+
+ return result;
+ }
+
+ @Override
+ public void createUI() {
+ this.checkbox = new JCheckBox("Encode all");
+ this.checkbox.setSelected(false);
+ this.addUIElement(null, this.checkbox);
+ }
+}
diff --git a/src/de/usd/cstchef/operations/encryption/RsaDecryption.java b/src/de/usd/cstchef/operations/encryption/RsaDecryption.java
new file mode 100644
index 0000000..908a3e0
--- /dev/null
+++ b/src/de/usd/cstchef/operations/encryption/RsaDecryption.java
@@ -0,0 +1,75 @@
+package de.usd.cstchef.operations.encryption;
+
+import javax.crypto.Cipher;
+import javax.swing.JComboBox;
+
+import org.bouncycastle.util.encoders.Base64;
+import org.bouncycastle.util.encoders.Hex;
+
+import de.usd.cstchef.operations.OperationCategory;
+import de.usd.cstchef.operations.Operation.OperationInfos;
+import de.usd.cstchef.operations.encryption.CipherUtils.CipherInfo;
+import de.usd.cstchef.operations.signature.KeystoreOperation;
+
+@OperationInfos(name = "RSA Decryption", category = OperationCategory.ENCRYPTION, description = "Decrypt input using a private key")
+public class RsaDecryption extends KeystoreOperation {
+
+ private static String[] inOutModes = new String[] { "Raw", "Hex", "Base64" };
+
+ protected String algorithm = "RSA";
+ protected String cipherMode = "ECB";
+
+ protected JComboBox inputMode;
+ protected JComboBox outputMode;
+ protected JComboBox paddings;
+
+ public RsaDecryption() {
+ super();
+ this.createMyUI();
+ }
+
+ protected byte[] perform(byte[] input) throws Exception {
+
+ if( ! this.keyAvailable.isSelected() )
+ throw new IllegalArgumentException("No private key available.");
+
+ String padding = (String)paddings.getSelectedItem();
+ Cipher cipher = Cipher.getInstance(String.format("%s/%s/%s", algorithm, cipherMode, padding));
+ cipher.init(Cipher.DECRYPT_MODE, this.selectedEntry.getPrivateKey());
+
+ String selectedInputMode = (String)inputMode.getSelectedItem();
+ String selectedOutputMode = (String)outputMode.getSelectedItem();
+
+ if( selectedInputMode.equals("Hex") )
+ input = Hex.decode(input);
+ if( selectedInputMode.equals("Base64") )
+ input = Base64.decode(input);
+
+ byte[] encrypted = cipher.doFinal(input);
+
+ if( selectedOutputMode.equals("Hex") )
+ encrypted = Hex.encode(encrypted);
+ if( selectedOutputMode.equals("Base64") )
+ encrypted = Base64.encode(encrypted);
+
+ return encrypted;
+ }
+
+ public void createMyUI() {
+
+ super.createMyUI();
+
+ CipherUtils utils = CipherUtils.getInstance();
+ CipherInfo info = utils.getCipherInfo(this.algorithm);
+
+ this.paddings = new JComboBox<>(info.getPaddings());
+ this.addUIElement("Padding", this.paddings);
+
+ this.inputMode = new JComboBox<>(inOutModes);
+ this.addUIElement("Input", this.inputMode);
+
+ this.outputMode = new JComboBox<>(inOutModes);
+ this.addUIElement("Output", this.outputMode);
+ }
+
+}
diff --git a/src/de/usd/cstchef/operations/encryption/RsaEncryption.java b/src/de/usd/cstchef/operations/encryption/RsaEncryption.java
new file mode 100644
index 0000000..edcde37
--- /dev/null
+++ b/src/de/usd/cstchef/operations/encryption/RsaEncryption.java
@@ -0,0 +1,75 @@
+package de.usd.cstchef.operations.encryption;
+
+import javax.crypto.Cipher;
+import javax.swing.JComboBox;
+
+import org.bouncycastle.util.encoders.Base64;
+import org.bouncycastle.util.encoders.Hex;
+
+import de.usd.cstchef.operations.OperationCategory;
+import de.usd.cstchef.operations.Operation.OperationInfos;
+import de.usd.cstchef.operations.encryption.CipherUtils.CipherInfo;
+import de.usd.cstchef.operations.signature.KeystoreOperation;
+
+@OperationInfos(name = "RSA Encryption", category = OperationCategory.ENCRYPTION, description = "Encrypt input using a certificate")
+public class RsaEncryption extends KeystoreOperation {
+
+ private static String[] inOutModes = new String[] { "Raw", "Hex", "Base64" };
+
+ protected String algorithm = "RSA";
+ protected String cipherMode = "ECB";
+
+ protected JComboBox inputMode;
+ protected JComboBox outputMode;
+ protected JComboBox paddings;
+
+ public RsaEncryption() {
+ super();
+ this.createMyUI();
+ }
+
+ protected byte[] perform(byte[] input) throws Exception {
+
+ if( ! this.certAvailable.isSelected() )
+ throw new IllegalArgumentException("No certificate available.");
+
+ String padding = (String)paddings.getSelectedItem();
+ Cipher cipher = Cipher.getInstance(String.format("%s/%s/%s", algorithm, cipherMode, padding));
+ cipher.init(Cipher.ENCRYPT_MODE, this.cert.getPublicKey());
+
+ String selectedInputMode = (String)inputMode.getSelectedItem();
+ String selectedOutputMode = (String)outputMode.getSelectedItem();
+
+ if( selectedInputMode.equals("Hex") )
+ input = Hex.decode(input);
+ if( selectedInputMode.equals("Base64") )
+ input = Base64.decode(input);
+
+ byte[] encrypted = cipher.doFinal(input);
+
+ if( selectedOutputMode.equals("Hex") )
+ encrypted = Hex.encode(encrypted);
+ if( selectedOutputMode.equals("Base64") )
+ encrypted = Base64.encode(encrypted);
+
+ return encrypted;
+ }
+
+ public void createMyUI() {
+
+ super.createMyUI();
+
+ CipherUtils utils = CipherUtils.getInstance();
+ CipherInfo info = utils.getCipherInfo(this.algorithm);
+
+ this.paddings = new JComboBox<>(info.getPaddings());
+ this.addUIElement("Padding", this.paddings);
+
+ this.inputMode = new JComboBox<>(inOutModes);
+ this.addUIElement("Input", this.inputMode);
+
+ this.outputMode = new JComboBox<>(inOutModes);
+ this.addUIElement("Output", this.outputMode);
+ }
+
+}
diff --git a/src/de/usd/cstchef/operations/setter/HttpHeaderSetter.java b/src/de/usd/cstchef/operations/setter/HttpHeaderSetter.java
index f91a080..01450f2 100644
--- a/src/de/usd/cstchef/operations/setter/HttpHeaderSetter.java
+++ b/src/de/usd/cstchef/operations/setter/HttpHeaderSetter.java
@@ -1,13 +1,12 @@
package de.usd.cstchef.operations.setter;
-import java.util.Arrays;
-
import javax.swing.JCheckBox;
import burp.BurpUtils;
import burp.IBurpExtenderCallbacks;
import burp.IExtensionHelpers;
import burp.IRequestInfo;
+import de.usd.cstchef.Utils;
import de.usd.cstchef.operations.Operation.OperationInfos;
import de.usd.cstchef.operations.OperationCategory;
@@ -37,7 +36,7 @@ protected byte[] perform(byte[] input) throws Exception {
int offset = helpers.indexOf(input, headerSearch, false, 0, length);
int start = helpers.indexOf(input, ": ".getBytes(), false, offset, length) + 2;
int end = helpers.indexOf(input, "\r\n".getBytes(), false, start, length);
- return insertAtOffset(input, start, end, newValue);
+ return Utils.insertAtOffset(input, start, end, newValue);
} catch( IllegalArgumentException e ) {
@@ -51,7 +50,7 @@ protected byte[] perform(byte[] input) throws Exception {
System.arraycopy(headerSearch, 0, value, 0, headerSearch.length);
System.arraycopy(newValue, 0, value, headerName.length + 2, newValue.length);
System.arraycopy("\r\n".getBytes(), 0, value, headerName.length + 2 + newValue.length, 2);
- return insertAtOffset(input, bodyOffset, bodyOffset, value);
+ return Utils.insertAtOffset(input, bodyOffset, bodyOffset, value);
}
}
@@ -64,15 +63,4 @@ public void createUI() {
this.addUIElement(null, this.addIfNotPresent);
}
- private byte[] insertAtOffset(byte[] input, int start, int end, byte[] newValue) {
- byte[] prefix = Arrays.copyOfRange(input, 0, start);
- byte[] rest = Arrays.copyOfRange(input, end, input.length);
-
- byte[] output = new byte[prefix.length + newValue.length + rest.length];
- System.arraycopy(prefix, 0, output, 0, prefix.length);
- System.arraycopy(newValue, 0, output, prefix.length, newValue.length);
- System.arraycopy(rest, 0, output, prefix.length + newValue.length, rest.length);
-
- return output;
- }
}
diff --git a/src/de/usd/cstchef/operations/setter/HttpSetCookie.java b/src/de/usd/cstchef/operations/setter/HttpSetCookie.java
index 23641ae..76dce5b 100644
--- a/src/de/usd/cstchef/operations/setter/HttpSetCookie.java
+++ b/src/de/usd/cstchef/operations/setter/HttpSetCookie.java
@@ -1,13 +1,12 @@
package de.usd.cstchef.operations.setter;
-import java.util.Arrays;
-
import javax.swing.JCheckBox;
import burp.BurpUtils;
import burp.IBurpExtenderCallbacks;
import burp.IExtensionHelpers;
import burp.IResponseInfo;
+import de.usd.cstchef.Utils;
import de.usd.cstchef.operations.Operation.OperationInfos;
import de.usd.cstchef.operations.OperationCategory;
@@ -52,7 +51,7 @@ protected byte[] perform(byte[] input) throws Exception {
if( end < 0 )
end = line_end;
- return insertAtOffset(input, start + cookieSearch.length, end, newValue);
+ return Utils.insertAtOffset(input, start + cookieSearch.length, end, newValue);
} catch( IllegalArgumentException e ) {
@@ -66,7 +65,7 @@ protected byte[] perform(byte[] input) throws Exception {
System.arraycopy("=".getBytes(), 0, value, cookieName.length, 1);
System.arraycopy(newValue, 0, value, cookieName.length + 1, newValue.length);
System.arraycopy("; ".getBytes(), 0, value, cookieName.length + 1 + newValue.length, 2);
- return insertAtOffset(input, offset + cookieHeaderLength, offset + cookieHeaderLength, value);
+ return Utils.insertAtOffset(input, offset + cookieHeaderLength, offset + cookieHeaderLength, value);
} else {
@@ -77,7 +76,7 @@ protected byte[] perform(byte[] input) throws Exception {
System.arraycopy("=".getBytes(), 0, value, cookieHeaderLength + cookieName.length, 1);
System.arraycopy(newValue, 0, value, cookieHeaderLength + cookieName.length + 1, newValue.length);
System.arraycopy(";".getBytes(), 0, value, cookieHeaderLength + cookieName.length + 1 + newValue.length, 1);
- return insertAtOffset(input, bodyOffset, bodyOffset, value);
+ return Utils.insertAtOffset(input, bodyOffset, bodyOffset, value);
}
}
}
@@ -89,16 +88,5 @@ public void createUI() {
this.addIfNotPresent.setSelected(true);
this.addUIElement(null, this.addIfNotPresent);
}
-
- private byte[] insertAtOffset(byte[] input, int start, int end, byte[] newValue) {
- byte[] prefix = Arrays.copyOfRange(input, 0, start);
- byte[] rest = Arrays.copyOfRange(input, end, input.length);
-
- byte[] output = new byte[prefix.length + newValue.length + rest.length];
- System.arraycopy(prefix, 0, output, 0, prefix.length);
- System.arraycopy(newValue, 0, output, prefix.length, newValue.length);
- System.arraycopy(rest, 0, output, prefix.length + newValue.length, rest.length);
-
- return output;
- }
+
}
diff --git a/src/de/usd/cstchef/operations/setter/LineSetter.java b/src/de/usd/cstchef/operations/setter/LineSetter.java
index c174674..1d4a3a1 100644
--- a/src/de/usd/cstchef/operations/setter/LineSetter.java
+++ b/src/de/usd/cstchef/operations/setter/LineSetter.java
@@ -8,6 +8,7 @@
import burp.BurpUtils;
import burp.IBurpExtenderCallbacks;
import burp.IExtensionHelpers;
+import de.usd.cstchef.Utils;
import de.usd.cstchef.operations.Operation.OperationInfos;
import de.usd.cstchef.operations.OperationCategory;
@@ -70,9 +71,9 @@ protected byte[] perform(byte[] input) throws Exception {
byte[] value = new byte[newValue.length + lineEndings.length];
System.arraycopy(lineEndings, 0, value, 0, lineEndings.length);
System.arraycopy(newValue, 0, value, lineEndings.length, newValue.length);
- return insertAtOffset(input, end, end, value);
+ return Utils.insertAtOffset(input, end, end, value);
} else {
- return insertAtOffset(input, start, end, newValue);
+ return Utils.insertAtOffset(input, start, end, newValue);
}
}
@@ -87,15 +88,4 @@ public void createUI() {
this.addUIElement("Lineseperator", this.formatBox);
}
- private byte[] insertAtOffset(byte[] input, int start, int end, byte[] newValue) {
- byte[] prefix = Arrays.copyOfRange(input, 0, start);
- byte[] rest = Arrays.copyOfRange(input, end, input.length);
-
- byte[] output = new byte[prefix.length + newValue.length + rest.length];
- System.arraycopy(prefix, 0, output, 0, prefix.length);
- System.arraycopy(newValue, 0, output, prefix.length, newValue.length);
- System.arraycopy(rest, 0, output, prefix.length + newValue.length, rest.length);
-
- return output;
- }
}
diff --git a/src/de/usd/cstchef/operations/signature/KeystoreOperation.java b/src/de/usd/cstchef/operations/signature/KeystoreOperation.java
new file mode 100644
index 0000000..8c6ae01
--- /dev/null
+++ b/src/de/usd/cstchef/operations/signature/KeystoreOperation.java
@@ -0,0 +1,181 @@
+package de.usd.cstchef.operations.signature;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.io.FileInputStream;
+import java.security.KeyStore;
+import java.security.KeyStore.PrivateKeyEntry;
+import java.security.cert.Certificate;
+import java.util.Enumeration;
+
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JFileChooser;
+import javax.swing.JPasswordField;
+
+import de.usd.cstchef.operations.Operation;
+
+public abstract class KeystoreOperation extends Operation implements ActionListener {
+
+ protected String[] keyEntries = new String[] {};
+ protected String[] keyStoreTypes = new String[] {"JKS", "PKCS12"};
+
+ protected Certificate cert = null;
+ protected KeyStore keyStore = null;
+ protected PrivateKeyEntry selectedEntry = null;
+
+ protected File keyStoreFile = null;
+ protected JPasswordField keyStorePass;
+
+ protected JCheckBox keyStoreOpen;
+ protected JCheckBox certAvailable;
+ protected JCheckBox keyAvailable;
+
+ protected JButton chooseFileButton;
+ protected JButton openKeyStoreButton;
+ protected JComboBox keyEntry;
+ protected JComboBox keyStoreType;
+ protected JFileChooser fileChooser = new JFileChooser();
+
+ public KeystoreOperation() {
+ super();
+ }
+
+ private void openKeyStore() {
+ try {
+
+ String storeType = (String)keyStoreType.getSelectedItem();
+ char[] password = keyStorePass.getPassword();
+ KeyStore ks = KeyStore.getInstance(storeType);
+ ks.load(new FileInputStream(keyStoreFile), password);
+ this.keyStore = ks;
+ this.keyStoreOpen.setSelected(true);
+ this.certAvailable.setSelected(false);
+ this.keyAvailable.setSelected(false);
+ this.updateKeyEntries();
+
+ } catch( Exception e ) {
+ this.resetKeyStore();
+ }
+ }
+
+ private void updateKeyEntries(){
+ try {
+ Enumeration entries = keyStore.aliases();
+ keyEntry.removeAllItems();
+ while (entries.hasMoreElements()) {
+ keyEntry.addItem(entries.nextElement());
+ }
+ } catch( Exception e ) {
+ this.resetKeyStore();
+ }
+ }
+
+ private void selectKeyEntry() {
+
+ String entry = (String)keyEntry.getSelectedItem();
+ try {
+ this.cert = keyStore.getCertificate(entry);
+ if ( this.cert != null )
+ this.certAvailable.setSelected(true);
+ else
+ this.certAvailable.setSelected(false);
+
+ } catch( Exception e ) {
+ this.certAvailable.setSelected(false);
+ }
+
+ char[] password = keyStorePass.getPassword();
+ try {
+ this.selectedEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(entry, new KeyStore.PasswordProtection(password));
+ if ( this.selectedEntry != null )
+ this.keyAvailable.setSelected(true);
+ else
+ this.keyAvailable.setSelected(false);
+ } catch( Exception e) {
+ this.keyAvailable.setSelected(false);
+ }
+
+ }
+
+
+ private void resetKeyStore() {
+ this.keyStoreOpen.setSelected(false);
+ this.certAvailable.setSelected(false);
+ this.keyAvailable.setSelected(false);
+ keyStore = null;
+ selectedEntry = null;
+ }
+
+
+ public void createMyUI() {
+ this.keyStoreType = new JComboBox<>(this.keyStoreTypes);
+ this.keyStoreType.addActionListener(this);
+ this.addUIElement("KeyStoreType", this.keyStoreType);
+
+ chooseFileButton = new JButton("Select file");
+ chooseFileButton.addActionListener(this);
+ this.addUIElement(null, this.chooseFileButton);
+
+ this.keyStorePass = new JPasswordField();
+ this.addUIElement("PrivKeyPassword", this.keyStorePass);
+
+ openKeyStoreButton = new JButton("Open keystore");
+ openKeyStoreButton.addActionListener(this);
+ this.addUIElement(null, this.openKeyStoreButton);
+
+ this.keyEntry = new JComboBox<>(keyEntries);
+ this.keyEntry.addActionListener(this);
+ this.addUIElement("KeyEntry", this.keyEntry);
+
+ this.keyStoreOpen = new JCheckBox("KeyStore Opened");
+ this.keyStoreOpen.setSelected(false);
+ this.keyStoreOpen.setEnabled(false);
+ this.keyStoreOpen.addActionListener(this);
+ this.addUIElement(null, this.keyStoreOpen);
+
+ this.certAvailable = new JCheckBox("Certificate available");
+ this.certAvailable.setSelected(false);
+ this.certAvailable.setEnabled(false);
+ this.certAvailable.addActionListener(this);
+ this.addUIElement(null, this.certAvailable);
+
+ this.keyAvailable = new JCheckBox("PrivKey available");
+ this.keyAvailable.setSelected(false);
+ this.keyAvailable.setEnabled(false);
+ this.keyAvailable.addActionListener(this);
+ this.addUIElement(null, this.keyAvailable);
+
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent arg0) {
+
+ if( arg0.getSource() == keyStoreType ) {
+
+ this.resetKeyStore();
+
+ } else if( arg0.getSource() == openKeyStoreButton ) {
+
+ this.resetKeyStore();
+ this.openKeyStore();
+
+ } else if( arg0.getSource() == chooseFileButton ) {
+
+ this.resetKeyStore();
+ int returnVal = fileChooser.showOpenDialog(this);
+ if (returnVal == JFileChooser.APPROVE_OPTION) {
+ keyStoreFile = fileChooser.getSelectedFile();
+ }
+
+ } else if( arg0.getSource() == keyEntry ) {
+ this.selectKeyEntry();
+ }
+
+ if( keyStore != null && keyEntry != null ) {
+ this.notifyChange();
+ }
+ }
+}
diff --git a/src/de/usd/cstchef/operations/signature/RsaSignature.java b/src/de/usd/cstchef/operations/signature/RsaSignature.java
new file mode 100644
index 0000000..b02b463
--- /dev/null
+++ b/src/de/usd/cstchef/operations/signature/RsaSignature.java
@@ -0,0 +1,69 @@
+package de.usd.cstchef.operations.signature;
+
+import java.security.Signature;
+
+import javax.swing.JComboBox;
+
+import org.bouncycastle.util.encoders.Base64;
+import org.bouncycastle.util.encoders.Hex;
+
+import de.usd.cstchef.operations.Operation.OperationInfos;
+import de.usd.cstchef.operations.OperationCategory;
+
+@OperationInfos(name = "RSA Signature", category = OperationCategory.SIGNATURE, description = "Create an RSA signature")
+public class RsaSignature extends KeystoreOperation {
+
+ private static String[] inOutModes = new String[] { "Raw", "Hex", "Base64" };
+
+ protected JComboBox algos;
+ protected JComboBox inputMode;
+ protected JComboBox outputMode;
+
+ public RsaSignature() {
+ super();
+ this.createMyUI();
+ }
+
+ protected byte[] perform(byte[] input) throws Exception {
+
+ if( !this.keyAvailable.isSelected() )
+ throw new IllegalArgumentException("No private key available.");
+
+ String algo = (String)algos.getSelectedItem();
+ Signature signature = Signature.getInstance(algo);
+
+ String selectedInputMode = (String)inputMode.getSelectedItem();
+ String selectedOutputMode = (String)outputMode.getSelectedItem();
+
+ if( selectedInputMode.equals("Hex") )
+ input = Hex.decode(input);
+ if( selectedInputMode.equals("Base64") )
+ input = Base64.decode(input);
+
+ signature.initSign(this.selectedEntry.getPrivateKey());
+ signature.update(input);
+ byte[] result = signature.sign();
+
+ if( selectedOutputMode.equals("Hex") )
+ result = Hex.encode(result);
+ if( selectedOutputMode.equals("Base64") )
+ result = Base64.encode(result);
+
+ return result;
+ }
+
+ public void createMyUI() {
+
+ super.createMyUI();
+ SignatureUtils utils = SignatureUtils.getInstance();
+
+ this.algos = new JComboBox<>(utils.getRsaAlgos());
+ this.addUIElement("Padding", this.algos);
+
+ this.inputMode = new JComboBox<>(inOutModes);
+ this.addUIElement("Input", this.inputMode);
+
+ this.outputMode = new JComboBox<>(inOutModes);
+ this.addUIElement("Output", this.outputMode);
+ }
+}
diff --git a/src/de/usd/cstchef/operations/signature/SignatureOperation.java b/src/de/usd/cstchef/operations/signature/SignatureOperation.java
deleted file mode 100644
index f946375..0000000
--- a/src/de/usd/cstchef/operations/signature/SignatureOperation.java
+++ /dev/null
@@ -1,135 +0,0 @@
-package de.usd.cstchef.operations.signature;
-
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.io.File;
-import java.io.FileInputStream;
-import java.security.KeyStore;
-import java.security.KeyStore.PrivateKeyEntry;
-import java.util.Enumeration;
-
-import javax.swing.JButton;
-import javax.swing.JCheckBox;
-import javax.swing.JComboBox;
-import javax.swing.JFileChooser;
-
-import de.usd.cstchef.operations.Operation;
-import de.usd.cstchef.view.ui.FormatTextField;
-
-public abstract class SignatureOperation extends Operation implements ActionListener {
-
- protected String[] keyEntries = new String[] {};
- protected String[] keyStoreTypes = new String[] {"PKCS12", "JKS"};
-
- protected KeyStore keyStore = null;
- protected PrivateKeyEntry selectedEntry = null;
-
- protected File keyStoreFile = null;
- protected FormatTextField keyStorePass;
-
- protected JCheckBox keyStoreOpen;
- protected JButton chooseFileButton;
- protected JButton openKeyStoreButton;
- protected JComboBox keyEntry;
- protected JComboBox keyStoreType;
- protected JFileChooser fileChooser = new JFileChooser();
-
-
- public SignatureOperation() {
- super();
- }
-
-
- private void openKeyStore() {
- try {
- String storeType = (String)keyStoreType.getSelectedItem();
- String password = new String(keyStorePass.getText());
- KeyStore ks = KeyStore.getInstance(storeType);
- ks.load(new FileInputStream(keyStoreFile), password.toCharArray());
- this.keyStore = ks;
- this.keyStoreOpen.setSelected(true);
- this.updateKeyEntries();
- } catch( Exception e ) {
- this.resetKeyStore();
- }
- }
-
-
- private void updateKeyEntries() {
- try {
- Enumeration entries = keyStore.aliases();
- keyEntry.removeAllItems();
- while (entries.hasMoreElements()) {
- keyEntry.addItem(entries.nextElement());
- }
- } catch( Exception e ) {
- this.resetKeyStore();
- }
- }
-
-
- private void selectKeyEntry() {
- try {
- String password = new String(keyStorePass.getText());
- String entryNumber = (String)keyEntry.getSelectedItem();
- selectedEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(entryNumber, new KeyStore.PasswordProtection(password.toCharArray()));
- } catch( Exception e ) {
- this.resetKeyStore();
- }
- }
-
-
- private void resetKeyStore() {
- this.keyStoreOpen.setSelected(false);
- keyStore = null;
- selectedEntry = null;
- }
-
-
- public void createMyUI() {
- this.keyStoreType = new JComboBox<>(this.keyStoreTypes);
- this.keyStoreType.addActionListener(this);
- this.addUIElement("KeyStoreType", this.keyStoreType);
-
- chooseFileButton = new JButton("Select file");
- chooseFileButton.addActionListener(this);
- this.addUIElement(null, this.chooseFileButton);
-
- this.keyStorePass = new FormatTextField();
- this.addUIElement("PrivKeyPassword", this.keyStorePass);
-
- openKeyStoreButton = new JButton("Open keystore");
- openKeyStoreButton.addActionListener(this);
- this.addUIElement(null, this.openKeyStoreButton);
-
- this.keyEntry = new JComboBox<>(keyEntries);
- this.keyEntry.addActionListener(this);
- this.addUIElement("KeyEntry", this.keyEntry);
-
- this.keyStoreOpen = new JCheckBox("KeyStore Opened");
- this.keyStoreOpen.setSelected(false);
- this.keyStoreOpen.addActionListener(this);
- this.addUIElement(null, this.keyStoreOpen);
- }
-
- @Override
- public void actionPerformed(ActionEvent arg0) {
- if( arg0.getSource() == keyStoreType ) {
- this.resetKeyStore();
- } else if( arg0.getSource() == openKeyStoreButton ) {
- this.resetKeyStore();
- this.openKeyStore();
- } else if( arg0.getSource() == chooseFileButton ) {
- this.resetKeyStore();
- int returnVal = fileChooser.showOpenDialog(this);
- if (returnVal == JFileChooser.APPROVE_OPTION) {
- keyStoreFile = fileChooser.getSelectedFile();
- }
- } else if( arg0.getSource() == keyEntry ) {
- this.selectKeyEntry();
- }
- if( keyStore != null && keyEntry != null ) {
- this.notifyChange();
- }
- }
-}
diff --git a/src/de/usd/cstchef/operations/signature/SignatureUtils.java b/src/de/usd/cstchef/operations/signature/SignatureUtils.java
new file mode 100644
index 0000000..04be967
--- /dev/null
+++ b/src/de/usd/cstchef/operations/signature/SignatureUtils.java
@@ -0,0 +1,42 @@
+package de.usd.cstchef.operations.signature;
+
+import java.security.Provider;
+import java.security.Provider.Service;
+import java.security.Security;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class SignatureUtils {
+
+ private static SignatureUtils instance;
+
+ private List algos;
+
+ private SignatureUtils() {
+ algos = new ArrayList();;
+ getSignatureInfos();
+ }
+
+ private void getSignatureInfos() {
+ for (Provider provider : Security.getProviders())
+ for (Service service : provider.getServices())
+ if (service.getType().equals("Signature"))
+ algos.add(service.getAlgorithm());
+ }
+
+ public static SignatureUtils getInstance() {
+ if (instance == null) {
+ instance = new SignatureUtils();
+ }
+ return instance;
+ }
+
+ public String[] getAlgos() {
+ return algos.toArray(new String[0]);
+ }
+ public String[] getRsaAlgos() {
+ List rsaAlgos = algos.stream().filter(p -> p.contains("RSA")).collect(Collectors.toList());
+ return rsaAlgos.toArray(new String[0]);
+ }
+}
diff --git a/src/de/usd/cstchef/operations/signature/SoapMultiSignature.java b/src/de/usd/cstchef/operations/signature/SoapMultiSignature.java
index 970f63a..cafca0e 100644
--- a/src/de/usd/cstchef/operations/signature/SoapMultiSignature.java
+++ b/src/de/usd/cstchef/operations/signature/SoapMultiSignature.java
@@ -43,12 +43,12 @@
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
-import de.usd.cstchef.operations.OperationCategory;
import de.usd.cstchef.operations.Operation.OperationInfos;
+import de.usd.cstchef.operations.OperationCategory;
import de.usd.cstchef.view.ui.FormatTextField;
@OperationInfos(name = "Soap Multi Signature", category = OperationCategory.ENCRYPTION, description = "Create a Soap signature.")
-public class SoapMultiSignature extends SignatureOperation {
+public class SoapMultiSignature extends KeystoreOperation {
public SoapMultiSignature() {
super();
diff --git a/src/de/usd/cstchef/operations/signature/XmlSignature.java b/src/de/usd/cstchef/operations/signature/XmlSignature.java
index 3da9381..e9ba6cd 100644
--- a/src/de/usd/cstchef/operations/signature/XmlSignature.java
+++ b/src/de/usd/cstchef/operations/signature/XmlSignature.java
@@ -37,7 +37,7 @@
import de.usd.cstchef.view.ui.FormatTextField;
-public abstract class XmlSignature extends SignatureOperation {
+public abstract class XmlSignature extends KeystoreOperation {
private boolean multiSignature = false;
private XMLSignatureFactory signatureFac;
diff --git a/src/de/usd/cstchef/operations/utils/NoOperation.java b/src/de/usd/cstchef/operations/utils/NoOperation.java
new file mode 100644
index 0000000..bfc8e27
--- /dev/null
+++ b/src/de/usd/cstchef/operations/utils/NoOperation.java
@@ -0,0 +1,15 @@
+package de.usd.cstchef.operations.utils;
+
+import de.usd.cstchef.operations.Operation;
+import de.usd.cstchef.operations.Operation.OperationInfos;
+import de.usd.cstchef.operations.OperationCategory;
+
+@OperationInfos(name = "No Operation", category = OperationCategory.UTILS, description = "Does nothing :)")
+public class NoOperation extends Operation {
+
+ @Override
+ protected byte[] perform(byte[] input) throws Exception {
+ return input;
+ }
+
+}
diff --git a/src/de/usd/cstchef/view/RecipePanel.java b/src/de/usd/cstchef/view/RecipePanel.java
index 58886a7..3350676 100644
--- a/src/de/usd/cstchef/view/RecipePanel.java
+++ b/src/de/usd/cstchef/view/RecipePanel.java
@@ -396,17 +396,26 @@ private byte[] doBake(byte[] input) {
intermediateResult = input;
outputChanged = false;
- // getOperations
- for (Operation op : ((RecipeStepPanel) operationLine).getOperations()) {
+
+ List operationList = ((RecipeStepPanel)operationLine).getOperations();
+ for(int i = 0; i < operationList.size(); i++) {
+
+ Operation op = operationList.get(i);
if (op.isDisabled()) {
continue;
}
+
intermediateResult = op.performOperation(intermediateResult);
outputChanged = true;
+
if (op.isBreakpoint()) {
result = intermediateResult;
- break out; // TODO wow..
+ store.setVariable(stepVariableName, intermediateResult);
+ break out;
}
+
+ i += op.getOperationSkip();
+ j += op.getLaneSkip();
}
if (outputChanged) {