args = new ArrayList<>();
- if (checkBoxUserClaims.isSelected()){
+ if (checkBoxUserClaims.isSelected()) {
args.add(ClaimsUtils.generateUserClaim(targetURL));
}
if (checkBoxUserWrappedClaims.isSelected()) {
@@ -87,7 +88,7 @@ private JWTClaimsSet checkInput( SecretKey selectedKey) {
args.add(ClaimsUtils.generateAuthenticatedClaims());
}
if (checkBoxUserAccessToken.isSelected()) {
- args.add(ClaimsUtils.generateUserAccessTokenPayload(targetURL,selectedKey));
+ args.add(ClaimsUtils.generateUserAccessTokenPayload(targetURL, selectedKey));
}
try {
return ClaimsUtils.concatClaims(args);
@@ -118,6 +119,8 @@ private void onOK() {
s = new OauthProxyTokenSigner(selectedKey);
} else if (tokenObject instanceof TornadoSignedToken) {
s = new TornadoTokenSigner(selectedKey);
+ } else if (tokenObject instanceof JSONWebSignature) {
+ s = new JSONWebSignatureTokenSigner(selectedKey);
} else if (tokenObject instanceof UnknownSignedToken) {
s = new TokenSigner(selectedKey);
} else {
diff --git a/src/main/java/one/d4d/sessionless/forms/utils/FormUtils.java b/src/main/java/one/d4d/sessionless/forms/utils/FormUtils.java
new file mode 100644
index 0000000..7b5ade1
--- /dev/null
+++ b/src/main/java/one/d4d/sessionless/forms/utils/FormUtils.java
@@ -0,0 +1,14 @@
+package one.d4d.sessionless.forms.utils;
+
+import org.exbin.deltahex.swing.CodeArea;
+import org.exbin.utils.binary_data.BinaryData;
+
+public class FormUtils {
+ public static byte[] getCodeAreaData(CodeArea codeArea) {
+ BinaryData binaryData = codeArea.getData();
+ int size = (int) binaryData.getDataSize();
+ byte[] data = new byte[size];
+ binaryData.copyToArray(0L, data, 0, size);
+ return data;
+ }
+}
diff --git a/src/main/java/one/d4d/sessionless/hexcodearea/HexCodeAreaCommandHandler.java b/src/main/java/one/d4d/sessionless/hexcodearea/HexCodeAreaCommandHandler.java
index e82ef58..ff18f34 100644
--- a/src/main/java/one/d4d/sessionless/hexcodearea/HexCodeAreaCommandHandler.java
+++ b/src/main/java/one/d4d/sessionless/hexcodearea/HexCodeAreaCommandHandler.java
@@ -1,6 +1,7 @@
package one.d4d.sessionless.hexcodearea;
import com.nimbusds.jose.util.Base64URL;
+import one.d4d.sessionless.forms.utils.FormUtils;
import one.d4d.sessionless.utils.Utils;
import org.exbin.deltahex.EditationMode;
import org.exbin.deltahex.swing.CodeArea;
@@ -19,17 +20,17 @@
/**
* Class to handle copy and paste from a CodeArea to/from hexadecimal strings
- *
+ *
* Modified from https://github.com/exbin/bined-lib-java/blob/5abc397f3091cf2471057e9c7a9943bb19deeb32/modules/bined-swt/src/main/java/org/exbin/bined/swt/basic/DefaultCodeAreaCommandHandler.java
- *
+ *
* Copyright (C) ExBin Project
- *
+ *
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -50,7 +51,7 @@ class HexCodeAreaCommandHandler extends DefaultCodeAreaCommandHandler {
*/
@Override
public void copy() {
- byte[] data = Utils.getCodeAreaData(codeArea);
+ byte[] data = FormUtils.getCodeAreaData(codeArea);
Utils.copyToClipboard(encodeHex(data));
}
@@ -59,13 +60,37 @@ public void copy() {
*/
@Override
public void cut() {
- byte[] data = Utils.getCodeAreaData(codeArea);
+ byte[] data = FormUtils.getCodeAreaData(codeArea);
super.cut();
Utils.copyToClipboard(encodeHex(data));
}
+ /**
+ * Paste to the contents of the CodeArea from the clipboard, which can be binary, base64 or hexadecimal
+ */
+ @Override
+ public void paste() {
+ Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+ try {
+ if (clipboard.isDataFlavorAvailable(DataFlavor.stringFlavor)) {
+ String clipboardData = (String) clipboard.getData(DataFlavor.stringFlavor);
+
+ if (Utils.isHex(clipboardData)) {
+ pasteByteArray(decodeHex(clipboardData));
+ } else if (Utils.isBase64URL(clipboardData)) {
+ pasteByteArray(Base64URL.from(clipboardData).decode());
+ } else {
+ super.paste();
+ }
+ }
+ } catch (UnsupportedFlavorException | IOException e) {
+ super.paste();
+ }
+ }
+
/**
* Paste an array of bytes into the CodeArea
+ *
* @param bytes bytes to paste
*/
private void pasteByteArray(byte[] bytes) {
@@ -89,27 +114,4 @@ private void pasteByteArray(byte[] bytes) {
this.codeArea.notifyCaretMoved();
this.codeArea.revealCursor();
}
-
- /**
- * Paste to the contents of the CodeArea from the clipboard, which can be binary, base64 or hexadecimal
- */
- @Override
- public void paste() {
- Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
- try {
- if (clipboard.isDataFlavorAvailable(DataFlavor.stringFlavor)) {
- String clipboardData = (String) clipboard.getData(DataFlavor.stringFlavor);
-
- if (Utils.isHex(clipboardData)) {
- pasteByteArray(decodeHex(clipboardData));
- } else if (Utils.isBase64URL(clipboardData)) {
- pasteByteArray(Base64URL.from(clipboardData).decode());
- } else {
- super.paste();
- }
- }
- } catch (UnsupportedFlavorException | IOException e) {
- super.paste();
- }
- }
}
diff --git a/src/main/java/one/d4d/sessionless/itsdangerous/crypto/Signers.java b/src/main/java/one/d4d/sessionless/itsdangerous/crypto/Signers.java
new file mode 100644
index 0000000..9b49ffa
--- /dev/null
+++ b/src/main/java/one/d4d/sessionless/itsdangerous/crypto/Signers.java
@@ -0,0 +1,5 @@
+package one.d4d.sessionless.itsdangerous.crypto;
+
+public enum Signers {
+ DANGEROUS, EXPRESS, OAUTH, TORNADO, RUBY, JWT, UNKNOWN
+}
diff --git a/src/main/java/one/d4d/sessionless/itsdangerous/model/RubySignedToken.java b/src/main/java/one/d4d/sessionless/itsdangerous/model/RubySignedToken.java
index f1d0eeb..353dc55 100644
--- a/src/main/java/one/d4d/sessionless/itsdangerous/model/RubySignedToken.java
+++ b/src/main/java/one/d4d/sessionless/itsdangerous/model/RubySignedToken.java
@@ -1,7 +1,7 @@
package one.d4d.sessionless.itsdangerous.model;
-import burp.config.Signers;
import one.d4d.sessionless.itsdangerous.crypto.RubyTokenSigner;
+import one.d4d.sessionless.itsdangerous.crypto.Signers;
import one.d4d.sessionless.utils.HexUtils;
public class RubySignedToken extends UnknownSignedToken {
diff --git a/src/main/java/one/d4d/sessionless/itsdangerous/model/SignedTokenObjectFinder.java b/src/main/java/one/d4d/sessionless/itsdangerous/model/SignedTokenObjectFinder.java
index 755dd83..0b9351d 100644
--- a/src/main/java/one/d4d/sessionless/itsdangerous/model/SignedTokenObjectFinder.java
+++ b/src/main/java/one/d4d/sessionless/itsdangerous/model/SignedTokenObjectFinder.java
@@ -1,10 +1,11 @@
package one.d4d.sessionless.itsdangerous.model;
import burp.api.montoya.http.message.Cookie;
+import burp.api.montoya.http.message.params.HttpParameterType;
import burp.api.montoya.http.message.params.ParsedHttpParameter;
import burp.config.SignerConfig;
-import burp.config.Signers;
import com.google.common.base.CharMatcher;
+import one.d4d.sessionless.itsdangerous.crypto.Signers;
import one.d4d.sessionless.utils.Utils;
import org.apache.commons.lang3.StringUtils;
@@ -21,20 +22,20 @@ public class SignedTokenObjectFinder {
// Regular expressions for JWS/JWE extraction
private static final String BASE64_REGEX = "[A-Za-z0-9-_]";
private static final String SEPARATOR_REGEX = "[.:!#$*;@|~]";
- private static final String SIGNER_REGEX = String.format("\\.?%s*%s+%s*%s+%s+", BASE64_REGEX, SEPARATOR_REGEX, BASE64_REGEX, SEPARATOR_REGEX, BASE64_REGEX);
+ private static final String SIGNER_REGEX = String.format("\\.?%s+%s+%s+%s+%s+", BASE64_REGEX, SEPARATOR_REGEX, BASE64_REGEX, SEPARATOR_REGEX, BASE64_REGEX);
private static final Pattern SIGNER_OBJECT_PATTERN = Pattern.compile(String.format("(%s)", SIGNER_REGEX));
private static final String UNKNOWN_SIGNED_STRING_REGEXP = String.format("(%s*%s%s{26,86})", BASE64_REGEX, SEPARATOR_REGEX, BASE64_REGEX);
private static final Pattern UNKNOWN_SIGNED_STRING_PATTERN = Pattern.compile(UNKNOWN_SIGNED_STRING_REGEXP);
public static boolean containsSignedTokenObjects(SignerConfig signerConfig, String text, List cookies, List params) {
List candidates = extractSignedTokenObjects(signerConfig, text, cookies, params);
- return candidates.size() > 0;
+ return !candidates.isEmpty();
}
public static List extractSignedTokenObjects(SignerConfig signerConfig, String text, List cookies, List params) {
List signedTokensObjects = new ArrayList<>();
Map cookiesToHashMap = convertCookiesToHashMap(cookies);
- Map paramsToHashMap = convertParamsToHashMap(params);
+ Map> paramsToHashMap = convertParamsToHashMap(params);
if (signerConfig.isEnabled(Signers.DANGEROUS)) {
Set tokenCandidates = findCandidateSignedTokenObjectsWithin(text);
for (String candidate : tokenCandidates) {
@@ -45,30 +46,36 @@ public static List extractSignedTokenObjects(SignerConfig si
}
if (signerConfig.isEnabled(Signers.EXPRESS)) {
signedTokensObjects.addAll(parseExpressSignedParams(cookiesToHashMap));
- signedTokensObjects.addAll(parseExpressSignedParams(paramsToHashMap));
+ paramsToHashMap.values().forEach(pairs -> signedTokensObjects.addAll(parseExpressSignedParams(pairs)));
}
if (signerConfig.isEnabled(Signers.OAUTH)) {
cookiesToHashMap.forEach((name, value) -> {
parseOauthProxySignedToken(name, value).ifPresent(v -> signedTokensObjects.add(new MutableSignedToken(value, v)));
});
- paramsToHashMap.forEach((name, value) -> {
- parseOauthProxySignedToken(name, value).ifPresent(v -> signedTokensObjects.add(new MutableSignedToken(value, v)));
+ paramsToHashMap.values().forEach(pairs -> {
+ pairs.forEach((name, value) -> {
+ parseOauthProxySignedToken(name, value).ifPresent(v -> signedTokensObjects.add(new MutableSignedToken(value, v)));
+ });
});
}
if (signerConfig.isEnabled(Signers.TORNADO)) {
cookiesToHashMap.forEach((name, value) -> {
parseTornadoSignedToken(name, value).ifPresent(v -> signedTokensObjects.add(new MutableSignedToken(value, v)));
});
- paramsToHashMap.forEach((name, value) -> {
- parseTornadoSignedToken(name, value).ifPresent(v -> signedTokensObjects.add(new MutableSignedToken(value, v)));
+ paramsToHashMap.values().forEach(pairs -> {
+ pairs.forEach((name, value) -> {
+ parseTornadoSignedToken(name, value).ifPresent(v -> signedTokensObjects.add(new MutableSignedToken(value, v)));
+ });
});
}
if (signerConfig.isEnabled(Signers.RUBY)) {
cookiesToHashMap.forEach((name, value) -> {
parseRubySignedToken(name, value).ifPresent(v -> signedTokensObjects.add(new MutableSignedToken(value, v)));
});
- paramsToHashMap.forEach((name, value) -> {
- parseRubySignedToken(name, value).ifPresent(v -> signedTokensObjects.add(new MutableSignedToken(value, v)));
+ paramsToHashMap.values().forEach(pairs -> {
+ pairs.forEach((name, value) -> {
+ parseRubySignedToken(name, value).ifPresent(v -> signedTokensObjects.add(new MutableSignedToken(value, v)));
+ });
});
}
if (signerConfig.isEnabled(Signers.UNKNOWN)) {
@@ -109,7 +116,8 @@ public static Set findCandidateUnknownSignedStringWithin(String text) {
public static Optional parseToken(String candidate) {
Optional dst = parseDjangoSignedToken(candidate);
- return dst.isPresent() ? dst : parseDangerousSignedToken(candidate);
+ dst = dst.isPresent() ? dst : parseDangerousSignedToken(candidate);
+ return dst.isPresent() ? dst : parseJSONWebSignature(candidate);
}
private static List parseParameters(List params) {
@@ -120,13 +128,13 @@ private static List parseCookies(List params) {
return parseSignedTokenWithinCookies(params);
}
- private static Map convertParamsToHashMap(List params) {
+ private static Map> convertParamsToHashMap(List params) {
if (params == null) return new HashMap<>();
- return params.stream()
- .collect(Collectors.toMap(
+ return params.stream().collect(Collectors.groupingBy(ParsedHttpParameter::type,
+ Collectors.toMap(
ParsedHttpParameter::name,
- ParsedHttpParameter::value)
- );
+ ParsedHttpParameter::value,
+ (key1, key2) -> key1)));
}
private static Map convertCookiesToHashMap(List cookies) {
@@ -454,7 +462,7 @@ public static Optional parseJSONWebSignature(String text) {
} catch (Exception e) {
return Optional.empty();
}
- SignedToken t = new JSONWebSignature(header, body, signature, new byte[]{(byte) separator});
+ JSONWebSignature t = new JSONWebSignature(header, body, signature, new byte[]{(byte) separator});
return Optional.of(t);
}
diff --git a/src/main/java/one/d4d/sessionless/itsdangerous/model/UnknownSignedToken.java b/src/main/java/one/d4d/sessionless/itsdangerous/model/UnknownSignedToken.java
index 1ad981a..66c9a66 100644
--- a/src/main/java/one/d4d/sessionless/itsdangerous/model/UnknownSignedToken.java
+++ b/src/main/java/one/d4d/sessionless/itsdangerous/model/UnknownSignedToken.java
@@ -1,11 +1,11 @@
package one.d4d.sessionless.itsdangerous.model;
-import burp.config.Signers;
import com.nimbusds.jwt.JWTClaimsSet;
import one.d4d.sessionless.itsdangerous.Algorithms;
import one.d4d.sessionless.itsdangerous.Derivation;
import one.d4d.sessionless.itsdangerous.MessageDerivation;
import one.d4d.sessionless.itsdangerous.MessageDigestAlgorithm;
+import one.d4d.sessionless.itsdangerous.crypto.Signers;
import one.d4d.sessionless.itsdangerous.crypto.TokenSigner;
public class UnknownSignedToken extends SignedToken {
diff --git a/src/main/java/one/d4d/sessionless/presenter/EditorModel.java b/src/main/java/one/d4d/sessionless/presenter/EditorModel.java
index 32ee1cd..af9e182 100644
--- a/src/main/java/one/d4d/sessionless/presenter/EditorModel.java
+++ b/src/main/java/one/d4d/sessionless/presenter/EditorModel.java
@@ -12,9 +12,8 @@
import java.util.concurrent.atomic.AtomicInteger;
class EditorModel {
- private final SignerConfig signerConfig;
private static final String SERIALIZED_OBJECT_FORMAT_STRING = "%d - %s";
-
+ private final SignerConfig signerConfig;
private final List mutableSerializedObjects = new ArrayList<>();
private final Object lock = new Object();
@@ -28,7 +27,7 @@ void setMessage(String content, List cookies, List
synchronized (lock) {
message = content;
mutableSerializedObjects.clear();
- mutableSerializedObjects.addAll(SignedTokenObjectFinder.extractSignedTokenObjects(signerConfig,content,cookies,params));
+ mutableSerializedObjects.addAll(SignedTokenObjectFinder.extractSignedTokenObjects(signerConfig, content, cookies, params));
}
}
diff --git a/src/main/java/one/d4d/sessionless/presenter/EditorPresenter.java b/src/main/java/one/d4d/sessionless/presenter/EditorPresenter.java
index 1edddbf..0ca75f8 100644
--- a/src/main/java/one/d4d/sessionless/presenter/EditorPresenter.java
+++ b/src/main/java/one/d4d/sessionless/presenter/EditorPresenter.java
@@ -177,6 +177,21 @@ private void setRuby(RubySignedToken token) {
view.setRubySeparator(token.getSeparator());
}
+ private JSONWebSignature getJSONWebSignature() {
+ String header = Base64.getUrlEncoder().withoutPadding().encodeToString(view.getJWTHeader().getBytes());
+ String payload = Base64.getUrlEncoder().withoutPadding().encodeToString(view.getJWTPayload().getBytes());
+ String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(view.getJWTSignature());
+ byte[] separator = view.getJWTSeparator().length == 0 ? new byte[]{46} : view.getJWTSeparator();
+ return new JSONWebSignature(header, payload, signature, separator);
+ }
+
+ private void setJSONWebSignature(JSONWebSignature token) {
+ view.setJWTHeader(token.getHeader());
+ view.setJWTPayload(token.getPayload());
+ view.setJWTSignature(token.getSignature());
+ view.setJWTSeparator(token.getSeparator());
+ }
+
private UnknownSignedToken getUnknown() {
String message = view.getUnknownMessage();
String signature = view.getUnknownSignature();
@@ -197,11 +212,12 @@ public void componentChanged() {
SignedToken tokenObject;
switch (view.getMode()) {
- case EditorTab.TAB_DANGEROUSE -> tokenObject = getDangerous();
+ case EditorTab.TAB_DANGEROUS -> tokenObject = getDangerous();
case EditorTab.TAB_EXPRESS -> tokenObject = getExpress();
case EditorTab.TAB_OAUTH -> tokenObject = getOAuth();
case EditorTab.TAB_TORNADO -> tokenObject = getTornado();
case EditorTab.TAB_RUBY -> tokenObject = getRuby();
+ case EditorTab.TAB_JWT -> tokenObject = getJSONWebSignature();
default -> tokenObject = getUnknown();
}
mutableSignedTokenObject.setModified(tokenObject);
@@ -229,6 +245,9 @@ public void onSelectionChanged() {
} else if (tokenObject instanceof RubySignedToken) {
view.setRubyMode();
setRuby((RubySignedToken) tokenObject);
+ } else if (tokenObject instanceof JSONWebSignature) {
+ view.setJWTMode();
+ setJSONWebSignature((JSONWebSignature) tokenObject);
} else if (tokenObject instanceof UnknownSignedToken) {
view.setUnknownMode();
setUnknown((UnknownSignedToken) tokenObject);
@@ -254,7 +273,7 @@ private void attackDialog() {
MutableSignedToken mutableJoseObject = model.getSignedTokenObject(view.getSelectedSignedTokenObjectIndex());
SignedToken tokenObject = mutableJoseObject.getModified();
- if (keysPresenter.getSigningKeys().size() == 0) {
+ if (keysPresenter.getSigningKeys().isEmpty()) {
messageDialogFactory.showWarningDialog("error_title_no_signing_keys", "error_no_signing_keys");
return;
}
@@ -285,6 +304,9 @@ private void attackDialog() {
} else if (signed instanceof RubySignedToken) {
view.setRubyMode();
setRuby((RubySignedToken) signed);
+ } else if (signed instanceof JSONWebSignature) {
+ view.setJWTMode();
+ setJSONWebSignature((JSONWebSignature) signed);
} else if (signed instanceof UnknownSignedToken) {
view.setUnknownMode();
setUnknown((UnknownSignedToken) signed);
@@ -328,6 +350,9 @@ private void signingDialog() {
} else if (signed instanceof RubySignedToken) {
view.setRubyMode();
setRuby((RubySignedToken) signed);
+ } else if (signed instanceof JSONWebSignature) {
+ view.setJWTMode();
+ setJSONWebSignature((JSONWebSignature) signed);
} else if (signed instanceof UnknownSignedToken) {
view.setUnknownMode();
setUnknown((UnknownSignedToken) signed);
@@ -344,17 +369,17 @@ public void onAttackClicked(Attack mode) {
Set attackKeys = keysPresenter.getSecrets();
Set attackSalts = keysPresenter.getSalts();
- if (attackKeys.size() == 0) {
+ if (attackKeys.isEmpty()) {
messageDialogFactory.showWarningDialog("error_title_no_secrets", "error_no_secrets");
return;
}
- if (attackSalts.size() == 0) {
+ if (attackSalts.isEmpty()) {
messageDialogFactory.showWarningDialog("error_title_no_salts", "error_no_salts");
return;
}
- if (keysPresenter.getSigningKeys().size() == 0 && mode == Attack.KNOWN) {
+ if (keysPresenter.getSigningKeys().isEmpty() && mode == Attack.KNOWN) {
messageDialogFactory.showWarningDialog("error_title_no_signing_keys", "error_no_signing_keys");
return;
}
diff --git a/src/main/java/one/d4d/sessionless/utils/Utils.java b/src/main/java/one/d4d/sessionless/utils/Utils.java
index 8634050..c37103c 100644
--- a/src/main/java/one/d4d/sessionless/utils/Utils.java
+++ b/src/main/java/one/d4d/sessionless/utils/Utils.java
@@ -1,13 +1,10 @@
package one.d4d.sessionless.utils;
-import burp.api.montoya.http.message.MimeType;
import com.google.common.primitives.Ints;
import com.google.gson.Gson;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
import org.apache.commons.lang3.StringUtils;
-import org.exbin.deltahex.swing.CodeArea;
-import org.exbin.utils.binary_data.BinaryData;
import java.awt.*;
import java.awt.datatransfer.Clipboard;
@@ -27,7 +24,6 @@
import java.util.zip.Inflater;
public class Utils {
- public static final Set SUPPORTED_MIMETYPES = Set.of(MimeType.HTML, MimeType.PLAIN_TEXT, MimeType.JSON, MimeType.XML, MimeType.YAML);
public static final int BRUTE_FORCE_CHUNK_SIZE = 4096;
public static final int WORDLIST_ONE_CHAR = 256;
public static final int WORDLIST_TWO_CHAR = 65536;
@@ -383,13 +379,6 @@ public static String compactJSON(String json) {
return stringBuilder.toString();
}
- public static byte[] getCodeAreaData(CodeArea codeArea) {
- BinaryData binaryData = codeArea.getData();
- int size = (int) binaryData.getDataSize();
- byte[] data = new byte[size];
- binaryData.copyToArray(0L, data, 0, size);
- return data;
- }
public static Set deserializeFile(File f) {
Set result = new HashSet<>();
diff --git a/src/main/resources/keys b/src/main/resources/keys
new file mode 100644
index 0000000..f082c43
--- /dev/null
+++ b/src/main/resources/keys
@@ -0,0 +1,17 @@
+{"keyId":"Flask","secret":"secret","salt":"salt","separator":".","digestMethod":"1","keyDerivation":"5","messageDerivation":"0","messageDigestAlgorythm":"4"}
+{"keyId":"Django","secret":"secret","salt":"django.contrib.sessions.backends.signed_cookies","separator":":","digestMethod":"1","keyDerivation":"4","messageDerivation":"0","messageDigestAlgorythm":"2"}
+{"keyId":"Express1","secret":"key1","salt":"salt","separator":".","digestMethod":"4","keyDerivation":"2","messageDerivation":"0","messageDigestAlgorythm":"1"}
+{"keyId":"Express2","secret":"key2","salt":"salt","separator":".","digestMethod":"4","keyDerivation":"2","messageDerivation":"0","messageDigestAlgorythm":"1"}
+{"keyId":"ExpressMagic","secret":"magic","salt":"salt","separator":".","digestMethod":"4","keyDerivation":"2","messageDerivation":"0","messageDigestAlgorythm":"1"}
+{"keyId":"OAuth2","secret":"j76h5PEMx3FIGr3caArJ5g\u003d\u003d","salt":"salt","separator":"|","digestMethod":"3","keyDerivation":"1","messageDerivation":"0","messageDigestAlgorythm":"7"}
+{"keyId":"Tornado","secret":"secret","salt":"","separator":"|","digestMethod":"3","keyDerivation":"6","messageDerivation":"0","messageDigestAlgorythm":"7"}
+{"keyId":"JSONWebSignature","secret":"secret","salt":"","separator":".","digestMethod":"3","keyDerivation":"6","messageDerivation":"0","messageDigestAlgorythm":"7"}
+{"keyId":"Ruby","secret":"aeb977de013ade650b97e0aa5246813591104017871a7753fe186e9634c9129b367306606878985c759ca4fddd17d955207011bb855ef01ed414398b4ac8317b","salt":"signed encrypted cookie","separator":"--","digestMethod":"1","keyDerivation":"7","messageDerivation":"0","messageDigestAlgorythm":"7"}
+{"keyId":"Ruby5","secret":"aeb977de013ade650b97e0aa5246813591104017871a7753fe186e9634c9129b367306606878985c759ca4fddd17d955207011bb855ef01ed414398b4ac8317b","salt":"signed encrypted cookie","separator":"--","digestMethod":"1","keyDerivation":"8","messageDerivation":"0","messageDigestAlgorythm":"7"}
+{"keyId":"RubyTruncated","secret":"aeb977de013ade650b97e0aa5246813591104017871a7753fe186e9634c9129b367306606878985c759ca4fddd17d955207011bb855ef01ed414398b4ac8317b","salt":"signed encrypted cookie","separator":"--","digestMethod":"1","keyDerivation":"9","messageDerivation":"0","messageDigestAlgorythm":"7"}
+{"keyId":"Superset","secret":"thisISaSECRET_1234","salt":"cookie-session","separator":".","digestMethod":"1","keyDerivation":"5","messageDerivation":"0","messageDigestAlgorythm":"4"}
+{"keyId":"Superset2","secret":"CHANGE_ME_TO_A_COMPLEX_RANDOM_SECRET","salt":"cookie-session","separator":".","digestMethod":"1","keyDerivation":"5","messageDerivation":"0","messageDigestAlgorythm":"4"}
+{"keyId":"Superset3","secret":"YOUR_OWN_RANDOM_GENERATED_SECRET_KEY","salt":"cookie-session","separator":".","digestMethod":"1","keyDerivation":"5","messageDerivation":"0","messageDigestAlgorythm":"4"}
+{"keyId":"Superset4","secret":"TEST_NON_DEV_SECRET","salt":"cookie-session","separator":".","digestMethod":"1","keyDerivation":"5","messageDerivation":"0","messageDigestAlgorythm":"4"}
+{"keyId":"Superset5","secret":"\u0002\u0001thisismyscretkey\u0001\u0002\\e\\y\\y\\h","salt":"cookie-session","separator":".","digestMethod":"1","keyDerivation":"5","messageDerivation":"0","messageDigestAlgorythm":"4"}
+{"keyId":"Redash","secret":"c292a0a3aa32397cdb050e233733900f","salt":"cookie-session","separator":".","digestMethod":"1","keyDerivation":"5","messageDerivation":"0","messageDigestAlgorythm":"4"}
diff --git a/src/main/resources/secrets b/src/main/resources/secrets
index 58469bd..17c5cfe 100644
--- a/src/main/resources/secrets
+++ b/src/main/resources/secrets
@@ -29,6 +29,8 @@
"!payment$ecret!"
"!secReT$123*"
"#######"
+"keys"
+"keykeys"
"#$Vby8o5ey+vbaio7vzw63v)273eyowhsukdt36iwu"
"#RwwwWXXUu!pPMG^AtWhDbXh?2qXum@CGqaAF8QaYfnqMyh+r#_Eu!RQ&zftFucDf5BH#7%!&bVfQAVJxP3b-?tEvdmHBNxK!LgjW!ekeG9AP^=gcM"
"#ZhiMaKaiMen1234@*"
diff --git a/src/main/resources/strings.properties b/src/main/resources/strings.properties
index 132bb4b..0dc8487 100644
--- a/src/main/resources/strings.properties
+++ b/src/main/resources/strings.properties
@@ -101,4 +101,9 @@ new_word_item_label=New item
ruby_tab_label=Ruby
ruby_message_label=Message
ruby_signature_label=Signature
-ruby_separator_label=Separator
\ No newline at end of file
+ruby_separator_label=Separator
+jsonwebsignature_tab_label=JWT
+jsonwebsignature_header_label=Header
+jsonwebsignature_payload_label=Payload
+jsonwebsignature_label=Signature
+jsonwebsignature_separator_label=Separator
\ No newline at end of file
diff --git a/src/test/java/ExpressSignedCookieTest.java b/src/test/java/ExpressSignedCookieTest.java
index 4c3c924..0348b9a 100644
--- a/src/test/java/ExpressSignedCookieTest.java
+++ b/src/test/java/ExpressSignedCookieTest.java
@@ -1,15 +1,16 @@
import burp.api.montoya.http.message.Cookie;
+import one.d4d.sessionless.itsdangerous.Attack;
+import one.d4d.sessionless.itsdangerous.BruteForce;
import one.d4d.sessionless.itsdangerous.crypto.ExpressTokenSigner;
import one.d4d.sessionless.itsdangerous.model.ExpressSignedToken;
import one.d4d.sessionless.itsdangerous.model.MutableSignedToken;
import one.d4d.sessionless.itsdangerous.model.SignedTokenObjectFinder;
+import one.d4d.sessionless.keys.SecretKey;
import one.d4d.sessionless.utils.TestCookie;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
+import java.util.*;
public class ExpressSignedCookieTest {
@Test
@@ -26,15 +27,23 @@ void OauthProxyParserTest() {
cookies.add(payloadCookie);
cookies.add(signatureCookie);
Assertions.assertDoesNotThrow(() -> {
- Optional token =
+ Optional optionalSignedToken =
SignedTokenObjectFinder.parseSignedTokenWithinCookies(cookies)
.stream()
.map(MutableSignedToken::getModified)
.map(ExpressSignedToken.class::cast)
.findFirst();
- if (token.isPresent()) {
- token.get().setSigner(s);
- token.get().unsign();
+ if (optionalSignedToken.isPresent()) {
+ ExpressSignedToken token = optionalSignedToken.get();
+ token.setSigner(s);
+ token.unsign();
+ final Set secrets = new HashSet<>(List.of("key1"));
+ final Set salts = new HashSet<>(List.of("salt"));
+ final List knownKeys = new ArrayList<>();
+
+ BruteForce bf = new BruteForce(secrets, salts, knownKeys, Attack.Balanced, token);
+ SecretKey sk = bf.parallel();
+ Assertions.assertNotNull(sk);
} else throw new Exception("Missed cookie");
});
}