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 ![CSTC](media/CSTC_White_Smaller.png) +![](https://github.com/usdAG/cstc/workflows/master%20maven%20CI/badge.svg?branch=master) +![](https://github.com/usdAG/cstc/workflows/develop%20maven%20CI/badge.svg?branch=develop) + # 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[] getOperationsBurp() { ZipInputStream zip = null; List> operations = new ArrayList>(); @@ -191,18 +221,24 @@ public static Class[] 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[] 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) {