├── .gitignore
├── settings.gradle.kts
├── Makefile
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── BappManifest.bmf
├── src
└── main
│ └── java
│ └── beanstack
│ ├── GlobalVars.java
│ ├── Config.java
│ ├── BurpExtender.java
│ └── Blake2b.java
├── BappDescription.html
├── README.md
├── gradlew.bat
├── gradlew
└── LICENSE
/.gitignore:
--------------------------------------------------------------------------------
1 | build/
2 | .gradle/
3 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | rootProject.name = "beanstack"
2 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | default:
2 | gradle build
3 | @echo output is in build/libs/*.jar
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PortSwigger/beanstack-stacktrace-fingerprinter/master/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/BappManifest.bmf:
--------------------------------------------------------------------------------
1 | Uuid: 2da0e069b2944fcab691f6d00b165078
2 | ExtensionType: 1
3 | Name: BeanStack - Stack-trace Fingerprinter
4 | RepoName: beanstack-stacktrace-fingerprinter
5 | ScreenVersion: 0.7.0
6 | SerialVersion: 6
7 | MinPlatformVersion: 2
8 | ProOnly: True
9 | Author: BeanStack
10 | ShortDescription: Java Fingerprinting using Stack Traces.
11 | EntryPoint: beanstack.jar
12 | BuildCommand: ./gradlew build
13 | SupportedProducts: Pro
14 |
--------------------------------------------------------------------------------
/src/main/java/beanstack/GlobalVars.java:
--------------------------------------------------------------------------------
1 | package beanstack;
2 |
3 | import burp.IBurpExtenderCallbacks;
4 |
5 | class GlobalVars {
6 | /* We're all hackers: if you want to hack on this client, that's great!
7 | * Just include an accurate user agent (there is no UA checking, it only
8 | * ends up in our logs, so we can talk to you if there are issues).
9 | * If you did not coordinate the release with us, please include something
10 | * by which we can reach you in case of problems, or if, for example, our
11 | * API is going to change.
12 | */
13 | public static final String USER_AGENT = "X41-BeanStack-BApp";
14 |
15 | public static final String EXTENSION_NAME = "X41 BeanStack";
16 | public static final String EXTENSION_NAME_SHORT = "BeanStack";
17 | public static final String VERSION = "0.7.0";
18 | public static final String REGURL = "https://beanstack.io";
19 | public static final String SETTINGDOCURL = "https://beanstack.io/settings.html";
20 | public static final String CVEURL = "https://nvd.nist.gov/vuln/detail/";
21 | public static final String SETTINGS = "Settings";
22 | public static final int SLEEP_DURATION = 100; // ms
23 | public static final int SLEEP_MAXTIME = 15; // s
24 |
25 | public static IBurpExtenderCallbacks callbacks;
26 | public static beanstack.Config config;
27 | public static java.io.PrintStream debug = System.out;
28 |
29 | public static void debug(Object o) {
30 | if (GlobalVars.config.getBoolean("debug")) {
31 | GlobalVars.debug.print(new java.text.SimpleDateFormat("HH:mm:ss").format(java.util.Calendar.getInstance().getTime()) + " ");
32 | GlobalVars.debug.println(o);
33 | }
34 | }
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/BappDescription.html:
--------------------------------------------------------------------------------
1 |
2 | This extension automatically identifies Java frameworks and libraries by analyzing stack traces found in HTTP
3 | responses. It sends stack traces to the BeanStack API for fingerprinting and reports identified versions along with
4 | associated CVEs directly in the Burp Suite dashboard.
5 |
6 |
7 |
8 | Note: This extension sends potentially private stack traces to a third-party service (beanstack.io)
9 | for processing.
10 |
11 |
12 | Features
13 |
14 | Automatically detects Java stack traces in proxy traffic and API responses
15 | Identifies specific versions of frameworks and libraries from stack trace patterns
16 | Reports known CVEs with CVSS scores for identified versions (requires free API key)
17 | Creates scan issues organized by product or optionally by individual CVE
18 | Supports privacy-enhanced mode that hashes stack traces before submission
19 | Configurable class prefix blacklist to exclude internal or sensitive traces
20 |
21 |
22 | Usage
23 |
24 | Browse to a website that displays Java stack traces through the Burp proxy
25 | The extension automatically detects stack traces in HTTP responses
26 | View fingerprinting results as scan issues in the Dashboard or Target tab
27 | Optional: Register for a free API key at beanstack.io to enable CVE detection
29 | Optional: Configure settings via the BeanStack menu or right-click context menu in the Issues list
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # X41 BeanStack (beta)
2 |
3 | *Java Fingerprinting using Stack Traces*
4 |
5 |
6 |
7 |
8 | ## Installing the Burp Extension
9 |
10 | The easiest way is to download *BeanStack* from the BApp Store, which can be found in your Burp Suite under the Extender tab.
11 |
12 | Alternatively, you can download [the latest release](https://github.com/x41sec/BeanStack/releases/latest)
13 | from this GitHub repository, or use your own build from `build/libs/beanstack.jar`. To install the jar:
14 |
15 | 1. Launch Burp
16 | 1. Create a temporary project or select a new/existing one
17 | 1. Open the Extender tab
18 | 1. Open the Extensions subtab
19 | 1. Click the Add button
20 | 1. Select the `jar` file
21 | 1. Leave all options as default, click "next", and finish the wizard
22 |
23 |
24 |
25 |
26 | ## Extension Usage
27 |
28 | Browse to a website with a nice stack trace (such as [beanstack.io](https://beanstack.io))
29 | and make sure the response passes through the Burp proxy. It should
30 | automatically be picked up, query the API (in the background), and produce an
31 | "Issue" in the Dashboard or Target tab.
32 |
33 |
34 |
35 |
36 | ## Building From Source
37 |
38 | Dependencies:
39 |
40 | apt install gradle default-jdk-headless
41 |
42 | Note that for ancient versions of Gradle (pre-3.4, Feb 2017), you will need to
43 | remove the bottom paragraph from `build.gradle`. Your version of Gradle cannot
44 | produce reproducible builds.
45 |
46 | Build:
47 |
48 | make
49 |
50 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 | @rem SPDX-License-Identifier: Apache-2.0
17 | @rem
18 |
19 | @if "%DEBUG%"=="" @echo off
20 | @rem ##########################################################################
21 | @rem
22 | @rem Gradle startup script for Windows
23 | @rem
24 | @rem ##########################################################################
25 |
26 | @rem Set local scope for the variables with windows NT shell
27 | if "%OS%"=="Windows_NT" setlocal
28 |
29 | set DIRNAME=%~dp0
30 | if "%DIRNAME%"=="" set DIRNAME=.
31 | @rem This is normally unused
32 | set APP_BASE_NAME=%~n0
33 | set APP_HOME=%DIRNAME%
34 |
35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
37 |
38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
40 |
41 | @rem Find java.exe
42 | if defined JAVA_HOME goto findJavaFromJavaHome
43 |
44 | set JAVA_EXE=java.exe
45 | %JAVA_EXE% -version >NUL 2>&1
46 | if %ERRORLEVEL% equ 0 goto execute
47 |
48 | echo. 1>&2
49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
50 | echo. 1>&2
51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
52 | echo location of your Java installation. 1>&2
53 |
54 | goto fail
55 |
56 | :findJavaFromJavaHome
57 | set JAVA_HOME=%JAVA_HOME:"=%
58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
59 |
60 | if exist "%JAVA_EXE%" goto execute
61 |
62 | echo. 1>&2
63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
64 | echo. 1>&2
65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
66 | echo location of your Java installation. 1>&2
67 |
68 | goto fail
69 |
70 | :execute
71 | @rem Setup the command line
72 |
73 |
74 |
75 | @rem Execute Gradle
76 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
77 |
78 | :end
79 | @rem End local scope for the variables with windows NT shell
80 | if %ERRORLEVEL% equ 0 goto mainEnd
81 |
82 | :fail
83 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
84 | rem the _cmd.exe /c_ return code!
85 | set EXIT_CODE=%ERRORLEVEL%
86 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
87 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
88 | exit /b %EXIT_CODE%
89 |
90 | :mainEnd
91 | if "%OS%"=="Windows_NT" endlocal
92 |
93 | :omega
94 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015 the original authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 | # SPDX-License-Identifier: Apache-2.0
19 | #
20 |
21 | ##############################################################################
22 | #
23 | # Gradle start up script for POSIX generated by Gradle.
24 | #
25 | # Important for running:
26 | #
27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
28 | # noncompliant, but you have some other compliant shell such as ksh or
29 | # bash, then to run this script, type that shell name before the whole
30 | # command line, like:
31 | #
32 | # ksh Gradle
33 | #
34 | # Busybox and similar reduced shells will NOT work, because this script
35 | # requires all of these POSIX shell features:
36 | # * functions;
37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
39 | # * compound commands having a testable exit status, especially «case»;
40 | # * various built-in commands including «command», «set», and «ulimit».
41 | #
42 | # Important for patching:
43 | #
44 | # (2) This script targets any POSIX shell, so it avoids extensions provided
45 | # by Bash, Ksh, etc; in particular arrays are avoided.
46 | #
47 | # The "traditional" practice of packing multiple parameters into a
48 | # space-separated string is a well documented source of bugs and security
49 | # problems, so this is (mostly) avoided, by progressively accumulating
50 | # options in "$@", and eventually passing that to Java.
51 | #
52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
54 | # see the in-line comments for details.
55 | #
56 | # There are tweaks for specific operating systems such as AIX, CygWin,
57 | # Darwin, MinGW, and NonStop.
58 | #
59 | # (3) This script is generated from the Groovy template
60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
61 | # within the Gradle project.
62 | #
63 | # You can find Gradle at https://github.com/gradle/gradle/.
64 | #
65 | ##############################################################################
66 |
67 | # Attempt to set APP_HOME
68 |
69 | # Resolve links: $0 may be a link
70 | app_path=$0
71 |
72 | # Need this for daisy-chained symlinks.
73 | while
74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
75 | [ -h "$app_path" ]
76 | do
77 | ls=$( ls -ld "$app_path" )
78 | link=${ls#*' -> '}
79 | case $link in #(
80 | /*) app_path=$link ;; #(
81 | *) app_path=$APP_HOME$link ;;
82 | esac
83 | done
84 |
85 | # This is normally unused
86 | # shellcheck disable=SC2034
87 | APP_BASE_NAME=${0##*/}
88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
90 |
91 | # Use the maximum available, or set MAX_FD != -1 to use that value.
92 | MAX_FD=maximum
93 |
94 | warn () {
95 | echo "$*"
96 | } >&2
97 |
98 | die () {
99 | echo
100 | echo "$*"
101 | echo
102 | exit 1
103 | } >&2
104 |
105 | # OS specific support (must be 'true' or 'false').
106 | cygwin=false
107 | msys=false
108 | darwin=false
109 | nonstop=false
110 | case "$( uname )" in #(
111 | CYGWIN* ) cygwin=true ;; #(
112 | Darwin* ) darwin=true ;; #(
113 | MSYS* | MINGW* ) msys=true ;; #(
114 | NONSTOP* ) nonstop=true ;;
115 | esac
116 |
117 |
118 |
119 | # Determine the Java command to use to start the JVM.
120 | if [ -n "$JAVA_HOME" ] ; then
121 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
122 | # IBM's JDK on AIX uses strange locations for the executables
123 | JAVACMD=$JAVA_HOME/jre/sh/java
124 | else
125 | JAVACMD=$JAVA_HOME/bin/java
126 | fi
127 | if [ ! -x "$JAVACMD" ] ; then
128 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
129 |
130 | Please set the JAVA_HOME variable in your environment to match the
131 | location of your Java installation."
132 | fi
133 | else
134 | JAVACMD=java
135 | if ! command -v java >/dev/null 2>&1
136 | then
137 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
138 |
139 | Please set the JAVA_HOME variable in your environment to match the
140 | location of your Java installation."
141 | fi
142 | fi
143 |
144 | # Increase the maximum file descriptors if we can.
145 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
146 | case $MAX_FD in #(
147 | max*)
148 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
149 | # shellcheck disable=SC2039,SC3045
150 | MAX_FD=$( ulimit -H -n ) ||
151 | warn "Could not query maximum file descriptor limit"
152 | esac
153 | case $MAX_FD in #(
154 | '' | soft) :;; #(
155 | *)
156 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
157 | # shellcheck disable=SC2039,SC3045
158 | ulimit -n "$MAX_FD" ||
159 | warn "Could not set maximum file descriptor limit to $MAX_FD"
160 | esac
161 | fi
162 |
163 | # Collect all arguments for the java command, stacking in reverse order:
164 | # * args from the command line
165 | # * the main class name
166 | # * -classpath
167 | # * -D...appname settings
168 | # * --module-path (only if needed)
169 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
170 |
171 | # For Cygwin or MSYS, switch paths to Windows format before running java
172 | if "$cygwin" || "$msys" ; then
173 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
174 |
175 | JAVACMD=$( cygpath --unix "$JAVACMD" )
176 |
177 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
178 | for arg do
179 | if
180 | case $arg in #(
181 | -*) false ;; # don't mess with options #(
182 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
183 | [ -e "$t" ] ;; #(
184 | *) false ;;
185 | esac
186 | then
187 | arg=$( cygpath --path --ignore --mixed "$arg" )
188 | fi
189 | # Roll the args list around exactly as many times as the number of
190 | # args, so each arg winds up back in the position where it started, but
191 | # possibly modified.
192 | #
193 | # NB: a `for` loop captures its iteration list before it begins, so
194 | # changing the positional parameters here affects neither the number of
195 | # iterations, nor the values presented in `arg`.
196 | shift # remove old arg
197 | set -- "$@" "$arg" # push replacement arg
198 | done
199 | fi
200 |
201 |
202 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
203 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
204 |
205 | # Collect all arguments for the java command:
206 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
207 | # and any embedded shellness will be escaped.
208 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
209 | # treated as '${Hostname}' itself on the command line.
210 |
211 | set -- \
212 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
213 | -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
214 | "$@"
215 |
216 | # Stop when "xargs" is not available.
217 | if ! command -v xargs >/dev/null 2>&1
218 | then
219 | die "xargs is not available"
220 | fi
221 |
222 | # Use "xargs" to parse quoted args.
223 | #
224 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
225 | #
226 | # In Bash we could simply go:
227 | #
228 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
229 | # set -- "${ARGS[@]}" "$@"
230 | #
231 | # but POSIX shell has neither arrays nor command substitution, so instead we
232 | # post-process each arg (as a line of input to sed) to backslash-escape any
233 | # character that might be a shell metacharacter, then use eval to reverse
234 | # that process (while maintaining the separation between arguments), and wrap
235 | # the whole thing up as a single "set" statement.
236 | #
237 | # This will of course break if any of these variables contains a newline or
238 | # an unmatched quote.
239 | #
240 |
241 | eval "set -- $(
242 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
243 | xargs -n1 |
244 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
245 | tr '\n' ' '
246 | )" '"$@"'
247 |
248 | exec "$JAVACMD" "$@"
249 |
--------------------------------------------------------------------------------
/src/main/java/beanstack/Config.java:
--------------------------------------------------------------------------------
1 | // Code taken from https://github.com/PortSwigger/distribute-damage/blob/866eb5a42e455a52b9d9fe553d0bd6527b86b72b/src/burp/Utilities.java
2 | // License: Apache2
3 |
4 | //Copyright 2016 PortSwigger Web Security
5 | //Copyright 2016 James Kettle
6 |
7 | package beanstack;
8 |
9 | import burp.IContextMenuFactory;
10 | import burp.IContextMenuInvocation;
11 |
12 | import javax.swing.*;
13 | import javax.swing.text.NumberFormatter;
14 | import java.awt.*;
15 | import java.awt.event.ActionEvent;
16 | import java.awt.event.ActionListener;
17 | import java.io.IOException;
18 | import java.text.NumberFormat;
19 | import java.util.ArrayList;
20 | import java.util.HashMap;
21 | import java.util.LinkedHashMap;
22 | import java.util.List;
23 |
24 | // ###########################################################################
25 | // The class that actually holds the config
26 | // ###########################################################################
27 | public class Config {
28 | private LinkedHashMap settings;
29 | private LinkedHashMap readableNames;
30 | private NumberFormatter onlyInt;
31 |
32 | public Config() {
33 | settings = new LinkedHashMap<>();
34 | // These put()s determine the order shown on the settings screen
35 | // Note that the default values are documented on the website, so update accordingly
36 | put("enable", true);
37 | put("apikey", "none");
38 | put("classblacklist", "");
39 | put("hashtrace", true);
40 | put("issuepercve", false);
41 | put("sizelimit", 25);
42 | put("debug", false);
43 | put("logdups", false);
44 | put("issuetitle", "Stack Trace Fingerprint Found");
45 | put("apiurl", "https://beanstack.io/api/");
46 |
47 | // NOTE: when editing these names, also update the documentation!
48 | readableNames = new LinkedHashMap<>();
49 | readableNames.put("enable", "Enable Lookups");
50 | readableNames.put("apiurl", "API URL");
51 | readableNames.put("issuetitle", "Issue Title");
52 | readableNames.put("debug", "Print Debug Messages to Stdout");
53 | readableNames.put("logdups", "Log Duplicates");
54 | readableNames.put("apikey", "API Key");
55 | readableNames.put("classblacklist", "Blacklisted Class Prefixes");
56 | readableNames.put("issuepercve", "Create an Issue for Each CVE*");
57 | readableNames.put("hashtrace", "Hash Traces before Submission*");
58 | readableNames.put("sizelimit", "Response Size Limit (RAM)");
59 |
60 | for (String key: settings.keySet()) {
61 | //callbacks.saveExtensionSetting(key, null); // purge saved settings
62 | String value = GlobalVars.callbacks.loadExtensionSetting(key);
63 | if (GlobalVars.callbacks.loadExtensionSetting(key) != null) {
64 | putRaw(key, value);
65 | }
66 | }
67 |
68 | NumberFormat format = NumberFormat.getInstance();
69 | onlyInt = new NumberFormatter(format);
70 | onlyInt.setValueClass(Integer.class);
71 | onlyInt.setMinimum(-1);
72 | onlyInt.setMaximum(Integer.MAX_VALUE);
73 | onlyInt.setAllowsInvalid(false);
74 | }
75 |
76 | private Config(Config base) {
77 | settings = new LinkedHashMap<>(base.settings);
78 | onlyInt = base.onlyInt;
79 | }
80 |
81 | void printSettings() {
82 | GlobalVars.debug("printSettings():");
83 | for(String key: settings.keySet()) {
84 | GlobalVars.debug(" - " + getType(key) + " " + key + " = " + settings.get(key));
85 | }
86 | }
87 |
88 | public static JFrame getBurpFrame()
89 | {
90 | for(Frame f : Frame.getFrames())
91 | {
92 | if(f.isVisible() && f.getTitle().startsWith(("Burp Suite")))
93 | {
94 | return (JFrame) f;
95 | }
96 | }
97 | return null;
98 | }
99 |
100 | private String encode(Object value) {
101 | String encoded;
102 | if (value instanceof Boolean) {
103 | encoded = String.valueOf(value);
104 | }
105 | else if (value instanceof Integer) {
106 | encoded = String.valueOf(value);
107 | }
108 | else {
109 | encoded = "\"" + ((String) value).replace("\\", "\\\\").replace("\"", "\\\"") + "\"";
110 | }
111 | return encoded;
112 | }
113 |
114 | private void putRaw(String key, String value) {
115 | settings.put(key, value);
116 | }
117 |
118 | private void put(String key, Object value) {
119 | settings.put(key, encode(value));
120 | }
121 |
122 | public void putAndSave(String key, Object value) {
123 | settings.put(key, encode(value));
124 | GlobalVars.callbacks.saveExtensionSetting(key, encode(value));
125 | }
126 |
127 | public String getString(String key) {
128 | String decoded = settings.get(key);
129 | decoded = decoded.substring(1, decoded.length()-1).replace("\\\"", "\"").replace("\\\\", "\\");
130 | return decoded;
131 | }
132 |
133 | public int getInt(String key) {
134 | return Integer.parseInt(settings.get(key));
135 | }
136 |
137 | public boolean getBoolean(String key) {
138 | String val = settings.get(key);
139 | if (val.equals("true") ) {
140 | return true;
141 | }
142 | else if (val.equals("false")){
143 | return false;
144 | }
145 | throw new RuntimeException();
146 | }
147 |
148 | String getType(String key) {
149 | String val = settings.get(key);
150 | if (val.equals("true") || val.equals("false")) {
151 | return "boolean";
152 | }
153 | else if (val.startsWith("\"")) {
154 | return "string";
155 | }
156 | else {
157 | return "number";
158 | }
159 | }
160 |
161 | void showSettings() {
162 | JPanel panel = new JPanel();
163 | panel.setLayout(new GridLayout(0, 2));
164 |
165 | JLabel lbl = new JLabel("" + GlobalVars.EXTENSION_NAME_SHORT + " settings (documentation )");
166 | lbl.putClientProperty("html.disable", null);
167 | lbl.setCursor(new Cursor(Cursor.HAND_CURSOR));
168 | panel.add(lbl);
169 |
170 | lbl.addMouseListener(new java.awt.event.MouseAdapter() {
171 | @Override public void mousePressed(java.awt.event.MouseEvent ev) {
172 | try {
173 | java.awt.Desktop.getDesktop().browse(new java.net.URI(GlobalVars.SETTINGDOCURL));
174 | }
175 | catch (IOException|java.net.URISyntaxException e) {
176 | e.printStackTrace();
177 | }
178 | }
179 | });
180 |
181 | panel.add(new JLabel());
182 |
183 | HashMap configured = new HashMap<>();
184 |
185 | for(String key: settings.keySet()) {
186 | String type = getType(key);
187 | panel.add(new JLabel("\n" + readableNames.get(key) + ": "));
188 |
189 | if (type.equals("boolean")) {
190 | JCheckBox box = new JCheckBox();
191 | box.setSelected(getBoolean(key));
192 | panel.add(box);
193 | configured.put(key, box);
194 | }
195 | else if (type.equals("number")){
196 | JTextField box = new JFormattedTextField(onlyInt);
197 | box.setText(String.valueOf(getInt(key)));
198 | panel.add(box);
199 | configured.put(key, box);
200 | }
201 | else {
202 | JTextField box = new JTextField(getString(key));
203 | panel.add(box);
204 | configured.put(key, box);
205 | }
206 | }
207 |
208 | panel.add(new JLabel("\n* Only available with an API key"));
209 | panel.add(new JLabel());
210 |
211 | int result = JOptionPane.showConfirmDialog(getBurpFrame(), panel, GlobalVars.EXTENSION_NAME + " settings", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
212 | if (result == JOptionPane.OK_OPTION) {
213 | for(String key: configured.keySet()) {
214 | Object val = configured.get(key);
215 | if (val instanceof JCheckBox) {
216 | val = ((JCheckBox) val).isSelected();
217 | }
218 | else if (val instanceof JFormattedTextField) {
219 | val = Integer.parseInt(((JFormattedTextField) val).getText().replace(",", ""));
220 | }
221 | else {
222 | val = ((JTextField) val).getText();
223 | if (key.equals("apiurl") && ! ((String)val).endsWith("/")) {
224 | val += "/";
225 | }
226 | }
227 | put(key, val);
228 | GlobalVars.callbacks.saveExtensionSetting(key, encode(val));
229 | }
230 |
231 | GlobalVars.debug("Saved settings.");
232 | printSettings();
233 | }
234 | else {
235 | GlobalVars.debug("Settings cancelled.");
236 | }
237 | }
238 | }
239 |
240 | // ###########################################################################
241 | // Class to add context menu (right click menu) actions and handle them
242 | // ###########################################################################
243 | class ContextMenuSettingsOptionAdder implements IContextMenuFactory, ActionListener {
244 | @Override
245 | public List createMenuItems(IContextMenuInvocation invocation) {
246 | ContextMenuSettingsOptionAdder outer = this;
247 | // 16 is an undocumented magic number that indicates it was invoked
248 | // from the Issues list in the Target tab. The place where our events
249 | // are logged, so that seemed a logical place for the options button.
250 | // The number was reverse engineered using the highly advanced method
251 | // of println()ing getToolFlag and right clicking the desired place.
252 | return invocation.getToolFlag() == 16 ? new ArrayList() {{
253 | add(new JMenuItem(GlobalVars.EXTENSION_NAME_SHORT + " settings") {{
254 | addActionListener(outer);
255 | }});
256 | }} : null;
257 | }
258 |
259 | public void actionPerformed(ActionEvent e) {
260 | SwingUtilities.invokeLater(new Runnable() {
261 | public void run(){
262 | GlobalVars.config.showSettings();
263 | }
264 | });
265 | }
266 | }
267 |
268 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/src/main/java/beanstack/BurpExtender.java:
--------------------------------------------------------------------------------
1 | package beanstack;
2 |
3 | import burp.*;
4 | import com.fasterxml.jackson.core.type.TypeReference;
5 | import com.fasterxml.jackson.databind.ObjectMapper;
6 |
7 | import javax.swing.*;
8 | import java.io.IOException;
9 | import java.net.URI;
10 | import java.net.URISyntaxException;
11 | import java.net.URL;
12 | import java.nio.ByteBuffer;
13 | import java.nio.charset.StandardCharsets;
14 | import java.time.Duration;
15 | import java.time.Instant;
16 | import java.util.*;
17 | import java.util.concurrent.ExecutorService;
18 | import java.util.concurrent.Executors;
19 | import java.util.concurrent.TimeUnit;
20 | import java.util.regex.Matcher;
21 | import java.util.regex.Pattern;
22 |
23 | public class BurpExtender implements IBurpExtender, IHttpListener, IExtensionStateListener {
24 | // Dictionary mapping request body hashes to response bodies
25 | private Map HttpReqMemoization;
26 |
27 | // Hashes of issues to avoid duplicates
28 | private Set AlreadyFingerprinted;
29 |
30 | // Background thread that does the lookups
31 | private ExecutorService threader;
32 |
33 | final Blake2b blake2b = Blake2b.Digest.newInstance(16);
34 |
35 | private boolean showed429AlertWithApiKey = false;
36 | private boolean showed429Alert = false;
37 |
38 | final String htmlindent = " ";
39 | final String CRLF = "\r\n";
40 | final String hexchars = "0123456789abcdefABCDEF";
41 |
42 | @Override
43 | public void registerExtenderCallbacks(final IBurpExtenderCallbacks callbacks) {
44 | GlobalVars.callbacks = callbacks;
45 |
46 | GlobalVars.callbacks.setExtensionName(GlobalVars.EXTENSION_NAME);
47 | GlobalVars.callbacks.registerHttpListener(this);
48 | GlobalVars.callbacks.registerExtensionStateListener(this);
49 |
50 | this.AlreadyFingerprinted = new HashSet();
51 | this.HttpReqMemoization = new HashMap();
52 |
53 | this.threader = Executors.newSingleThreadExecutor();
54 |
55 | GlobalVars.config = new Config();
56 | GlobalVars.config.printSettings();
57 |
58 | GlobalVars.callbacks.registerContextMenuFactory(new ContextMenuSettingsOptionAdder());
59 |
60 | // Check if we already checked this URL
61 | IScanIssue[] issuelist = GlobalVars.callbacks.getScanIssues("");
62 |
63 | if (issuelist == null) {
64 | JOptionPane.showMessageDialog(null,
65 | "Error loading scan issues. Unfortunately, this extension\nuses features only available in Burp Pro.",
66 | "Burp Extension " + GlobalVars.EXTENSION_NAME,
67 | JOptionPane.ERROR_MESSAGE
68 | );
69 | return;
70 | }
71 |
72 | for (IScanIssue si : issuelist) {
73 | // Only add fingerprinting items
74 | if (si.getIssueName().equals(GlobalVars.config.getString("issuetitle"))) {
75 | AlreadyFingerprinted.add(hashScanIssue(si));
76 | }
77 | }
78 | GlobalVars.debug("Found " + AlreadyFingerprinted.size() + " fingerprints in already-existing issues (to avoid creating duplicate issues).");
79 |
80 | threader.submit(new Runnable() {
81 | public void run() {
82 | int timeSlept = 0;
83 | while (Config.getBurpFrame().getJMenuBar() == null) {
84 | if (timeSlept > GlobalVars.SLEEP_MAXTIME * 1000) {
85 | GlobalVars.debug("Sleeper timed out. Here be dragons.");
86 | break;
87 | }
88 |
89 | try { java.lang.Thread.sleep(GlobalVars.SLEEP_DURATION); } catch (java.lang.InterruptedException e) { break; }
90 | GlobalVars.debug("Sleeping " + GlobalVars.SLEEP_DURATION + "ms before adding " + GlobalVars.EXTENSION_NAME_SHORT + " menu button because Burp's menu bar UI does not yet exist...");
91 | timeSlept += GlobalVars.SLEEP_DURATION;
92 | }
93 | SwingUtilities.invokeLater(new BeanstackMenu());
94 | }
95 | });
96 | }
97 |
98 | @Override
99 | public void extensionUnloaded() {
100 | GlobalVars.debug("Extension unloading: shutting down thread pool...");
101 | if (threader != null) {
102 | threader.shutdownNow();
103 |
104 | try {
105 | if (!threader.awaitTermination(5, TimeUnit.SECONDS)) {
106 | GlobalVars.debug("Thread pool did not terminate within timeout.");
107 | }
108 | } catch (InterruptedException e) {
109 | Thread.currentThread().interrupt();
110 | }
111 |
112 | threader = null;
113 | }
114 | }
115 |
116 | private String cvssToBurpSeverity(float cvss) {
117 | // Based on https://www.first.org/cvss/specification-document#5-Qualitative-Severity-Rating-Scale
118 | if (cvss < 4.0f) return "Information";
119 | if (cvss < 7.0f) return "Low";
120 | if (cvss < 9.0f) return "Medium";
121 | return "High";
122 | }
123 |
124 | private ByteBuffer hashScanIssue(IScanIssue si) {
125 | return ByteBuffer.wrap(blake2b.digest((si.getUrl().toString() + "\n" + si.getIssueDetail()).getBytes()));
126 | }
127 |
128 | private byte[] buildHttpRequest(String host, String URI, String method, String body) {
129 | String headers = "";
130 | headers += "User-Agent: " + GlobalVars.USER_AGENT + "/" + GlobalVars.VERSION + CRLF;
131 | if (method.equals("POST")) {
132 | headers += "Content-Type: application/x-www-form-urlencoded\r\n";
133 | headers += "Content-Length: " + body.length() + CRLF;
134 | }
135 | return (method + " " + URI + " HTTP/1.1\r\nHost: " + host + CRLF + headers + CRLF + body).getBytes();
136 | }
137 |
138 | private SHR parseHttpResponse(byte[] response) {
139 | String[] headersbody = new String(response).split("\r\n\r\n", 2);
140 | String[] headers = headersbody[0].split(CRLF);
141 | Map headermap = new HashMap<>();
142 | for (String header : headers) {
143 | if (Objects.equals(header, headers[0])) continue; // Skip first: that's the status line
144 | String[] nameval = header.split(":", 2);
145 | headermap.put(nameval[0].toLowerCase().trim(), nameval[1].trim());
146 | }
147 | String[] methodcodestatus = headers[0].split(" ", 3);
148 |
149 | int status = Integer.parseInt(methodcodestatus[1]);
150 | return new SHR(status, headermap, headersbody[1]);
151 | }
152 |
153 | private String url2uri(URL url) {
154 | return (url.getPath() != null ? url.getPath() : "")
155 | + (url.getQuery() != null ? url.getQuery() : "");
156 | }
157 |
158 | private boolean isBlacklisted(String stacktraceline) {
159 | String[] blacklisted_class_prefixes = GlobalVars.config.getString("classblacklist").split(",");
160 | for (String blacklisted_class_prefix : blacklisted_class_prefixes) {
161 | if (blacklisted_class_prefix.length() < 3) {
162 | continue;
163 | }
164 | if (stacktraceline.contains(blacklisted_class_prefix)) {
165 | return true;
166 | }
167 | }
168 |
169 | return false;
170 | }
171 |
172 | private String getHashedTrace(String stacktrace) {
173 | // This function assumes a sanitized stack trace
174 | StringBuilder hashedTrace = new StringBuilder();
175 | for (String line : stacktrace.split("\n")) {
176 | String[] match = line.trim().split("\\(|\\)|:");
177 | String fullfunctionname = match[0];
178 | String sourcename = match[1];
179 | int lineno = Integer.parseInt(match[2]);
180 |
181 | String[] splitfunc = fullfunctionname.split("\\.");
182 | String[] tmp = Arrays.copyOfRange(splitfunc, 0, splitfunc.length - 1);
183 | String classname = String.join(".", tmp);
184 | String functionname = splitfunc[splitfunc.length - 1];
185 |
186 | String functionname_2b = beanstack.Blake2b.Engine.LittleEndian.toHexStr(blake2b.digest(functionname.getBytes()));
187 | String classname_2b = beanstack.Blake2b.Engine.LittleEndian.toHexStr(blake2b.digest(classname.getBytes()));
188 | String fullfunctionname_2b = beanstack.Blake2b.Engine.LittleEndian.toHexStr(blake2b.digest(fullfunctionname.getBytes()));
189 |
190 | hashedTrace.append(String.format("%s:%s:%s:%d\n", fullfunctionname_2b, classname_2b, functionname_2b, lineno));
191 | }
192 |
193 | return hashedTrace.toString();
194 | }
195 |
196 | private String checktrace(String stacktrace) {
197 | String retval = null; // Return value
198 |
199 | try {
200 | ByteBuffer tracedigest = ByteBuffer.wrap(blake2b.digest((GlobalVars.config.getString("apikey") + stacktrace).getBytes("UTF-8")));
201 | if (HttpReqMemoization.containsKey(tracedigest)) {
202 | GlobalVars.debug("Trace found in memoization table, returning stored response.");
203 | return HttpReqMemoization.get(tracedigest);
204 | }
205 |
206 | boolean retry = true;
207 | while (retry) {
208 | retry = false;
209 |
210 | boolean isset_apikey = GlobalVars.config.getString("apikey").length() > 4;
211 | boolean submit_hashed_trace = isset_apikey && GlobalVars.config.getBoolean("hashtrace");
212 |
213 | URL url = new URI(GlobalVars.config.getString("apiurl") + (submit_hashed_trace ? "hashTrace" : "")).toURL();
214 | boolean ishttps = url.getProtocol().equalsIgnoreCase("https");
215 | int port = url.getPort() == -1 ? url.getDefaultPort() : url.getPort();
216 |
217 | GlobalVars.debug(String.format("Submitting a trace to %s", url));
218 |
219 | String body = "";
220 | if (isset_apikey) {
221 | body += "apikey=";
222 | body += GlobalVars.config.getString("apikey").trim();
223 | body += "&";
224 | }
225 | body += "trace=";
226 | body += java.net.URLEncoder.encode(submit_hashed_trace ? getHashedTrace(stacktrace) : stacktrace, StandardCharsets.UTF_8);
227 |
228 | byte[] httpreq = buildHttpRequest(url.getHost(), url2uri(url), "POST", body);
229 | SHR response = parseHttpResponse(GlobalVars.callbacks.makeHttpRequest(url.getHost(), port, ishttps, httpreq));
230 | GlobalVars.debug("Response status " + response.status);
231 |
232 | if (response.status == 204) {
233 | retval = null;
234 | }
235 | else if (response.status == 301 && response.headers.containsKey("location") && response.headers.get("location").equals(GlobalVars.config.getString("apiurl").replace("http://", "https://"))) {
236 | // Oblige an HTTP -> HTTPS redirect (but nothing else)
237 | GlobalVars.debug(String.format("Got a 301, updating apiurl setting from <%s> to <%s>.", GlobalVars.config.getString("apiurl"), response.headers.get("location")));
238 | GlobalVars.config.putAndSave("apiurl", response.headers.get("location"));
239 | retry = true;
240 | }
241 | else if (response.status == 429) {
242 | if (isset_apikey) {
243 | GlobalVars.debug("HTTP request failed: 429 (with API key)");
244 | // An API key is set
245 | String msg = "Your API key ran out of requests. For bulk\nlookup of stack traces, please contact us.";
246 | if ( ! showed429AlertWithApiKey) {
247 | // Only alert once; nobody wants to be annoyed by this stuff
248 | showed429AlertWithApiKey = true;
249 |
250 | JOptionPane.showMessageDialog(null, msg, "Burp Extension " + GlobalVars.EXTENSION_NAME, JOptionPane.ERROR_MESSAGE);
251 | }
252 | GlobalVars.callbacks.issueAlert(msg);
253 | }
254 | else {
255 | GlobalVars.debug("HTTP request failed: 429 (no API key set)");
256 | if ( ! showed429Alert) {
257 | // Only alert once; nobody wants to be annoyed by this stuff
258 | showed429Alert = true;
259 |
260 | // No API key set. Prompt for one and mention where they can get one.
261 | String result = JOptionPane.showInputDialog(GlobalVars.config.getBurpFrame(),
262 | "You have reached the request limit for " + GlobalVars.EXTENSION_NAME_SHORT + ". "
263 | + "Please register on " + GlobalVars.REGURL + "\nfor a free API key. If you already have an API key, please enter it here.",
264 | GlobalVars.EXTENSION_NAME + " API key",
265 | JOptionPane.PLAIN_MESSAGE
266 | );
267 | if (!result.isEmpty()) {
268 | GlobalVars.config.putAndSave("apikey", result);
269 | GlobalVars.debug("apikey configured after prompt");
270 | retry = true;
271 | }
272 | }
273 | else {
274 | GlobalVars.callbacks.issueAlert("Extension " + GlobalVars.EXTENSION_NAME_SHORT + ": You hit the request limit for the API. "
275 | + "To continue, please register for a free API key at " + GlobalVars.REGURL + ", or slow the rate of requests.");
276 | }
277 | }
278 | if (!retry) {
279 | return null;
280 | }
281 | }
282 | else if (response.status == 401 && isset_apikey) {
283 | GlobalVars.debug("HTTP request failed: invalid API key (401)");
284 |
285 | // N.B. we thread this, but due to the thread pool of 1, further requests will just be queued, so we won't get dialogs on top of each other.
286 | // Further requests will also automatically use the API key if the user enters one here, even if they were already queued previously.
287 |
288 | String result = (String)JOptionPane.showInputDialog(GlobalVars.config.getBurpFrame(),
289 | "Your API key is invalid.\nIf you want to use a different API key, please enter it here.",
290 | GlobalVars.EXTENSION_NAME + " API key invalid",
291 | JOptionPane.PLAIN_MESSAGE,
292 | null,
293 | null,
294 | GlobalVars.config.getString("apikey")
295 | );
296 | if (result != null && !result.isEmpty()) {
297 | GlobalVars.config.putAndSave("apikey", result);
298 | GlobalVars.debug("apikey reconfigured");
299 | retry = true;
300 | }
301 | else {
302 | // If they cancelled the dialog or emptied it, override the string so they don't get more of those alerts.
303 | GlobalVars.config.putAndSave("apikey", "none");
304 | }
305 |
306 | if (!retry) {
307 | return null;
308 | }
309 | }
310 | else if (response.status != 200) {
311 | GlobalVars.callbacks.issueAlert("Extension " + GlobalVars.EXTENSION_NAME + ": HTTP request to back-end failed with status " + response.status);
312 |
313 | GlobalVars.debug("HTTP request failed with status " + response.status);
314 |
315 | return null;
316 | }
317 | else {
318 | retval = response.body;
319 | }
320 | } // End of while(retry) loop
321 |
322 | // The code should only reach here if we want to memoize the result. Otherwise, early exit (return) above!
323 |
324 | GlobalVars.debug("Result: " + (retval == null ? "null" : retval.substring(0, Math.min(150, retval.length()))));
325 |
326 | HttpReqMemoization.put(tracedigest, retval);
327 |
328 | return retval;
329 | }
330 | catch (IOException | URISyntaxException e) {
331 | e.printStackTrace(new java.io.PrintStream(GlobalVars.debug));
332 | }
333 |
334 | return null;
335 | }
336 |
337 | private String DecodeUrl(String tracestr) {
338 | // Because java.net.URLDecoder.decode (understandably) throws an exception if there is a percent symbol anywhere not followed by two hex chars.
339 |
340 | int pos = -1;
341 | while ((pos = tracestr.indexOf("%", pos + 1)) > -1) {
342 | if (pos > tracestr.length() - 2) break;
343 |
344 | if (hexchars.indexOf(tracestr.charAt(pos + 1)) > -1 && hexchars.indexOf(tracestr.charAt(pos + 2)) > -1) {
345 | tracestr = tracestr.replace(tracestr.substring(pos, pos + 3), ((char)Integer.parseInt(tracestr.substring(pos + 1, pos + 3), 16)) + "");
346 | pos--;
347 | }
348 | }
349 |
350 | return tracestr;
351 | }
352 |
353 | private String DecodeStackTraceHtml(String tracestr) {
354 | // It seems we'd need to include a library to do HTML decoding... but it's not all that difficult given the limited charset in a stack trace,
355 | // so that seems like overkill, and now we can do things like fix double encoding, ignore invalid encoding without aborting altogether, etc.
356 |
357 | if ( ! tracestr.contains("&")) {
358 | return tracestr;
359 | }
360 |
361 | tracestr = tracestr.replace("&", "&"); // Fix any double encoding first
362 |
363 | Map replacemap = new HashMap() {{
364 | put("nbsp", " ");
365 | put("nonbreakingspace", " ");
366 | put("tab", " ");
367 | put("lt", "<");
368 | put("gt", ">");
369 | put("dollar", "$");
370 | put("lpar", "(");
371 | put("rpar", ")");
372 | put("period", ".");
373 | put("colon", ":");
374 | }};
375 | // If the {1,6} is expanded to allow >=8 chars (technically valid b/c leading zeroes... currently unsupported because that's within the realm of obfuscation
376 | // and if you want to obfuscate your stack traces... there are easier methods to evade BeanStack), then you will need to try{} below to avoid >int_max.
377 | Pattern pattern = Pattern.compile("(&(#[0-9]{1,6}|#x[0-9a-f]{1,9}|nbsp|NonBreakingSpace|tab|lt|gt|dollar|lpar|rpar|period|colon);)", Pattern.CASE_INSENSITIVE);
378 | Matcher matcher = pattern.matcher(tracestr);
379 | while (matcher.find()) {
380 | if (matcher.group(2).startsWith("#")) { // If we have a third group, then we matched a numeric or hex entity
381 | if (matcher.group(2).toLowerCase().startsWith("#x")) {
382 | tracestr = tracestr.replace(matcher.group(1), ((char)Integer.parseInt(matcher.group(2).substring(2), 16)) + "");
383 | }
384 | else {
385 | tracestr = tracestr.replace(matcher.group(1), ((char)Integer.parseInt(matcher.group(2).substring(1))) + "");
386 | }
387 | }
388 | else {
389 | String lce = matcher.group(2).toLowerCase();
390 | if ( ! replacemap.containsKey(lce)) {
391 | continue;
392 | }
393 | tracestr = tracestr.replace(matcher.group(1), replacemap.get(lce));
394 | }
395 | }
396 |
397 | return tracestr;
398 | }
399 |
400 | @SuppressWarnings("unchecked")
401 | public static double determineCvssScore(Map cve) {
402 | /**
403 | * There's an array of scores from different organizations. We're prioritizing
404 | * NIST scores over other (i.e. potentially vendor) scores.
405 | *
406 | * Schema:
407 | * https://csrc.nist.gov/schema/nvd/api/2.0/cve_api_json_2.0.schema
408 | */
409 |
410 | if (!((Map) cve.get("data")).containsKey("metrics")) {
411 | return -1;
412 | }
413 |
414 | ObjectMapper mapper = new ObjectMapper();
415 | Map metricsObj = mapper.convertValue(((Map) cve.get("data")).get("metrics"), new TypeReference<>() {
416 | });
417 | if (metricsObj.isEmpty()) {
418 | return -1;
419 | }
420 |
421 | // keys need to be in order of preference, to prefer later versions
422 | String[] cvssKeys = {"cvssMetricV40", "cvssMetricV31", "cvssMetricV30", "cvssMetricV2"};
423 | List>> allMetrics = new ArrayList<>();
424 |
425 | for (String key : cvssKeys) {
426 | if (metricsObj.containsKey(key)) {
427 | allMetrics.add((List>) metricsObj.get(key));
428 | }
429 | }
430 |
431 | Double newestSecondaryScore = null;
432 |
433 | for (List> metricArray : allMetrics) {
434 | for (Map rating : metricArray) {
435 | Map cvssData = (Map) rating.get("cvssData");
436 | double baseScore = ((Number) cvssData.get("baseScore")).doubleValue();
437 |
438 | String type = (String) rating.get("type");
439 | if ("Primary".equals(type)) {
440 | return baseScore;
441 | } else if (newestSecondaryScore == null) {
442 | newestSecondaryScore = baseScore;
443 | }
444 | }
445 | }
446 |
447 | return newestSecondaryScore != null ? newestSecondaryScore : -1.0;
448 | }
449 |
450 | @Override
451 | @SuppressWarnings("unchecked")
452 | public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse baseRequestResponse) {
453 | if (messageIsRequest) {
454 | // If the trace is locally generated, it probably isn't interesting for us
455 | return;
456 | }
457 |
458 | if ( ! GlobalVars.config.getBoolean("enable")) {
459 | GlobalVars.debug("Note: " + GlobalVars.EXTENSION_NAME_SHORT + " plugin is disabled.");
460 | return;
461 | }
462 |
463 | threader.submit(new Runnable() {
464 | public void run() {
465 | try {
466 | int sizelimit = GlobalVars.config.getInt("sizelimit") * 1024 * 1024;
467 |
468 | byte[] bytesresponse = baseRequestResponse.getResponse();
469 | if (bytesresponse.length > sizelimit) {
470 | byte[] partial = new byte[sizelimit];
471 | System.arraycopy(bytesresponse, 0, partial, 0, sizelimit / 2);
472 | System.arraycopy(bytesresponse, bytesresponse.length - sizelimit / 2, partial, sizelimit / 2, sizelimit / 2);
473 | bytesresponse = partial;
474 | }
475 | String response = new String(bytesresponse, StandardCharsets.UTF_8);
476 |
477 | response = response.replace("\\$", "$").replace("\\/", "/");
478 | response = DecodeUrl(response);
479 | response = DecodeStackTraceHtml(response);
480 |
481 | // Basically the pattern checks /\s[valid class path chars].[more valid class chars]([filename chars].java:1234)/
482 | Pattern pattern = Pattern.compile("(\\s|/)([a-zA-Z0-9\\.\\$]{1,300}\\.[a-zA-Z0-9\\.\\$]{1,300})\\(([a-zA-Z0-9]{1,300})\\.java:\\d{1,6}\\)");
483 | Matcher matcher = pattern.matcher(response);
484 |
485 | // Reconstruct the trace (since who knows what might be in between the lines, e.g. "<br>" or "," or "\n")
486 | StringBuilder stacktrace = new StringBuilder();
487 | while (matcher.find()) {
488 | if (!matcher.group(2).contains(".")) {
489 | // Enforce a dot in the full class name (sanity check)
490 | continue;
491 | }
492 | if (!(matcher.group(2).indexOf(matcher.group(3) + "$") >= 2
493 | || matcher.group(2).indexOf(matcher.group(3) + ".") >= 2)) {
494 | // (^Some extra checks to prevent submitting false positives to our API.)
495 | // The filename should occur in the first part, either followed by a dollar or by a dot,
496 | // and it usually does not start with that (so match from position 2 onwards, because
497 | // there should be at least 1 character and a dot, like "a.test.run(test.java:42)").
498 | continue;
499 | }
500 | String line = matcher.group(0).substring(1);
501 | if (!isBlacklisted(line)) {
502 | GlobalVars.debug(" " + line);
503 | stacktrace.append(" ").append(line).append("\n");
504 | } else {
505 | GlobalVars.debug(String.format("[filtered out blacklisted class: %s]", matcher.group(2)));
506 | }
507 | }
508 |
509 | if (stacktrace.isEmpty()) {
510 | return;
511 | }
512 |
513 | Instant start = Instant.now();
514 |
515 | // Check the trace with our back-end
516 | String result = checktrace(stacktrace.toString());
517 |
518 | GlobalVars.debug("checktrace() returned in " + Duration.between(start, Instant.now()).toMillis() + "ms");
519 |
520 | // Either some error (already handled) or no results
521 | if (result == null) {
522 | return;
523 | }
524 |
525 | ObjectMapper mapper = new ObjectMapper();
526 | // Deserialize JSON into a Map
527 | Map products = mapper.readValue(
528 | result,
529 | new TypeReference<>() {}
530 | );
531 |
532 | StringBuilder issuetext = new StringBuilder();
533 | String comma = "";
534 |
535 | boolean is_uncertain_cve;
536 | boolean any_uncertain_cves = false;
537 | boolean any_certain_cves = false;
538 | double maxcvss = 0;
539 | int i = 0;
540 |
541 | String outdated = "";
542 | String notice = "";
543 |
544 | issuetext.append("X41 BeanStack found the following versions based on the stack trace: ");
545 | for (Map.Entry product : products.entrySet()) {
546 | if (product.getKey().equals("__BeanStack_demo")) {
547 | notice = " Note: CVEs are shown for this stack trace as a demo. To view CVEs with other stack traces, please request an API key .";
548 | continue;
549 | }
550 |
551 | if (product.getKey().equals("__BeanStack_needs_upgrading")) {
552 | outdated = (String) product.getValue();
553 | continue;
554 | }
555 |
556 | i += 1;
557 | issuetext.append(String.format("%d. %s " + htmlindent, i, product.getKey()));
558 |
559 | Map productmap = (Map) product.getValue();
560 | Object[] versions = ((List) productmap.get("versions")).toArray();
561 |
562 | for (Object v : versions) {
563 | System.out.println(v);
564 | }
565 | if (versions.length == 1) {
566 | issuetext.append("version: ").append(versions[0].toString());
567 | } else {
568 | issuetext.append("matching versions: ");
569 | comma = "";
570 | for (Object ver : versions) {
571 | issuetext.append(comma).append(ver.toString());
572 | comma = ", ";
573 | }
574 | }
575 |
576 | if (productmap.containsKey("cves")) {
577 | Object[] cves = ((List) productmap.get("cves")).toArray();
578 | if (cves.length > 0) {
579 | issuetext.append(" " + htmlindent + "CVE(s): ");
580 |
581 | comma = "";
582 | for (Object cveobj : cves) {
583 | Map cvemap = (Map) cveobj;
584 |
585 | String cveid = ((Map) cvemap.get("data")).get("id");
586 | is_uncertain_cve = Integer.parseInt(cvemap.get("vermatch").toString()) != 0;
587 | any_uncertain_cves = is_uncertain_cve ? is_uncertain_cve : any_uncertain_cves;
588 | any_certain_cves = is_uncertain_cve ? any_certain_cves : !is_uncertain_cve;
589 | issuetext.append(comma).append("").append(cveid).append(" ").append(is_uncertain_cve ? "*" : "");
590 | comma = ", ";
591 |
592 | String score = "(not given)";
593 | double cvssScore = determineCvssScore(cvemap);
594 | if (cvssScore != -1.0) {
595 | issuetext.append(" (").append(cvssScore).append(")");
596 | score = Double.toString(cvssScore);
597 | maxcvss = Math.max(cvssScore, maxcvss);
598 | }
599 | System.out.println("Score: " + score);
600 |
601 | if (GlobalVars.config.getBoolean("issuepercve") && !is_uncertain_cve) {
602 | GlobalVars.debug(String.format("Logging separate issue for %s", cveid));
603 | GlobalVars.callbacks.addScanIssue(new CustomScanIssue(
604 | baseRequestResponse.getHttpService(),
605 | GlobalVars.callbacks.getHelpers().analyzeRequest(baseRequestResponse).getUrl(),
606 | new IHttpRequestResponse[]{baseRequestResponse},
607 | String.format("%s (%s)", GlobalVars.config.getString("issuetitle"), cveid),
608 | String.format("In the stack trace, %s with CVSS score %s was discovered. It is present in %s.", cveid, score, product.getKey()),
609 | cvssToBurpSeverity(Float.parseFloat(score)),
610 | "Firm"
611 | ));
612 | }
613 | }
614 | issuetext.append(" ");
615 | }
616 | } else {
617 | if (GlobalVars.config.getString("apikey").length() > 4) {
618 | issuetext.append(" (no CVEs known) ");
619 | } else {
620 | issuetext.append(" ");
621 | }
622 | }
623 | }
624 |
625 | if (any_uncertain_cves) {
626 | issuetext.append(" * This CVE applies to a range of versions. Many projects use non-semver versioning schemes and CVEs do not mention which versioning scheme " + "is used, so we can only do reliable version matching when an exact version is given instead of a range. Therefore, this CVE may not apply.");
627 | }
628 |
629 | if (notice.isEmpty() && GlobalVars.config.getString("apikey").length() <= 4) {
630 | notice = " Note: to check for CVEs, please request an API key or configure your key .";
631 | }
632 |
633 | String certainty;
634 | if (any_uncertain_cves || any_certain_cves) {
635 | // If there are CVEs at all
636 | if (!any_uncertain_cves) {
637 | // Since the severity is determined by the highest CVSS score, and since that
638 | // CVSS score might belong to an uncertain CVE (one that might not apply to
639 | // the product we found, but we don't know because we can't do version
640 | // comparisons without knowing the versioning scheme), we can only be
641 | // "certain" if there are no uncertain CVEs.
642 | certainty = "Certain";
643 | } else if (any_certain_cves) {
644 | certainty = "Firm";
645 | } else {
646 | // Not a single one was an exact version match, so this is fairly uncertain
647 | certainty = "Tentative";
648 | }
649 | } else {
650 | // We didn't find any CVEs, so return the standard certainty
651 | certainty = "Certain";
652 | }
653 |
654 | IScanIssue issue = new CustomScanIssue(
655 | baseRequestResponse.getHttpService(),
656 | GlobalVars.callbacks.getHelpers().analyzeRequest(baseRequestResponse).getUrl(),
657 | new IHttpRequestResponse[]{baseRequestResponse},
658 | GlobalVars.config.getString("issuetitle"),
659 | outdated + issuetext + notice,
660 | cvssToBurpSeverity((float) maxcvss),
661 | certainty
662 | );
663 |
664 | ByteBuffer hash = hashScanIssue(issue);
665 |
666 | if (!AlreadyFingerprinted.add(hash)) {
667 | // We already created an issue for this, avoid creating a duplicate.
668 | if (GlobalVars.config.getBoolean("logdups")) {
669 | GlobalVars.debug("Issue already exists, but logging anyway because logdups config is set.");
670 | } else {
671 | GlobalVars.debug("Issue already exists! Avoiding duplicate.");
672 | return;
673 | }
674 | }
675 |
676 | GlobalVars.callbacks.addScanIssue(issue);
677 | GlobalVars.debug("Logged issue");
678 |
679 | } catch (Exception e) {
680 | System.err.println(e.getMessage());
681 | throw new RuntimeException(e);
682 | }
683 | }
684 | });
685 | }
686 | }
687 |
688 | class BeanstackMenu implements Runnable, java.awt.event.ActionListener, IExtensionStateListener {
689 | private JMenu topMenu;
690 |
691 | BeanstackMenu() {
692 | GlobalVars.callbacks.registerExtensionStateListener(this);
693 | }
694 |
695 | public void run() {
696 | topMenu = new JMenu(GlobalVars.EXTENSION_NAME_SHORT);
697 |
698 | JMenuItem settingsButton = new JMenuItem(GlobalVars.SETTINGS);
699 | settingsButton.addActionListener(this);
700 |
701 | JMenuItem menuHeader = new JMenuItem(GlobalVars.EXTENSION_NAME);
702 | menuHeader.setEnabled(false);
703 |
704 | topMenu.add(menuHeader);
705 | topMenu.add(settingsButton);
706 |
707 | GlobalVars.config.getBurpFrame().getJMenuBar().add(topMenu);
708 | GlobalVars.config.getBurpFrame().getJMenuBar().updateUI();
709 | }
710 |
711 | public void actionPerformed(java.awt.event.ActionEvent e) {
712 | SwingUtilities.invokeLater(new Runnable() {
713 | public void run(){
714 | GlobalVars.config.showSettings();
715 | }
716 | });
717 | }
718 |
719 | public void extensionUnloaded() {
720 | GlobalVars.config.getBurpFrame().getJMenuBar().remove(topMenu);
721 | GlobalVars.config.getBurpFrame().getJMenuBar().updateUI();
722 | }
723 | }
724 |
725 | class SHR {
726 | public final int status;
727 | public final String body;
728 | public final Map headers;
729 | public SHR(int status, Map headers, String body) {
730 | this.status = status;
731 | this.headers = headers;
732 | this.body = body;
733 | }
734 | }
735 |
736 | // From the example project
737 | class CustomScanIssue implements IScanIssue {
738 | private IHttpService httpService;
739 | private URL url;
740 | private IHttpRequestResponse[] httpMessages;
741 | private String name;
742 | private String detail;
743 | private String severity;
744 | private String confidence;
745 |
746 | public CustomScanIssue(
747 | IHttpService httpService,
748 | URL url,
749 | IHttpRequestResponse[] httpMessages,
750 | String name,
751 | String detail,
752 | String severity,
753 | String confidence) {
754 | this.httpService = httpService;
755 | this.url = url;
756 | this.httpMessages = httpMessages;
757 | this.name = name;
758 | this.detail = detail;
759 | this.severity = severity;
760 | this.confidence = confidence;
761 | }
762 |
763 | @Override
764 | public URL getUrl() {
765 | return url;
766 | }
767 |
768 | @Override
769 | public String getIssueName() {
770 | return name;
771 | }
772 |
773 | @Override
774 | public int getIssueType() {
775 | return 0;
776 | }
777 |
778 | @Override
779 | public String getSeverity() {
780 | return severity;
781 | }
782 |
783 | @Override
784 | public String getConfidence() {
785 | return confidence;
786 | }
787 |
788 | @Override
789 | public String getIssueBackground() {
790 | return null;
791 | }
792 |
793 | @Override
794 | public String getRemediationBackground() {
795 | return null;
796 | }
797 |
798 | @Override
799 | public String getIssueDetail() {
800 | return detail;
801 | }
802 |
803 | @Override
804 | public String getRemediationDetail() {
805 | return null;
806 | }
807 |
808 | @Override
809 | public IHttpRequestResponse[] getHttpMessages() {
810 | return httpMessages;
811 | }
812 |
813 | @Override
814 | public IHttpService getHttpService() {
815 | return httpService;
816 | }
817 | }
818 |
819 |
--------------------------------------------------------------------------------
/src/main/java/beanstack/Blake2b.java:
--------------------------------------------------------------------------------
1 | /* !!! Doost !!! */
2 |
3 | /*
4 | A Java implementation of BLAKE2B cryptographic digest algorithm.
5 |
6 | Joubin Mohammad Houshyar
7 | bushwick, nyc
8 | 02-14-2014
9 |
10 | --
11 |
12 | To the extent possible under law, the author(s) have dedicated all copyright
13 | and related and neighboring rights to this software to the public domain
14 | worldwide. This software is distributed without any warranty.
15 |
16 | You should have received a copy of the CC0 Public Domain Dedication along with
17 | this software. If not, see .
18 | */
19 |
20 | // Source: https://raw.githubusercontent.com/alphazero/Blake2b/master/src/main/java/ove/crypto/digest/Blake2b.java
21 |
22 | package beanstack;
23 |
24 | import java.io.PrintStream;
25 | import java.io.Serializable;
26 | import java.security.Key;
27 | import java.security.spec.AlgorithmParameterSpec; // JCE not supported / anticipated ..
28 | import java.util.Arrays;
29 |
30 | import static beanstack.Blake2b.Engine.Assert.*;
31 | import static beanstack.Blake2b.Engine.LittleEndian.*;
32 |
33 |
34 | /** */
35 | public interface Blake2b {
36 | // ---------------------------------------------------------------------
37 | // Specification
38 | // ---------------------------------------------------------------------
39 | public interface Spec {
40 | /** pblock size of blake2b */
41 | int param_bytes = 64;
42 |
43 | /** pblock size of blake2b */
44 | int block_bytes = 128;
45 |
46 | /** maximum digest size */
47 | int max_digest_bytes = 64;
48 |
49 | /** maximum key sie */
50 | int max_key_bytes = 64;
51 |
52 | /** maximum salt size */
53 | int max_salt_bytes = 16;
54 |
55 | /** maximum personalization string size */
56 | int max_personalization_bytes = 16;
57 |
58 | /** length of h space vector array */
59 | int state_space_len = 8;
60 |
61 | /** max tree fanout value */
62 | int max_tree_fantout = 0xFF;
63 |
64 | /** max tree depth value */
65 | int max_tree_depth = 0xFF;
66 |
67 | /** max tree leaf length value.Note that this has uint32 semantics
68 | and thus 0xFFFFFFFF is used as max value limit. */
69 | int max_tree_leaf_length = 0xFFFFFFFF;
70 |
71 | /** max node offset value. Note that this has uint64 semantics
72 | and thus 0xFFFFFFFFFFFFFFFFL is used as max value limit. */
73 | long max_node_offset = 0xFFFFFFFFFFFFFFFFL;
74 |
75 | /** max tree inner length value */
76 | int max_tree_inner_length = 0xFF;
77 |
78 | /** initialization values map ref-Spec IV[i] -> slice iv[i*8:i*8+7] */
79 | long[] IV = {
80 | 0x6a09e667f3bcc908L,
81 | 0xbb67ae8584caa73bL,
82 | 0x3c6ef372fe94f82bL,
83 | 0xa54ff53a5f1d36f1L,
84 | 0x510e527fade682d1L,
85 | 0x9b05688c2b3e6c1fL,
86 | 0x1f83d9abfb41bd6bL,
87 | 0x5be0cd19137e2179L
88 | };
89 | }
90 |
91 | // ---------------------------------------------------------------------
92 | // API
93 | // ---------------------------------------------------------------------
94 | // TODO add ByteBuffer variants
95 |
96 | /**
97 | * A serializable / JSON-izable object usable for pausing a hash-in-process
98 | * which can then be resumed with the same Parameter the original digest
99 | * was constructed with, and fed additional bytes to conclude the hash.
100 | */
101 | public static final class ResumeHandle implements Serializable {
102 | /** per spec */
103 | public long[] h = new long [ 8 ];
104 | /** per spec */
105 | public long[] t = new long [ 2 ];
106 | /** per spec */
107 | public long[] f = new long [ 2 ];
108 | /** per spec (tree) */
109 | public boolean last_node = false;
110 | /** pulled up 2b optimal */
111 | public long[] m = new long [16];
112 | /** pulled up 2b optimal */
113 | public long[] v = new long [16];
114 |
115 | /** compressor cache buffer */
116 | public byte[] buffer;
117 | /** compressor cache buffer offset/cached data length */
118 | public int buflen;
119 |
120 | /** digest length from init param - copied here on init */
121 | public int outlen;
122 |
123 | public int type;
124 |
125 | /**
126 | * Create a reconstituted Black2b digest from
127 | *
128 | * @param param
129 | * @return
130 | */
131 | public Blake2b resume(Param param) {
132 | assert this.buffer != null && this.buffer.length == Spec.block_bytes;
133 | assert this.h != null && this.h.length == 8
134 | && this.t != null && this.t.length == 2
135 | && this.f != null && this.f.length == 2
136 | && this.m != null && this.m.length == 16
137 | && this.v != null && this.v.length == 16 : "Data is corrupted";
138 | assert this.outlen == param.getDigestLength() : "Not originally initialized from this param";
139 | assert this.type == 1 || this.type == 2 : "Unknown type " + this.type;
140 | Engine.State state = new Engine.State(outlen, this.type == 1);
141 | System.arraycopy(this.h, 0, state.h, 0, state.h.length);
142 | System.arraycopy(this.t, 0, state.t, 0, state.t.length);
143 | System.arraycopy(this.f, 0, state.f, 0, state.f.length);
144 | System.arraycopy(this.m, 0, m, 0, m.length);
145 | System.arraycopy(this.v, 0, v, 0, v.length);
146 | System.arraycopy(this.buffer, 0, state.buffer, 0, state.buffer.length);
147 | state.buflen = buflen;
148 | return type == 1 ? new Mac(param, state) : new Digest(param, state);
149 | }
150 | }
151 |
152 | /** */
153 | void update (byte[] input) ;
154 |
155 | /** */
156 | void update (byte input) ;
157 |
158 | /** */
159 | void update (byte[] input, int offset, int len) ;
160 |
161 | /** */
162 | byte[] digest () ;
163 |
164 | /** */
165 | byte[] digest (byte[] input) ;
166 |
167 | /** */
168 | void digest (byte[] output, int offset, int len) ;
169 |
170 | /** */
171 | void reset () ;
172 |
173 | ResumeHandle state();
174 | // ---------------------------------------------------------------------
175 | // Blake2b Message Digest
176 | // ---------------------------------------------------------------------
177 |
178 | /** Generalized Blake2b digest. */
179 | public static class Digest extends Engine implements Blake2b {
180 | private Digest (final Param p) { super (p); }
181 | private Digest () { super (); }
182 | private Digest(Param p, State state) {
183 | super(state, p);
184 | }
185 |
186 | public static Digest newInstance () {
187 | return new Digest ();
188 | }
189 | public static Digest newInstance (final int digestLength) {
190 | return new Digest (new Param().setDigestLength(digestLength));
191 | }
192 | public static Digest newInstance (Param p) {
193 | return new Digest (p);
194 | }
195 | public static Digest newInstance (Param p, State state) {
196 | return new Digest(p, state);
197 | }
198 | }
199 |
200 | // ---------------------------------------------------------------------
201 | // Blake2b Message Authentication Code
202 | // ---------------------------------------------------------------------
203 |
204 | /** Message Authentication Code (MAC) digest. */
205 | public static class Mac extends Engine implements Blake2b {
206 | private Mac (final Param p, State state) { super (state, p); }
207 | private Mac (final Param p) { super (p); }
208 | private Mac () { super (); }
209 |
210 | /** Blake2b.MAC 512 - using default Blake2b.Spec settings with given key */
211 | public static Mac newInstance (final byte[] key) {
212 | return new Mac (new Param().setKey(key));
213 | }
214 | /** Blake2b.MAC - using default Blake2b.Spec settings with given key, with given digest length */
215 | public static Mac newInstance (final byte[] key, final int digestLength) {
216 | return new Mac (new Param().setKey(key).setDigestLength(digestLength));
217 | }
218 | /** Blake2b.MAC - using default Blake2b.Spec settings with given java.security.Key, with given digest length */
219 | public static Mac newInstance (final Key key, final int digestLength) {
220 | return new Mac (new Param().setKey(key).setDigestLength(digestLength));
221 | }
222 | /** Blake2b.MAC - using the specified Parameters.
223 | * @param p asserted valid configured Param with key */
224 | public static Mac newInstance (Param p) {
225 | assert p != null : "Param (p) is null";
226 | assert p.hasKey() : "Param (p) not configured with a key";
227 | return new Mac (p);
228 | }
229 | }
230 |
231 | // ---------------------------------------------------------------------
232 | // Blake2b Incremental Message Digest (Tree)
233 | // ---------------------------------------------------------------------
234 |
235 | /**
236 | * Note that Tree is just a convenience class; incremental hash (tree)
237 | * can be done directly with the Digest class.
238 | *
239 | * Further node, that tree does NOT accumulate the leaf hashes --
240 | * you need to do that
241 | */
242 | public static class Tree {
243 |
244 | final int depth;
245 | final int fanout;
246 | final int leaf_length;
247 | final int inner_length;
248 | final int digest_length;
249 |
250 | /**
251 | *
252 | * @param fanout
253 | * @param depth
254 | * @param leaf_length size of data input for leaf nodes.
255 | * @param inner_length note this is used also as digest-length for non-root nodes.
256 | * @param digest_length final hash out digest-length for the tree
257 | */
258 | public Tree (
259 | final int depth,
260 | final int fanout,
261 | final int leaf_length,
262 | final int inner_length,
263 | final int digest_length
264 | ) {
265 | this.fanout = fanout;
266 | this.depth = depth;
267 | this.leaf_length = leaf_length;
268 | this.inner_length = inner_length;
269 | this.digest_length = digest_length;
270 | }
271 | private Param treeParam() {
272 | return new Param().
273 | setDepth(depth).setFanout(fanout).setLeafLength(leaf_length).setInnerLength(inner_length);
274 | }
275 | /** returns the Digest for tree node @ (depth, offset) */
276 | public final Digest getNode (final int depth, final int offset) {
277 | final Param nodeParam = treeParam().setNodeDepth(depth).setNodeOffset(offset).setDigestLength(inner_length);
278 | return Digest.newInstance(nodeParam);
279 | }
280 | /** returns the Digest for root node */
281 | public final Digest getRoot () {
282 | final int depth = this.depth - 1;
283 | final Param rootParam = treeParam().setNodeDepth(depth).setNodeOffset(0L).setDigestLength(digest_length);
284 | return Digest.newInstance(rootParam);
285 | }
286 | }
287 |
288 | // ---------------------------------------------------------------------
289 | // Engine
290 | // ---------------------------------------------------------------------
291 | static class Engine implements Blake2b {
292 |
293 | // ---------------------------------------------------------------------
294 | // Blake2b State(+) per reference implementation
295 | // ---------------------------------------------------------------------
296 | // REVU: address last_node TODO part of the Tree/incremental
297 | static final class State {
298 | /** per spec */
299 | private final long[] h = new long [ 8 ];
300 | /** per spec */
301 | private final long[] t = new long [ 2 ];
302 | /** per spec */
303 | private final long[] f = new long [ 2 ];
304 | /** per spec (tree) */
305 | private boolean last_node = false;
306 | /** pulled up 2b optimal */
307 | private final long[] m = new long [16];
308 | /** pulled up 2b optimal */
309 | private final long[] v = new long [16];
310 |
311 | /** compressor cache buffer */
312 | private final byte[] buffer;
313 | /** compressor cache buffer offset/cached data length */
314 | private int buflen;
315 |
316 | /** digest length from init param - copied here on init */
317 | private final int outlen;
318 |
319 | private final int digestType;
320 |
321 | State(int digestLength, boolean isMac) {
322 | this.buffer = new byte [ Spec.block_bytes ];
323 | this.outlen = digestLength;
324 | // do not use zero, so we can detect serialization errors
325 | this.digestType = isMac ? 1 : 2;
326 | }
327 |
328 | public ResumeHandle toResumableForm() {
329 | ResumeHandle state = new ResumeHandle();
330 | state.h = h;
331 | state.t = t;
332 | state.f = f;
333 | state.last_node = last_node;
334 | state.m = m;
335 | state.v = v;
336 | state.buffer = buffer;
337 | state.buflen = buflen;
338 | state.outlen = outlen;
339 | state.type = digestType;
340 | return state;
341 | }
342 | }
343 |
344 | private State state;
345 | /** configuration params */
346 | private final Param param;
347 |
348 | /** read only */
349 | private static byte[] zeropad = new byte [ Spec.block_bytes ];
350 |
351 | /** a little bit of semantics */
352 | interface flag {
353 | int last_block = 0;
354 | int last_node = 1;
355 | }
356 | /** to support update(byte) */
357 | private final byte[] oneByte = new byte[1];
358 |
359 | // ---------------------------------------------------------------------
360 | // Ctor & Initialization
361 | // ---------------------------------------------------------------------
362 |
363 | /** Basic use constructor pending (TODO) JCA/JCE compliance */
364 | Engine () {
365 | this( new Param() );
366 | }
367 |
368 | Engine(State state, Param param) {
369 | assert state != null : "state is null";
370 | assert param != null : "param is null";
371 | this.state = state;
372 | this.param = param;
373 | }
374 |
375 | /** User provided Param for custom configurations */
376 | Engine (final Param param) {
377 | assert param != null : "param is null";
378 | this.param = param;
379 | state = new State(param.getDigestLength(), this instanceof Mac);
380 | if ( param.getDepth() > Param.Default.depth ) {
381 | final int ndepth = param.getNodeDepth();
382 | final long nxoff = param.getNodeOffset();
383 | if (ndepth == param.getDepth() - 1) {
384 | state.last_node = true;
385 | assert nxoff == 0 : "root must have offset of zero";
386 | } else if ( nxoff == param.getFanout() - 1) {
387 | this.state.last_node = true;
388 | }
389 | }
390 |
391 | initialize();
392 | }
393 |
394 | public ResumeHandle state() {
395 | return state.toResumableForm();
396 | }
397 |
398 | private void initialize () {
399 | // state vector h - copy values to address reset() requests
400 | System.arraycopy( param.initialized_H(), 0, this.state.h, 0, Spec.state_space_len);
401 |
402 | // if we have a key update initial block
403 | // Note param has zero padded key_bytes to Spec.max_key_bytes
404 | if(param.hasKey){
405 | this.update (param.key_bytes, 0, Spec.block_bytes);
406 | }
407 | }
408 |
409 | public static void main(String... args) {
410 | Blake2b mac = Blake2b.Mac.newInstance("LOVE".getBytes());
411 | final byte[] hash = mac.digest("Salaam!".getBytes());
412 | // Debug.dumpBuffer(System.out, "-- mac hash --", hash);
413 | }
414 |
415 | // ---------------------------------------------------------------------
416 | // interface: Blake2b API
417 | // ---------------------------------------------------------------------
418 |
419 | /** {@inheritDoc} */
420 | @Override final public void reset () {
421 | // reset cache
422 | this.state.buflen = 0;
423 | for(int i=0; i < state.buffer.length; i++){
424 | state.buffer[ i ] = (byte) 0;
425 | }
426 |
427 | // reset flags
428 | this.state.f[ 0 ] = 0L;
429 | this.state.f[ 1 ] = 0L;
430 |
431 | // reset counters
432 | this.state.t[ 0 ] = 0L;
433 | this.state.t[ 1 ] = 0L;
434 |
435 | // reset state vector
436 | // NOTE: keep as last stmt as init calls update0 for MACs.
437 | initialize();
438 | }
439 |
440 | /** {@inheritDoc} */
441 | @Override final public void update (final byte[] b, int off, int len) {
442 | if (b == null) {
443 | throw new IllegalArgumentException("input buffer (b) is null");
444 | }
445 | /* zero or more calls to compress */
446 | final long[] t = state.t;
447 | final byte[] buffer = state.buffer;
448 | while (len > 0) {
449 | if ( state.buflen == 0) {
450 | /* try compressing direct from input ? */
451 | while ( len > Spec.block_bytes ) {
452 | t[0] += Spec.block_bytes;
453 | t[1] += (t[0] < 0 && state.buflen > -t[0]) ? 1 : 0;
454 | compress( b, off);
455 | len -= Spec.block_bytes;
456 | off += Spec.block_bytes;
457 | }
458 | } else if ( state.buflen == Spec.block_bytes ) {
459 | /* flush */
460 | t[0] += Spec.block_bytes;
461 | t[1] += t[0] == 0 ? 1 : 0;
462 | compress( buffer, 0 );
463 | state.buflen = 0;
464 | continue;
465 | }
466 |
467 | // "are we there yet?"
468 | if( len == 0 ) return;
469 |
470 | final int cap = Spec.block_bytes - state.buflen;
471 | final int fill = len > cap ? cap : len;
472 | System.arraycopy( b, off, buffer, state.buflen, fill );
473 | state.buflen += fill;
474 | len -= fill;
475 | off += fill;
476 | }
477 | }
478 |
479 | /** {@inheritDoc} */
480 | @Override final public void update (byte b) {
481 | oneByte[0] = b;
482 | update (oneByte, 0, 1);
483 | }
484 |
485 | /** {@inheritDoc} */
486 | @Override final public void update(byte[] input) {
487 | update (input, 0, input.length);
488 | }
489 |
490 | /** {@inheritDoc} */
491 | @Override final public void digest(byte[] output, int off, int len) {
492 | // zero pad last block; set last block flags; and compress
493 | System.arraycopy( zeropad, 0, state.buffer, state.buflen, Spec.block_bytes - state.buflen);
494 | if(state.buflen > 0) {
495 | this.state.t[0] += state.buflen;
496 | this.state.t[1] += this.state.t[0] == 0 ? 1 : 0;
497 | }
498 |
499 | this.state.f[ flag.last_block ] = 0xFFFFFFFFFFFFFFFFL;
500 | this.state.f[ flag.last_node ] = this.state.last_node ? 0xFFFFFFFFFFFFFFFFL : 0x0L;
501 |
502 | // compres and write final out (truncated to len) to output
503 | compress( state.buffer, 0 );
504 | hashout( output, off, len );
505 |
506 | reset();
507 | }
508 |
509 | /** {@inheritDoc} */
510 | @Override final public byte[] digest () throws IllegalArgumentException {
511 | final byte[] out = new byte [state.outlen];
512 | digest ( out, 0, state.outlen );
513 | return out;
514 | }
515 |
516 | /** {@inheritDoc} */
517 | @Override final public byte[] digest (byte[] input) {
518 | update(input, 0, input.length);
519 | return digest();
520 | }
521 |
522 | // ---------------------------------------------------------------------
523 | // Internal Ops
524 | // ---------------------------------------------------------------------
525 |
526 | /**
527 | * write out the digest output from the 'h' registers.
528 | * truncate full output if necessary.
529 | */
530 | private void hashout (final byte[] out, final int offset, final int hashlen) {
531 | // write max number of whole longs
532 | final int lcnt = hashlen >>> 3;
533 | long v = 0;
534 | int i = offset;
535 | final long[] h = state.h;
536 | for (int w = 0; w < lcnt; w++) {
537 | v = h [ w ];
538 | out [ i ] = (byte) v; v >>>= 8;
539 | out [ i+1 ] = (byte) v; v >>>= 8;
540 | out [ i+2 ] = (byte) v; v >>>= 8;
541 | out [ i+3 ] = (byte) v; v >>>= 8;
542 | out [ i+4 ] = (byte) v; v >>>= 8;
543 | out [ i+5 ] = (byte) v; v >>>= 8;
544 | out [ i+6 ] = (byte) v; v >>>= 8;
545 | out [ i+7 ] = (byte) v;
546 | i+=8;
547 | }
548 |
549 | // basta?
550 | if( hashlen == Spec.max_digest_bytes) return;
551 |
552 | // write the remaining bytes of a partial long value
553 | v = h [ lcnt ];
554 | i = lcnt << 3;
555 | while( i < hashlen ) {
556 | out [ offset + i ] = (byte) v; v >>>= 8; ++i;
557 | }
558 | }
559 |
560 | ////////////////////////////////////////////////////////////////////////
561 | /// Compression Kernel /////////////////////////////////////////// BEGIN
562 | ////////////////////////////////////////////////////////////////////////
563 |
564 | /** compress Spec.block_bytes data from b, from offset */
565 | private void compress (final byte[] b, final int offset) {
566 |
567 | // set m registers
568 | final long[] m = state.m;
569 | m[ 0] = LittleEndian.readLong(b, offset);
570 | m[ 1] = LittleEndian.readLong(b, offset + 8);
571 | m[ 2] = LittleEndian.readLong(b, offset + 16);
572 | m[ 3] = LittleEndian.readLong(b, offset + 24);
573 | m[ 4] = LittleEndian.readLong(b, offset + 32);
574 | m[ 5] = LittleEndian.readLong(b, offset + 40);
575 | m[ 6] = LittleEndian.readLong(b, offset + 48);
576 | m[ 7] = LittleEndian.readLong(b, offset + 56);
577 | m[ 8] = LittleEndian.readLong(b, offset + 64);
578 | m[ 9] = LittleEndian.readLong(b, offset + 72);
579 | m[10] = LittleEndian.readLong(b, offset + 80);
580 | m[11] = LittleEndian.readLong(b, offset + 88);
581 | m[12] = LittleEndian.readLong(b, offset + 96);
582 | m[13] = LittleEndian.readLong(b, offset + 104);
583 | m[14] = LittleEndian.readLong(b, offset + 112);
584 | m[15] = LittleEndian.readLong(b, offset + 120);
585 |
586 | // set v registers
587 | final long[] v = state.v;
588 | final long[] h = state.h;
589 | final long[] t = state.t;
590 | final long[] f = state.f;
591 | v[ 0] = h[0];
592 | v[ 1] = h[1];
593 | v[ 2] = h[2];
594 | v[ 3] = h[3];
595 | v[ 4] = h[4];
596 | v[ 5] = h[5];
597 | v[ 6] = h[6];
598 | v[ 7] = h[7];
599 | v[ 8] = 0x6a09e667f3bcc908L;
600 | v[ 9] = 0xbb67ae8584caa73bL;
601 | v[10] = 0x3c6ef372fe94f82bL;
602 | v[11] = 0xa54ff53a5f1d36f1L;
603 | v[12] = t [0] ^ 0x510e527fade682d1L;
604 | v[13] = t [1] ^ 0x9b05688c2b3e6c1fL;
605 | v[14] = f [0] ^ 0x1f83d9abfb41bd6bL;
606 | v[15] = f [1] ^ 0x5be0cd19137e2179L;
607 |
608 | // do the rounds
609 | round_0(v, m);
610 | round_1(v, m);
611 | round_2(v, m);
612 | round_3(v, m);
613 | round_4(v, m);
614 | round_5(v, m);
615 | round_6(v, m);
616 | round_7(v, m);
617 | round_8(v, m);
618 | round_9(v, m);
619 | round_0(v, m); // round 10 is identical to round 0
620 | round_1(v, m); // round 11 is identical to round 1
621 |
622 | // Update state vector h
623 | h[0] ^= v[0] ^ v[8];
624 | h[1] ^= v[1] ^ v[9];
625 | h[2] ^= v[2] ^ v[10];
626 | h[3] ^= v[3] ^ v[11];
627 | h[4] ^= v[4] ^ v[12];
628 | h[5] ^= v[5] ^ v[13];
629 | h[6] ^= v[6] ^ v[14];
630 | h[7] ^= v[7] ^ v[15];
631 |
632 | /* kaamil */
633 | }
634 | private void round_0(final long[] v, final long[] m) {
635 | v[ 0] = v[ 0] + v[ 4] + m[0];
636 | v[12] ^= v[ 0];
637 | v[12] = ( v[12] << 32 ) | ( v[12] >>> 32 );
638 | v[ 8] = v[ 8] + v[12];
639 | v[ 4] ^= v[ 8];
640 | v[ 4] = ( v[ 4] >>> 24 ) | ( v[ 4] << 40 );
641 | v[ 0] = v[ 0] + v[ 4] + m [1];
642 | v[12] ^= v[ 0];
643 | v[12] = ( v[12] >>> 16 ) | ( v[12] << 48 );
644 | v[ 8] = v[ 8] + v[12];
645 | v[ 4] ^= v[ 8];
646 | v[ 4] = ( v[ 4] << 1 ) | ( v[ 4] >>> 63 );
647 |
648 | v[ 1] = v[ 1] + v[ 5] + m[2];
649 | v[13] ^= v[ 1];
650 | v[13] = ( v[13] << 32 ) | ( v[13] >>> 32 );
651 | v[ 9] = v[ 9] + v[13];
652 | v[ 5] ^= v[ 9];
653 | v[ 5] = ( v[ 5] >>> 24 ) | ( v[ 5] << 40 );
654 | v[ 1] = v[ 1] + v[ 5] + m[3];
655 | v[13] ^= v[ 1];
656 | v[13] = ( v[13] >>> 16 ) | ( v[13] << 48 );
657 | v[ 9] = v[ 9] + v[13];
658 | v[ 5] ^= v[ 9];
659 | v[ 5] = ( v[ 5] << 1 ) | ( v[ 5] >>> 63 );
660 |
661 | v[ 2] = v[ 2] + v[ 6] + m[4];
662 | v[14] ^= v[ 2];
663 | v[14] = ( v[14] << 32 ) | ( v[14] >>> 32 );
664 | v[10] = v[10] + v[14];
665 | v[ 6] ^= v[10];
666 | v[ 6] = ( v[ 6] >>> 24 ) | ( v[ 6] << 40 );
667 | v[ 2] = v[ 2] + v[ 6] + m[5];
668 | v[14] ^= v[ 2];
669 | v[14] = ( v[14] >>> 16 ) | ( v[14] << 48 );
670 | v[10] = v[10] + v[14];
671 | v[ 6] ^= v[10];
672 | v[ 6] = ( v[ 6] << 1 ) | ( v[ 6] >>> 63 );
673 |
674 | v[ 3] = v[ 3] + v[ 7] + m[6];
675 | v[15] ^= v[ 3];
676 | v[15] = ( v[15] << 32 ) | ( v[15] >>> 32 );
677 | v[11] = v[11] + v[15];
678 | v[ 7] ^= v[11];
679 | v[ 7] = ( v[ 7] >>> 24 ) | ( v[ 7] << 40 );
680 | v[ 3] = v[ 3] + v[ 7] + m[7];
681 | v[15] ^= v[ 3];
682 | v[15] = ( v[15] >>> 16 ) | ( v[15] << 48 );
683 | v[11] = v[11] + v[15];
684 | v[ 7] ^= v[11];
685 | v[ 7] = ( v[ 7] << 1 ) | ( v[ 7] >>> 63 );
686 |
687 | v[ 0] = v[ 0] + v[ 5] + m[8];
688 | v[15] ^= v[ 0];
689 | v[15] = ( v[15] << 32 ) | ( v[15] >>> 32 );
690 | v[10] = v[10] + v[15];
691 | v[ 5] ^= v[10];
692 | v[ 5] = ( v[ 5] >>> 24 ) | ( v[ 5] << 40 );
693 | v[ 0] = v[ 0] + v[ 5] + m[9];
694 | v[15] ^= v[ 0];
695 | v[15] = ( v[15] >>> 16 ) | ( v[15] << 48 );
696 | v[10] = v[10] + v[15];
697 | v[ 5] ^= v[10];
698 | v[ 5] = ( v[ 5] << 1 ) | ( v[ 5] >>> 63 );
699 |
700 | v[ 1] = v[ 1] + v[ 6] + m[10];
701 | v[12] ^= v[ 1];
702 | v[12] = ( v[12] << 32 ) | ( v[12] >>> 32 );
703 | v[11] = v[11] + v[12];
704 | v[ 6] ^= v[11];
705 | v[ 6] = ( v[ 6] >>> 24 ) | ( v[ 6] << 40 );
706 | v[ 1] = v[ 1] + v[ 6] + + m[11];
707 | v[12] ^= v[ 1];
708 | v[12] = ( v[12] >>> 16 ) | ( v[12] << 48 );
709 | v[11] = v[11] + v[12];
710 | v[ 6] ^= v[11];
711 | v[ 6] = ( v[ 6] << 1 ) | ( v[ 6] >>> 63 );
712 |
713 | v[ 2] = v[ 2] + v[ 7] + m[12];
714 | v[13] ^= v[ 2];
715 | v[13] = ( v[13] << 32 ) | ( v[13] >>> 32 );
716 | v[ 8] = v[ 8] + v[13];
717 | v[ 7] ^= v[ 8];
718 | v[ 7] = ( v[ 7] >>> 24 ) | ( v[ 7] << 40 );
719 | v[ 2] = v[ 2] + v[ 7] + m[13];
720 | v[13] ^= v[ 2];
721 | v[13] = ( v[13] >>> 16 ) | ( v[13] << 48 );
722 | v[ 8] = v[ 8] + v[13];
723 | v[ 7] ^= v[ 8];
724 | v[ 7] = ( v[ 7] << 1 ) | ( v[ 7] >>> 63 );
725 |
726 | v[ 3] = v[ 3] + v[ 4] + m[14];
727 | v[14] ^= v[ 3];
728 | v[14] = ( v[14] << 32 ) | ( v[14] >>> 32 );
729 | v[ 9] = v[ 9] + v[14];
730 | v[ 4] ^= v[ 9];
731 | v[ 4] = ( v[ 4] >>> 24 ) | ( v[ 4] << 40 );
732 | v[ 3] = v[ 3] + v[ 4] + m[15];
733 | v[14] ^= v[ 3];
734 | v[14] = ( v[14] >>> 16 ) | ( v[14] << 48 );
735 | v[ 9] = v[ 9] + v[14];
736 | v[ 4] ^= v[ 9];
737 | v[ 4] = ( v[ 4] << 1 ) | ( v[ 4] >>> 63 );
738 | }
739 | private void round_1(final long[] v, final long[] m) {
740 | v[ 0] = v[ 0] + v[ 4] + m[14];
741 | v[12] ^= v[ 0];
742 | v[12] = ( v[12] << 32 ) | ( v[12] >>> 32 );
743 | v[ 8] = v[ 8] + v[12];
744 | v[ 4] ^= v[ 8];
745 | v[ 4] = ( v[ 4] >>> 24 ) | ( v[ 4] << 40 );
746 | v[ 0] = v[ 0] + v[ 4] + m [10];
747 | v[12] ^= v[ 0];
748 | v[12] = ( v[12] >>> 16 ) | ( v[12] << 48 );
749 | v[ 8] = v[ 8] + v[12];
750 | v[ 4] ^= v[ 8];
751 | v[ 4] = ( v[ 4] << 1 ) | ( v[ 4] >>> 63 );
752 |
753 | v[ 1] = v[ 1] + v[ 5] + m[4];
754 | v[13] ^= v[ 1];
755 | v[13] = ( v[13] << 32 ) | ( v[13] >>> 32 );
756 | v[ 9] = v[ 9] + v[13];
757 | v[ 5] ^= v[ 9];
758 | v[ 5] = ( v[ 5] >>> 24 ) | ( v[ 5] << 40 );
759 | v[ 1] = v[ 1] + v[ 5] + m[8];
760 | v[13] ^= v[ 1];
761 | v[13] = ( v[13] >>> 16 ) | ( v[13] << 48 );
762 | v[ 9] = v[ 9] + v[13];
763 | v[ 5] ^= v[ 9];
764 | v[ 5] = ( v[ 5] << 1 ) | ( v[ 5] >>> 63 );
765 |
766 | v[ 2] = v[ 2] + v[ 6] + m[9];
767 | v[14] ^= v[ 2];
768 | v[14] = ( v[14] << 32 ) | ( v[14] >>> 32 );
769 | v[10] = v[10] + v[14];
770 | v[ 6] ^= v[10];
771 | v[ 6] = ( v[ 6] >>> 24 ) | ( v[ 6] << 40 );
772 | v[ 2] = v[ 2] + v[ 6] + m[15];
773 | v[14] ^= v[ 2];
774 | v[14] = ( v[14] >>> 16 ) | ( v[14] << 48 );
775 | v[10] = v[10] + v[14];
776 | v[ 6] ^= v[10];
777 | v[ 6] = ( v[ 6] << 1 ) | ( v[ 6] >>> 63 );
778 |
779 | v[ 3] = v[ 3] + v[ 7] + m[13];
780 | v[15] ^= v[ 3];
781 | v[15] = ( v[15] << 32 ) | ( v[15] >>> 32 );
782 | v[11] = v[11] + v[15];
783 | v[ 7] ^= v[11];
784 | v[ 7] = ( v[ 7] >>> 24 ) | ( v[ 7] << 40 );
785 | v[ 3] = v[ 3] + v[ 7] + m[6];
786 | v[15] ^= v[ 3];
787 | v[15] = ( v[15] >>> 16 ) | ( v[15] << 48 );
788 | v[11] = v[11] + v[15];
789 | v[ 7] ^= v[11];
790 | v[ 7] = ( v[ 7] << 1 ) | ( v[ 7] >>> 63 );
791 |
792 | v[ 0] = v[ 0] + v[ 5] + m[1];
793 | v[15] ^= v[ 0];
794 | v[15] = ( v[15] << 32 ) | ( v[15] >>> 32 );
795 | v[10] = v[10] + v[15];
796 | v[ 5] ^= v[10];
797 | v[ 5] = ( v[ 5] >>> 24 ) | ( v[ 5] << 40 );
798 | v[ 0] = v[ 0] + v[ 5] + m[12];
799 | v[15] ^= v[ 0];
800 | v[15] = ( v[15] >>> 16 ) | ( v[15] << 48 );
801 | v[10] = v[10] + v[15];
802 | v[ 5] ^= v[10];
803 | v[ 5] = ( v[ 5] << 1 ) | ( v[ 5] >>> 63 );
804 |
805 | v[ 1] = v[ 1] + v[ 6] + m[0];
806 | v[12] ^= v[ 1];
807 | v[12] = ( v[12] << 32 ) | ( v[12] >>> 32 );
808 | v[11] = v[11] + v[12];
809 | v[ 6] ^= v[11];
810 | v[ 6] = ( v[ 6] >>> 24 ) | ( v[ 6] << 40 );
811 | v[ 1] = v[ 1] + v[ 6] + + m[2];
812 | v[12] ^= v[ 1];
813 | v[12] = ( v[12] >>> 16 ) | ( v[12] << 48 );
814 | v[11] = v[11] + v[12];
815 | v[ 6] ^= v[11];
816 | v[ 6] = ( v[ 6] << 1 ) | ( v[ 6] >>> 63 );
817 |
818 | v[ 2] = v[ 2] + v[ 7] + m[11];
819 | v[13] ^= v[ 2];
820 | v[13] = ( v[13] << 32 ) | ( v[13] >>> 32 );
821 | v[ 8] = v[ 8] + v[13];
822 | v[ 7] ^= v[ 8];
823 | v[ 7] = ( v[ 7] >>> 24 ) | ( v[ 7] << 40 );
824 | v[ 2] = v[ 2] + v[ 7] + m[7];
825 | v[13] ^= v[ 2];
826 | v[13] = ( v[13] >>> 16 ) | ( v[13] << 48 );
827 | v[ 8] = v[ 8] + v[13];
828 | v[ 7] ^= v[ 8];
829 | v[ 7] = ( v[ 7] << 1 ) | ( v[ 7] >>> 63 );
830 |
831 | v[ 3] = v[ 3] + v[ 4] + m[5];
832 | v[14] ^= v[ 3];
833 | v[14] = ( v[14] << 32 ) | ( v[14] >>> 32 );
834 | v[ 9] = v[ 9] + v[14];
835 | v[ 4] ^= v[ 9];
836 | v[ 4] = ( v[ 4] >>> 24 ) | ( v[ 4] << 40 );
837 | v[ 3] = v[ 3] + v[ 4] + m[3];
838 | v[14] ^= v[ 3];
839 | v[14] = ( v[14] >>> 16 ) | ( v[14] << 48 );
840 | v[ 9] = v[ 9] + v[14];
841 | v[ 4] ^= v[ 9];
842 | v[ 4] = ( v[ 4] << 1 ) | ( v[ 4] >>> 63 );
843 | }
844 | private void round_2(final long[] v, final long[] m) {
845 | v[ 0] = v[ 0] + v[ 4] + m[11];
846 | v[12] ^= v[ 0];
847 | v[12] = ( v[12] << 32 ) | ( v[12] >>> 32 );
848 | v[ 8] = v[ 8] + v[12];
849 | v[ 4] ^= v[ 8];
850 | v[ 4] = ( v[ 4] >>> 24 ) | ( v[ 4] << 40 );
851 | v[ 0] = v[ 0] + v[ 4] + m [8];
852 | v[12] ^= v[ 0];
853 | v[12] = ( v[12] >>> 16 ) | ( v[12] << 48 );
854 | v[ 8] = v[ 8] + v[12];
855 | v[ 4] ^= v[ 8];
856 | v[ 4] = ( v[ 4] << 1 ) | ( v[ 4] >>> 63 );
857 |
858 | v[ 1] = v[ 1] + v[ 5] + m[12];
859 | v[13] ^= v[ 1];
860 | v[13] = ( v[13] << 32 ) | ( v[13] >>> 32 );
861 | v[ 9] = v[ 9] + v[13];
862 | v[ 5] ^= v[ 9];
863 | v[ 5] = ( v[ 5] >>> 24 ) | ( v[ 5] << 40 );
864 | v[ 1] = v[ 1] + v[ 5] + m[0];
865 | v[13] ^= v[ 1];
866 | v[13] = ( v[13] >>> 16 ) | ( v[13] << 48 );
867 | v[ 9] = v[ 9] + v[13];
868 | v[ 5] ^= v[ 9];
869 | v[ 5] = ( v[ 5] << 1 ) | ( v[ 5] >>> 63 );
870 |
871 | v[ 2] = v[ 2] + v[ 6] + m[5];
872 | v[14] ^= v[ 2];
873 | v[14] = ( v[14] << 32 ) | ( v[14] >>> 32 );
874 | v[10] = v[10] + v[14];
875 | v[ 6] ^= v[10];
876 | v[ 6] = ( v[ 6] >>> 24 ) | ( v[ 6] << 40 );
877 | v[ 2] = v[ 2] + v[ 6] + m[2];
878 | v[14] ^= v[ 2];
879 | v[14] = ( v[14] >>> 16 ) | ( v[14] << 48 );
880 | v[10] = v[10] + v[14];
881 | v[ 6] ^= v[10];
882 | v[ 6] = ( v[ 6] << 1 ) | ( v[ 6] >>> 63 );
883 |
884 | v[ 3] = v[ 3] + v[ 7] + m[15];
885 | v[15] ^= v[ 3];
886 | v[15] = ( v[15] << 32 ) | ( v[15] >>> 32 );
887 | v[11] = v[11] + v[15];
888 | v[ 7] ^= v[11];
889 | v[ 7] = ( v[ 7] >>> 24 ) | ( v[ 7] << 40 );
890 | v[ 3] = v[ 3] + v[ 7] + m[13];
891 | v[15] ^= v[ 3];
892 | v[15] = ( v[15] >>> 16 ) | ( v[15] << 48 );
893 | v[11] = v[11] + v[15];
894 | v[ 7] ^= v[11];
895 | v[ 7] = ( v[ 7] << 1 ) | ( v[ 7] >>> 63 );
896 |
897 | v[ 0] = v[ 0] + v[ 5] + m[10];
898 | v[15] ^= v[ 0];
899 | v[15] = ( v[15] << 32 ) | ( v[15] >>> 32 );
900 | v[10] = v[10] + v[15];
901 | v[ 5] ^= v[10];
902 | v[ 5] = ( v[ 5] >>> 24 ) | ( v[ 5] << 40 );
903 | v[ 0] = v[ 0] + v[ 5] + m[14];
904 | v[15] ^= v[ 0];
905 | v[15] = ( v[15] >>> 16 ) | ( v[15] << 48 );
906 | v[10] = v[10] + v[15];
907 | v[ 5] ^= v[10];
908 | v[ 5] = ( v[ 5] << 1 ) | ( v[ 5] >>> 63 );
909 |
910 | v[ 1] = v[ 1] + v[ 6] + m[3];
911 | v[12] ^= v[ 1];
912 | v[12] = ( v[12] << 32 ) | ( v[12] >>> 32 );
913 | v[11] = v[11] + v[12];
914 | v[ 6] ^= v[11];
915 | v[ 6] = ( v[ 6] >>> 24 ) | ( v[ 6] << 40 );
916 | v[ 1] = v[ 1] + v[ 6] + + m[6];
917 | v[12] ^= v[ 1];
918 | v[12] = ( v[12] >>> 16 ) | ( v[12] << 48 );
919 | v[11] = v[11] + v[12];
920 | v[ 6] ^= v[11];
921 | v[ 6] = ( v[ 6] << 1 ) | ( v[ 6] >>> 63 );
922 |
923 | v[ 2] = v[ 2] + v[ 7] + m[7];
924 | v[13] ^= v[ 2];
925 | v[13] = ( v[13] << 32 ) | ( v[13] >>> 32 );
926 | v[ 8] = v[ 8] + v[13];
927 | v[ 7] ^= v[ 8];
928 | v[ 7] = ( v[ 7] >>> 24 ) | ( v[ 7] << 40 );
929 | v[ 2] = v[ 2] + v[ 7] + m[1];
930 | v[13] ^= v[ 2];
931 | v[13] = ( v[13] >>> 16 ) | ( v[13] << 48 );
932 | v[ 8] = v[ 8] + v[13];
933 | v[ 7] ^= v[ 8];
934 | v[ 7] = ( v[ 7] << 1 ) | ( v[ 7] >>> 63 );
935 |
936 | v[ 3] = v[ 3] + v[ 4] + m[9];
937 | v[14] ^= v[ 3];
938 | v[14] = ( v[14] << 32 ) | ( v[14] >>> 32 );
939 | v[ 9] = v[ 9] + v[14];
940 | v[ 4] ^= v[ 9];
941 | v[ 4] = ( v[ 4] >>> 24 ) | ( v[ 4] << 40 );
942 | v[ 3] = v[ 3] + v[ 4] + m[4];
943 | v[14] ^= v[ 3];
944 | v[14] = ( v[14] >>> 16 ) | ( v[14] << 48 );
945 | v[ 9] = v[ 9] + v[14];
946 | v[ 4] ^= v[ 9];
947 | v[ 4] = ( v[ 4] << 1 ) | ( v[ 4] >>> 63 );
948 | }
949 | private void round_3(final long[] v, final long[] m) {
950 | v[ 0] = v[ 0] + v[ 4] + m[7];
951 | v[12] ^= v[ 0];
952 | v[12] = ( v[12] << 32 ) | ( v[12] >>> 32 );
953 | v[ 8] = v[ 8] + v[12];
954 | v[ 4] ^= v[ 8];
955 | v[ 4] = ( v[ 4] >>> 24 ) | ( v[ 4] << 40 );
956 | v[ 0] = v[ 0] + v[ 4] + m [9];
957 | v[12] ^= v[ 0];
958 | v[12] = ( v[12] >>> 16 ) | ( v[12] << 48 );
959 | v[ 8] = v[ 8] + v[12];
960 | v[ 4] ^= v[ 8];
961 | v[ 4] = ( v[ 4] << 1 ) | ( v[ 4] >>> 63 );
962 |
963 | v[ 1] = v[ 1] + v[ 5] + m[3];
964 | v[13] ^= v[ 1];
965 | v[13] = ( v[13] << 32 ) | ( v[13] >>> 32 );
966 | v[ 9] = v[ 9] + v[13];
967 | v[ 5] ^= v[ 9];
968 | v[ 5] = ( v[ 5] >>> 24 ) | ( v[ 5] << 40 );
969 | v[ 1] = v[ 1] + v[ 5] + m[1];
970 | v[13] ^= v[ 1];
971 | v[13] = ( v[13] >>> 16 ) | ( v[13] << 48 );
972 | v[ 9] = v[ 9] + v[13];
973 | v[ 5] ^= v[ 9];
974 | v[ 5] = ( v[ 5] << 1 ) | ( v[ 5] >>> 63 );
975 |
976 | v[ 2] = v[ 2] + v[ 6] + m[13];
977 | v[14] ^= v[ 2];
978 | v[14] = ( v[14] << 32 ) | ( v[14] >>> 32 );
979 | v[10] = v[10] + v[14];
980 | v[ 6] ^= v[10];
981 | v[ 6] = ( v[ 6] >>> 24 ) | ( v[ 6] << 40 );
982 | v[ 2] = v[ 2] + v[ 6] + m[12];
983 | v[14] ^= v[ 2];
984 | v[14] = ( v[14] >>> 16 ) | ( v[14] << 48 );
985 | v[10] = v[10] + v[14];
986 | v[ 6] ^= v[10];
987 | v[ 6] = ( v[ 6] << 1 ) | ( v[ 6] >>> 63 );
988 |
989 | v[ 3] = v[ 3] + v[ 7] + m[11];
990 | v[15] ^= v[ 3];
991 | v[15] = ( v[15] << 32 ) | ( v[15] >>> 32 );
992 | v[11] = v[11] + v[15];
993 | v[ 7] ^= v[11];
994 | v[ 7] = ( v[ 7] >>> 24 ) | ( v[ 7] << 40 );
995 | v[ 3] = v[ 3] + v[ 7] + m[14];
996 | v[15] ^= v[ 3];
997 | v[15] = ( v[15] >>> 16 ) | ( v[15] << 48 );
998 | v[11] = v[11] + v[15];
999 | v[ 7] ^= v[11];
1000 | v[ 7] = ( v[ 7] << 1 ) | ( v[ 7] >>> 63 );
1001 |
1002 | v[ 0] = v[ 0] + v[ 5] + m[2];
1003 | v[15] ^= v[ 0];
1004 | v[15] = ( v[15] << 32 ) | ( v[15] >>> 32 );
1005 | v[10] = v[10] + v[15];
1006 | v[ 5] ^= v[10];
1007 | v[ 5] = ( v[ 5] >>> 24 ) | ( v[ 5] << 40 );
1008 | v[ 0] = v[ 0] + v[ 5] + m[6];
1009 | v[15] ^= v[ 0];
1010 | v[15] = ( v[15] >>> 16 ) | ( v[15] << 48 );
1011 | v[10] = v[10] + v[15];
1012 | v[ 5] ^= v[10];
1013 | v[ 5] = ( v[ 5] << 1 ) | ( v[ 5] >>> 63 );
1014 |
1015 | v[ 1] = v[ 1] + v[ 6] + m[5];
1016 | v[12] ^= v[ 1];
1017 | v[12] = ( v[12] << 32 ) | ( v[12] >>> 32 );
1018 | v[11] = v[11] + v[12];
1019 | v[ 6] ^= v[11];
1020 | v[ 6] = ( v[ 6] >>> 24 ) | ( v[ 6] << 40 );
1021 | v[ 1] = v[ 1] + v[ 6] + + m[10];
1022 | v[12] ^= v[ 1];
1023 | v[12] = ( v[12] >>> 16 ) | ( v[12] << 48 );
1024 | v[11] = v[11] + v[12];
1025 | v[ 6] ^= v[11];
1026 | v[ 6] = ( v[ 6] << 1 ) | ( v[ 6] >>> 63 );
1027 |
1028 | v[ 2] = v[ 2] + v[ 7] + m[4];
1029 | v[13] ^= v[ 2];
1030 | v[13] = ( v[13] << 32 ) | ( v[13] >>> 32 );
1031 | v[ 8] = v[ 8] + v[13];
1032 | v[ 7] ^= v[ 8];
1033 | v[ 7] = ( v[ 7] >>> 24 ) | ( v[ 7] << 40 );
1034 | v[ 2] = v[ 2] + v[ 7] + m[0];
1035 | v[13] ^= v[ 2];
1036 | v[13] = ( v[13] >>> 16 ) | ( v[13] << 48 );
1037 | v[ 8] = v[ 8] + v[13];
1038 | v[ 7] ^= v[ 8];
1039 | v[ 7] = ( v[ 7] << 1 ) | ( v[ 7] >>> 63 );
1040 |
1041 | v[ 3] = v[ 3] + v[ 4] + m[15];
1042 | v[14] ^= v[ 3];
1043 | v[14] = ( v[14] << 32 ) | ( v[14] >>> 32 );
1044 | v[ 9] = v[ 9] + v[14];
1045 | v[ 4] ^= v[ 9];
1046 | v[ 4] = ( v[ 4] >>> 24 ) | ( v[ 4] << 40 );
1047 | v[ 3] = v[ 3] + v[ 4] + m[8];
1048 | v[14] ^= v[ 3];
1049 | v[14] = ( v[14] >>> 16 ) | ( v[14] << 48 );
1050 | v[ 9] = v[ 9] + v[14];
1051 | v[ 4] ^= v[ 9];
1052 | v[ 4] = ( v[ 4] << 1 ) | ( v[ 4] >>> 63 );
1053 | }
1054 | private void round_4(final long[] v, final long[] m) {
1055 | v[ 0] = v[ 0] + v[ 4] + m[9];
1056 | v[12] ^= v[ 0];
1057 | v[12] = ( v[12] << 32 ) | ( v[12] >>> 32 );
1058 | v[ 8] = v[ 8] + v[12];
1059 | v[ 4] ^= v[ 8];
1060 | v[ 4] = ( v[ 4] >>> 24 ) | ( v[ 4] << 40 );
1061 | v[ 0] = v[ 0] + v[ 4] + m [0];
1062 | v[12] ^= v[ 0];
1063 | v[12] = ( v[12] >>> 16 ) | ( v[12] << 48 );
1064 | v[ 8] = v[ 8] + v[12];
1065 | v[ 4] ^= v[ 8];
1066 | v[ 4] = ( v[ 4] << 1 ) | ( v[ 4] >>> 63 );
1067 |
1068 | v[ 1] = v[ 1] + v[ 5] + m[5];
1069 | v[13] ^= v[ 1];
1070 | v[13] = ( v[13] << 32 ) | ( v[13] >>> 32 );
1071 | v[ 9] = v[ 9] + v[13];
1072 | v[ 5] ^= v[ 9];
1073 | v[ 5] = ( v[ 5] >>> 24 ) | ( v[ 5] << 40 );
1074 | v[ 1] = v[ 1] + v[ 5] + m[7];
1075 | v[13] ^= v[ 1];
1076 | v[13] = ( v[13] >>> 16 ) | ( v[13] << 48 );
1077 | v[ 9] = v[ 9] + v[13];
1078 | v[ 5] ^= v[ 9];
1079 | v[ 5] = ( v[ 5] << 1 ) | ( v[ 5] >>> 63 );
1080 |
1081 | v[ 2] = v[ 2] + v[ 6] + m[2];
1082 | v[14] ^= v[ 2];
1083 | v[14] = ( v[14] << 32 ) | ( v[14] >>> 32 );
1084 | v[10] = v[10] + v[14];
1085 | v[ 6] ^= v[10];
1086 | v[ 6] = ( v[ 6] >>> 24 ) | ( v[ 6] << 40 );
1087 | v[ 2] = v[ 2] + v[ 6] + m[4];
1088 | v[14] ^= v[ 2];
1089 | v[14] = ( v[14] >>> 16 ) | ( v[14] << 48 );
1090 | v[10] = v[10] + v[14];
1091 | v[ 6] ^= v[10];
1092 | v[ 6] = ( v[ 6] << 1 ) | ( v[ 6] >>> 63 );
1093 |
1094 | v[ 3] = v[ 3] + v[ 7] + m[10];
1095 | v[15] ^= v[ 3];
1096 | v[15] = ( v[15] << 32 ) | ( v[15] >>> 32 );
1097 | v[11] = v[11] + v[15];
1098 | v[ 7] ^= v[11];
1099 | v[ 7] = ( v[ 7] >>> 24 ) | ( v[ 7] << 40 );
1100 | v[ 3] = v[ 3] + v[ 7] + m[15];
1101 | v[15] ^= v[ 3];
1102 | v[15] = ( v[15] >>> 16 ) | ( v[15] << 48 );
1103 | v[11] = v[11] + v[15];
1104 | v[ 7] ^= v[11];
1105 | v[ 7] = ( v[ 7] << 1 ) | ( v[ 7] >>> 63 );
1106 |
1107 | v[ 0] = v[ 0] + v[ 5] + m[14];
1108 | v[15] ^= v[ 0];
1109 | v[15] = ( v[15] << 32 ) | ( v[15] >>> 32 );
1110 | v[10] = v[10] + v[15];
1111 | v[ 5] ^= v[10];
1112 | v[ 5] = ( v[ 5] >>> 24 ) | ( v[ 5] << 40 );
1113 | v[ 0] = v[ 0] + v[ 5] + m[1];
1114 | v[15] ^= v[ 0];
1115 | v[15] = ( v[15] >>> 16 ) | ( v[15] << 48 );
1116 | v[10] = v[10] + v[15];
1117 | v[ 5] ^= v[10];
1118 | v[ 5] = ( v[ 5] << 1 ) | ( v[ 5] >>> 63 );
1119 |
1120 | v[ 1] = v[ 1] + v[ 6] + m[11];
1121 | v[12] ^= v[ 1];
1122 | v[12] = ( v[12] << 32 ) | ( v[12] >>> 32 );
1123 | v[11] = v[11] + v[12];
1124 | v[ 6] ^= v[11];
1125 | v[ 6] = ( v[ 6] >>> 24 ) | ( v[ 6] << 40 );
1126 | v[ 1] = v[ 1] + v[ 6] + + m[12];
1127 | v[12] ^= v[ 1];
1128 | v[12] = ( v[12] >>> 16 ) | ( v[12] << 48 );
1129 | v[11] = v[11] + v[12];
1130 | v[ 6] ^= v[11];
1131 | v[ 6] = ( v[ 6] << 1 ) | ( v[ 6] >>> 63 );
1132 |
1133 | v[ 2] = v[ 2] + v[ 7] + m[6];
1134 | v[13] ^= v[ 2];
1135 | v[13] = ( v[13] << 32 ) | ( v[13] >>> 32 );
1136 | v[ 8] = v[ 8] + v[13];
1137 | v[ 7] ^= v[ 8];
1138 | v[ 7] = ( v[ 7] >>> 24 ) | ( v[ 7] << 40 );
1139 | v[ 2] = v[ 2] + v[ 7] + m[8];
1140 | v[13] ^= v[ 2];
1141 | v[13] = ( v[13] >>> 16 ) | ( v[13] << 48 );
1142 | v[ 8] = v[ 8] + v[13];
1143 | v[ 7] ^= v[ 8];
1144 | v[ 7] = ( v[ 7] << 1 ) | ( v[ 7] >>> 63 );
1145 |
1146 | v[ 3] = v[ 3] + v[ 4] + m[3];
1147 | v[14] ^= v[ 3];
1148 | v[14] = ( v[14] << 32 ) | ( v[14] >>> 32 );
1149 | v[ 9] = v[ 9] + v[14];
1150 | v[ 4] ^= v[ 9];
1151 | v[ 4] = ( v[ 4] >>> 24 ) | ( v[ 4] << 40 );
1152 | v[ 3] = v[ 3] + v[ 4] + m[13];
1153 | v[14] ^= v[ 3];
1154 | v[14] = ( v[14] >>> 16 ) | ( v[14] << 48 );
1155 | v[ 9] = v[ 9] + v[14];
1156 | v[ 4] ^= v[ 9];
1157 | v[ 4] = ( v[ 4] << 1 ) | ( v[ 4] >>> 63 );
1158 | }
1159 | private void round_5(final long[] v, final long[] m) {
1160 | v[ 0] = v[ 0] + v[ 4] + m[2];
1161 | v[12] ^= v[ 0];
1162 | v[12] = ( v[12] << 32 ) | ( v[12] >>> 32 );
1163 | v[ 8] = v[ 8] + v[12];
1164 | v[ 4] ^= v[ 8];
1165 | v[ 4] = ( v[ 4] >>> 24 ) | ( v[ 4] << 40 );
1166 | v[ 0] = v[ 0] + v[ 4] + m [12];
1167 | v[12] ^= v[ 0];
1168 | v[12] = ( v[12] >>> 16 ) | ( v[12] << 48 );
1169 | v[ 8] = v[ 8] + v[12];
1170 | v[ 4] ^= v[ 8];
1171 | v[ 4] = ( v[ 4] << 1 ) | ( v[ 4] >>> 63 );
1172 |
1173 | v[ 1] = v[ 1] + v[ 5] + m[6];
1174 | v[13] ^= v[ 1];
1175 | v[13] = ( v[13] << 32 ) | ( v[13] >>> 32 );
1176 | v[ 9] = v[ 9] + v[13];
1177 | v[ 5] ^= v[ 9];
1178 | v[ 5] = ( v[ 5] >>> 24 ) | ( v[ 5] << 40 );
1179 | v[ 1] = v[ 1] + v[ 5] + m[10];
1180 | v[13] ^= v[ 1];
1181 | v[13] = ( v[13] >>> 16 ) | ( v[13] << 48 );
1182 | v[ 9] = v[ 9] + v[13];
1183 | v[ 5] ^= v[ 9];
1184 | v[ 5] = ( v[ 5] << 1 ) | ( v[ 5] >>> 63 );
1185 |
1186 | v[ 2] = v[ 2] + v[ 6] + m[0];
1187 | v[14] ^= v[ 2];
1188 | v[14] = ( v[14] << 32 ) | ( v[14] >>> 32 );
1189 | v[10] = v[10] + v[14];
1190 | v[ 6] ^= v[10];
1191 | v[ 6] = ( v[ 6] >>> 24 ) | ( v[ 6] << 40 );
1192 | v[ 2] = v[ 2] + v[ 6] + m[11];
1193 | v[14] ^= v[ 2];
1194 | v[14] = ( v[14] >>> 16 ) | ( v[14] << 48 );
1195 | v[10] = v[10] + v[14];
1196 | v[ 6] ^= v[10];
1197 | v[ 6] = ( v[ 6] << 1 ) | ( v[ 6] >>> 63 );
1198 |
1199 | v[ 3] = v[ 3] + v[ 7] + m[8];
1200 | v[15] ^= v[ 3];
1201 | v[15] = ( v[15] << 32 ) | ( v[15] >>> 32 );
1202 | v[11] = v[11] + v[15];
1203 | v[ 7] ^= v[11];
1204 | v[ 7] = ( v[ 7] >>> 24 ) | ( v[ 7] << 40 );
1205 | v[ 3] = v[ 3] + v[ 7] + m[3];
1206 | v[15] ^= v[ 3];
1207 | v[15] = ( v[15] >>> 16 ) | ( v[15] << 48 );
1208 | v[11] = v[11] + v[15];
1209 | v[ 7] ^= v[11];
1210 | v[ 7] = ( v[ 7] << 1 ) | ( v[ 7] >>> 63 );
1211 |
1212 | v[ 0] = v[ 0] + v[ 5] + m[4];
1213 | v[15] ^= v[ 0];
1214 | v[15] = ( v[15] << 32 ) | ( v[15] >>> 32 );
1215 | v[10] = v[10] + v[15];
1216 | v[ 5] ^= v[10];
1217 | v[ 5] = ( v[ 5] >>> 24 ) | ( v[ 5] << 40 );
1218 | v[ 0] = v[ 0] + v[ 5] + m[13];
1219 | v[15] ^= v[ 0];
1220 | v[15] = ( v[15] >>> 16 ) | ( v[15] << 48 );
1221 | v[10] = v[10] + v[15];
1222 | v[ 5] ^= v[10];
1223 | v[ 5] = ( v[ 5] << 1 ) | ( v[ 5] >>> 63 );
1224 |
1225 | v[ 1] = v[ 1] + v[ 6] + m[7];
1226 | v[12] ^= v[ 1];
1227 | v[12] = ( v[12] << 32 ) | ( v[12] >>> 32 );
1228 | v[11] = v[11] + v[12];
1229 | v[ 6] ^= v[11];
1230 | v[ 6] = ( v[ 6] >>> 24 ) | ( v[ 6] << 40 );
1231 | v[ 1] = v[ 1] + v[ 6] + + m[5];
1232 | v[12] ^= v[ 1];
1233 | v[12] = ( v[12] >>> 16 ) | ( v[12] << 48 );
1234 | v[11] = v[11] + v[12];
1235 | v[ 6] ^= v[11];
1236 | v[ 6] = ( v[ 6] << 1 ) | ( v[ 6] >>> 63 );
1237 |
1238 | v[ 2] = v[ 2] + v[ 7] + m[15];
1239 | v[13] ^= v[ 2];
1240 | v[13] = ( v[13] << 32 ) | ( v[13] >>> 32 );
1241 | v[ 8] = v[ 8] + v[13];
1242 | v[ 7] ^= v[ 8];
1243 | v[ 7] = ( v[ 7] >>> 24 ) | ( v[ 7] << 40 );
1244 | v[ 2] = v[ 2] + v[ 7] + m[14];
1245 | v[13] ^= v[ 2];
1246 | v[13] = ( v[13] >>> 16 ) | ( v[13] << 48 );
1247 | v[ 8] = v[ 8] + v[13];
1248 | v[ 7] ^= v[ 8];
1249 | v[ 7] = ( v[ 7] << 1 ) | ( v[ 7] >>> 63 );
1250 |
1251 | v[ 3] = v[ 3] + v[ 4] + m[1];
1252 | v[14] ^= v[ 3];
1253 | v[14] = ( v[14] << 32 ) | ( v[14] >>> 32 );
1254 | v[ 9] = v[ 9] + v[14];
1255 | v[ 4] ^= v[ 9];
1256 | v[ 4] = ( v[ 4] >>> 24 ) | ( v[ 4] << 40 );
1257 | v[ 3] = v[ 3] + v[ 4] + m[9];
1258 | v[14] ^= v[ 3];
1259 | v[14] = ( v[14] >>> 16 ) | ( v[14] << 48 );
1260 | v[ 9] = v[ 9] + v[14];
1261 | v[ 4] ^= v[ 9];
1262 | v[ 4] = ( v[ 4] << 1 ) | ( v[ 4] >>> 63 );
1263 | }
1264 | private void round_6(final long[] v, final long[] m) {
1265 | v[ 0] = v[ 0] + v[ 4] + m[12];
1266 | v[12] ^= v[ 0];
1267 | v[12] = ( v[12] << 32 ) | ( v[12] >>> 32 );
1268 | v[ 8] = v[ 8] + v[12];
1269 | v[ 4] ^= v[ 8];
1270 | v[ 4] = ( v[ 4] >>> 24 ) | ( v[ 4] << 40 );
1271 | v[ 0] = v[ 0] + v[ 4] + m [5];
1272 | v[12] ^= v[ 0];
1273 | v[12] = ( v[12] >>> 16 ) | ( v[12] << 48 );
1274 | v[ 8] = v[ 8] + v[12];
1275 | v[ 4] ^= v[ 8];
1276 | v[ 4] = ( v[ 4] << 1 ) | ( v[ 4] >>> 63 );
1277 |
1278 | v[ 1] = v[ 1] + v[ 5] + m[1];
1279 | v[13] ^= v[ 1];
1280 | v[13] = ( v[13] << 32 ) | ( v[13] >>> 32 );
1281 | v[ 9] = v[ 9] + v[13];
1282 | v[ 5] ^= v[ 9];
1283 | v[ 5] = ( v[ 5] >>> 24 ) | ( v[ 5] << 40 );
1284 | v[ 1] = v[ 1] + v[ 5] + m[15];
1285 | v[13] ^= v[ 1];
1286 | v[13] = ( v[13] >>> 16 ) | ( v[13] << 48 );
1287 | v[ 9] = v[ 9] + v[13];
1288 | v[ 5] ^= v[ 9];
1289 | v[ 5] = ( v[ 5] << 1 ) | ( v[ 5] >>> 63 );
1290 |
1291 | v[ 2] = v[ 2] + v[ 6] + m[14];
1292 | v[14] ^= v[ 2];
1293 | v[14] = ( v[14] << 32 ) | ( v[14] >>> 32 );
1294 | v[10] = v[10] + v[14];
1295 | v[ 6] ^= v[10];
1296 | v[ 6] = ( v[ 6] >>> 24 ) | ( v[ 6] << 40 );
1297 | v[ 2] = v[ 2] + v[ 6] + m[13];
1298 | v[14] ^= v[ 2];
1299 | v[14] = ( v[14] >>> 16 ) | ( v[14] << 48 );
1300 | v[10] = v[10] + v[14];
1301 | v[ 6] ^= v[10];
1302 | v[ 6] = ( v[ 6] << 1 ) | ( v[ 6] >>> 63 );
1303 |
1304 | v[ 3] = v[ 3] + v[ 7] + m[4];
1305 | v[15] ^= v[ 3];
1306 | v[15] = ( v[15] << 32 ) | ( v[15] >>> 32 );
1307 | v[11] = v[11] + v[15];
1308 | v[ 7] ^= v[11];
1309 | v[ 7] = ( v[ 7] >>> 24 ) | ( v[ 7] << 40 );
1310 | v[ 3] = v[ 3] + v[ 7] + m[10];
1311 | v[15] ^= v[ 3];
1312 | v[15] = ( v[15] >>> 16 ) | ( v[15] << 48 );
1313 | v[11] = v[11] + v[15];
1314 | v[ 7] ^= v[11];
1315 | v[ 7] = ( v[ 7] << 1 ) | ( v[ 7] >>> 63 );
1316 |
1317 | v[ 0] = v[ 0] + v[ 5] + m[0];
1318 | v[15] ^= v[ 0];
1319 | v[15] = ( v[15] << 32 ) | ( v[15] >>> 32 );
1320 | v[10] = v[10] + v[15];
1321 | v[ 5] ^= v[10];
1322 | v[ 5] = ( v[ 5] >>> 24 ) | ( v[ 5] << 40 );
1323 | v[ 0] = v[ 0] + v[ 5] + m[7];
1324 | v[15] ^= v[ 0];
1325 | v[15] = ( v[15] >>> 16 ) | ( v[15] << 48 );
1326 | v[10] = v[10] + v[15];
1327 | v[ 5] ^= v[10];
1328 | v[ 5] = ( v[ 5] << 1 ) | ( v[ 5] >>> 63 );
1329 |
1330 | v[ 1] = v[ 1] + v[ 6] + m[6];
1331 | v[12] ^= v[ 1];
1332 | v[12] = ( v[12] << 32 ) | ( v[12] >>> 32 );
1333 | v[11] = v[11] + v[12];
1334 | v[ 6] ^= v[11];
1335 | v[ 6] = ( v[ 6] >>> 24 ) | ( v[ 6] << 40 );
1336 | v[ 1] = v[ 1] + v[ 6] + + m[3];
1337 | v[12] ^= v[ 1];
1338 | v[12] = ( v[12] >>> 16 ) | ( v[12] << 48 );
1339 | v[11] = v[11] + v[12];
1340 | v[ 6] ^= v[11];
1341 | v[ 6] = ( v[ 6] << 1 ) | ( v[ 6] >>> 63 );
1342 |
1343 | v[ 2] = v[ 2] + v[ 7] + m[9];
1344 | v[13] ^= v[ 2];
1345 | v[13] = ( v[13] << 32 ) | ( v[13] >>> 32 );
1346 | v[ 8] = v[ 8] + v[13];
1347 | v[ 7] ^= v[ 8];
1348 | v[ 7] = ( v[ 7] >>> 24 ) | ( v[ 7] << 40 );
1349 | v[ 2] = v[ 2] + v[ 7] + m[2];
1350 | v[13] ^= v[ 2];
1351 | v[13] = ( v[13] >>> 16 ) | ( v[13] << 48 );
1352 | v[ 8] = v[ 8] + v[13];
1353 | v[ 7] ^= v[ 8];
1354 | v[ 7] = ( v[ 7] << 1 ) | ( v[ 7] >>> 63 );
1355 |
1356 | v[ 3] = v[ 3] + v[ 4] + m[8];
1357 | v[14] ^= v[ 3];
1358 | v[14] = ( v[14] << 32 ) | ( v[14] >>> 32 );
1359 | v[ 9] = v[ 9] + v[14];
1360 | v[ 4] ^= v[ 9];
1361 | v[ 4] = ( v[ 4] >>> 24 ) | ( v[ 4] << 40 );
1362 | v[ 3] = v[ 3] + v[ 4] + m[11];
1363 | v[14] ^= v[ 3];
1364 | v[14] = ( v[14] >>> 16 ) | ( v[14] << 48 );
1365 | v[ 9] = v[ 9] + v[14];
1366 | v[ 4] ^= v[ 9];
1367 | v[ 4] = ( v[ 4] << 1 ) | ( v[ 4] >>> 63 );
1368 | }
1369 | private void round_7(final long[] v, final long[] m) {
1370 | v[ 0] = v[ 0] + v[ 4] + m[13];
1371 | v[12] ^= v[ 0];
1372 | v[12] = ( v[12] << 32 ) | ( v[12] >>> 32 );
1373 | v[ 8] = v[ 8] + v[12];
1374 | v[ 4] ^= v[ 8];
1375 | v[ 4] = ( v[ 4] >>> 24 ) | ( v[ 4] << 40 );
1376 | v[ 0] = v[ 0] + v[ 4] + m [11];
1377 | v[12] ^= v[ 0];
1378 | v[12] = ( v[12] >>> 16 ) | ( v[12] << 48 );
1379 | v[ 8] = v[ 8] + v[12];
1380 | v[ 4] ^= v[ 8];
1381 | v[ 4] = ( v[ 4] << 1 ) | ( v[ 4] >>> 63 );
1382 |
1383 | v[ 1] = v[ 1] + v[ 5] + m[7];
1384 | v[13] ^= v[ 1];
1385 | v[13] = ( v[13] << 32 ) | ( v[13] >>> 32 );
1386 | v[ 9] = v[ 9] + v[13];
1387 | v[ 5] ^= v[ 9];
1388 | v[ 5] = ( v[ 5] >>> 24 ) | ( v[ 5] << 40 );
1389 | v[ 1] = v[ 1] + v[ 5] + m[14];
1390 | v[13] ^= v[ 1];
1391 | v[13] = ( v[13] >>> 16 ) | ( v[13] << 48 );
1392 | v[ 9] = v[ 9] + v[13];
1393 | v[ 5] ^= v[ 9];
1394 | v[ 5] = ( v[ 5] << 1 ) | ( v[ 5] >>> 63 );
1395 |
1396 | v[ 2] = v[ 2] + v[ 6] + m[12];
1397 | v[14] ^= v[ 2];
1398 | v[14] = ( v[14] << 32 ) | ( v[14] >>> 32 );
1399 | v[10] = v[10] + v[14];
1400 | v[ 6] ^= v[10];
1401 | v[ 6] = ( v[ 6] >>> 24 ) | ( v[ 6] << 40 );
1402 | v[ 2] = v[ 2] + v[ 6] + m[1];
1403 | v[14] ^= v[ 2];
1404 | v[14] = ( v[14] >>> 16 ) | ( v[14] << 48 );
1405 | v[10] = v[10] + v[14];
1406 | v[ 6] ^= v[10];
1407 | v[ 6] = ( v[ 6] << 1 ) | ( v[ 6] >>> 63 );
1408 |
1409 | v[ 3] = v[ 3] + v[ 7] + m[3];
1410 | v[15] ^= v[ 3];
1411 | v[15] = ( v[15] << 32 ) | ( v[15] >>> 32 );
1412 | v[11] = v[11] + v[15];
1413 | v[ 7] ^= v[11];
1414 | v[ 7] = ( v[ 7] >>> 24 ) | ( v[ 7] << 40 );
1415 | v[ 3] = v[ 3] + v[ 7] + m[9];
1416 | v[15] ^= v[ 3];
1417 | v[15] = ( v[15] >>> 16 ) | ( v[15] << 48 );
1418 | v[11] = v[11] + v[15];
1419 | v[ 7] ^= v[11];
1420 | v[ 7] = ( v[ 7] << 1 ) | ( v[ 7] >>> 63 );
1421 |
1422 | v[ 0] = v[ 0] + v[ 5] + m[5];
1423 | v[15] ^= v[ 0];
1424 | v[15] = ( v[15] << 32 ) | ( v[15] >>> 32 );
1425 | v[10] = v[10] + v[15];
1426 | v[ 5] ^= v[10];
1427 | v[ 5] = ( v[ 5] >>> 24 ) | ( v[ 5] << 40 );
1428 | v[ 0] = v[ 0] + v[ 5] + m[0];
1429 | v[15] ^= v[ 0];
1430 | v[15] = ( v[15] >>> 16 ) | ( v[15] << 48 );
1431 | v[10] = v[10] + v[15];
1432 | v[ 5] ^= v[10];
1433 | v[ 5] = ( v[ 5] << 1 ) | ( v[ 5] >>> 63 );
1434 |
1435 | v[ 1] = v[ 1] + v[ 6] + m[15];
1436 | v[12] ^= v[ 1];
1437 | v[12] = ( v[12] << 32 ) | ( v[12] >>> 32 );
1438 | v[11] = v[11] + v[12];
1439 | v[ 6] ^= v[11];
1440 | v[ 6] = ( v[ 6] >>> 24 ) | ( v[ 6] << 40 );
1441 | v[ 1] = v[ 1] + v[ 6] + + m[4];
1442 | v[12] ^= v[ 1];
1443 | v[12] = ( v[12] >>> 16 ) | ( v[12] << 48 );
1444 | v[11] = v[11] + v[12];
1445 | v[ 6] ^= v[11];
1446 | v[ 6] = ( v[ 6] << 1 ) | ( v[ 6] >>> 63 );
1447 |
1448 | v[ 2] = v[ 2] + v[ 7] + m[8];
1449 | v[13] ^= v[ 2];
1450 | v[13] = ( v[13] << 32 ) | ( v[13] >>> 32 );
1451 | v[ 8] = v[ 8] + v[13];
1452 | v[ 7] ^= v[ 8];
1453 | v[ 7] = ( v[ 7] >>> 24 ) | ( v[ 7] << 40 );
1454 | v[ 2] = v[ 2] + v[ 7] + m[6];
1455 | v[13] ^= v[ 2];
1456 | v[13] = ( v[13] >>> 16 ) | ( v[13] << 48 );
1457 | v[ 8] = v[ 8] + v[13];
1458 | v[ 7] ^= v[ 8];
1459 | v[ 7] = ( v[ 7] << 1 ) | ( v[ 7] >>> 63 );
1460 |
1461 | v[ 3] = v[ 3] + v[ 4] + m[2];
1462 | v[14] ^= v[ 3];
1463 | v[14] = ( v[14] << 32 ) | ( v[14] >>> 32 );
1464 | v[ 9] = v[ 9] + v[14];
1465 | v[ 4] ^= v[ 9];
1466 | v[ 4] = ( v[ 4] >>> 24 ) | ( v[ 4] << 40 );
1467 | v[ 3] = v[ 3] + v[ 4] + m[10];
1468 | v[14] ^= v[ 3];
1469 | v[14] = ( v[14] >>> 16 ) | ( v[14] << 48 );
1470 | v[ 9] = v[ 9] + v[14];
1471 | v[ 4] ^= v[ 9];
1472 | v[ 4] = ( v[ 4] << 1 ) | ( v[ 4] >>> 63 );
1473 | }
1474 | private void round_8(final long[] v, final long[] m) {
1475 | v[ 0] = v[ 0] + v[ 4] + m[6];
1476 | v[12] ^= v[ 0];
1477 | v[12] = ( v[12] << 32 ) | ( v[12] >>> 32 );
1478 | v[ 8] = v[ 8] + v[12];
1479 | v[ 4] ^= v[ 8];
1480 | v[ 4] = ( v[ 4] >>> 24 ) | ( v[ 4] << 40 );
1481 | v[ 0] = v[ 0] + v[ 4] + m [15];
1482 | v[12] ^= v[ 0];
1483 | v[12] = ( v[12] >>> 16 ) | ( v[12] << 48 );
1484 | v[ 8] = v[ 8] + v[12];
1485 | v[ 4] ^= v[ 8];
1486 | v[ 4] = ( v[ 4] << 1 ) | ( v[ 4] >>> 63 );
1487 |
1488 | v[ 1] = v[ 1] + v[ 5] + m[14];
1489 | v[13] ^= v[ 1];
1490 | v[13] = ( v[13] << 32 ) | ( v[13] >>> 32 );
1491 | v[ 9] = v[ 9] + v[13];
1492 | v[ 5] ^= v[ 9];
1493 | v[ 5] = ( v[ 5] >>> 24 ) | ( v[ 5] << 40 );
1494 | v[ 1] = v[ 1] + v[ 5] + m[9];
1495 | v[13] ^= v[ 1];
1496 | v[13] = ( v[13] >>> 16 ) | ( v[13] << 48 );
1497 | v[ 9] = v[ 9] + v[13];
1498 | v[ 5] ^= v[ 9];
1499 | v[ 5] = ( v[ 5] << 1 ) | ( v[ 5] >>> 63 );
1500 |
1501 | v[ 2] = v[ 2] + v[ 6] + m[11];
1502 | v[14] ^= v[ 2];
1503 | v[14] = ( v[14] << 32 ) | ( v[14] >>> 32 );
1504 | v[10] = v[10] + v[14];
1505 | v[ 6] ^= v[10];
1506 | v[ 6] = ( v[ 6] >>> 24 ) | ( v[ 6] << 40 );
1507 | v[ 2] = v[ 2] + v[ 6] + m[3];
1508 | v[14] ^= v[ 2];
1509 | v[14] = ( v[14] >>> 16 ) | ( v[14] << 48 );
1510 | v[10] = v[10] + v[14];
1511 | v[ 6] ^= v[10];
1512 | v[ 6] = ( v[ 6] << 1 ) | ( v[ 6] >>> 63 );
1513 |
1514 | v[ 3] = v[ 3] + v[ 7] + m[0];
1515 | v[15] ^= v[ 3];
1516 | v[15] = ( v[15] << 32 ) | ( v[15] >>> 32 );
1517 | v[11] = v[11] + v[15];
1518 | v[ 7] ^= v[11];
1519 | v[ 7] = ( v[ 7] >>> 24 ) | ( v[ 7] << 40 );
1520 | v[ 3] = v[ 3] + v[ 7] + m[8];
1521 | v[15] ^= v[ 3];
1522 | v[15] = ( v[15] >>> 16 ) | ( v[15] << 48 );
1523 | v[11] = v[11] + v[15];
1524 | v[ 7] ^= v[11];
1525 | v[ 7] = ( v[ 7] << 1 ) | ( v[ 7] >>> 63 );
1526 |
1527 | v[ 0] = v[ 0] + v[ 5] + m[12];
1528 | v[15] ^= v[ 0];
1529 | v[15] = ( v[15] << 32 ) | ( v[15] >>> 32 );
1530 | v[10] = v[10] + v[15];
1531 | v[ 5] ^= v[10];
1532 | v[ 5] = ( v[ 5] >>> 24 ) | ( v[ 5] << 40 );
1533 | v[ 0] = v[ 0] + v[ 5] + m[2];
1534 | v[15] ^= v[ 0];
1535 | v[15] = ( v[15] >>> 16 ) | ( v[15] << 48 );
1536 | v[10] = v[10] + v[15];
1537 | v[ 5] ^= v[10];
1538 | v[ 5] = ( v[ 5] << 1 ) | ( v[ 5] >>> 63 );
1539 |
1540 | v[ 1] = v[ 1] + v[ 6] + m[13];
1541 | v[12] ^= v[ 1];
1542 | v[12] = ( v[12] << 32 ) | ( v[12] >>> 32 );
1543 | v[11] = v[11] + v[12];
1544 | v[ 6] ^= v[11];
1545 | v[ 6] = ( v[ 6] >>> 24 ) | ( v[ 6] << 40 );
1546 | v[ 1] = v[ 1] + v[ 6] + + m[7];
1547 | v[12] ^= v[ 1];
1548 | v[12] = ( v[12] >>> 16 ) | ( v[12] << 48 );
1549 | v[11] = v[11] + v[12];
1550 | v[ 6] ^= v[11];
1551 | v[ 6] = ( v[ 6] << 1 ) | ( v[ 6] >>> 63 );
1552 |
1553 | v[ 2] = v[ 2] + v[ 7] + m[1];
1554 | v[13] ^= v[ 2];
1555 | v[13] = ( v[13] << 32 ) | ( v[13] >>> 32 );
1556 | v[ 8] = v[ 8] + v[13];
1557 | v[ 7] ^= v[ 8];
1558 | v[ 7] = ( v[ 7] >>> 24 ) | ( v[ 7] << 40 );
1559 | v[ 2] = v[ 2] + v[ 7] + m[4];
1560 | v[13] ^= v[ 2];
1561 | v[13] = ( v[13] >>> 16 ) | ( v[13] << 48 );
1562 | v[ 8] = v[ 8] + v[13];
1563 | v[ 7] ^= v[ 8];
1564 | v[ 7] = ( v[ 7] << 1 ) | ( v[ 7] >>> 63 );
1565 |
1566 | v[ 3] = v[ 3] + v[ 4] + m[10];
1567 | v[14] ^= v[ 3];
1568 | v[14] = ( v[14] << 32 ) | ( v[14] >>> 32 );
1569 | v[ 9] = v[ 9] + v[14];
1570 | v[ 4] ^= v[ 9];
1571 | v[ 4] = ( v[ 4] >>> 24 ) | ( v[ 4] << 40 );
1572 | v[ 3] = v[ 3] + v[ 4] + m[5];
1573 | v[14] ^= v[ 3];
1574 | v[14] = ( v[14] >>> 16 ) | ( v[14] << 48 );
1575 | v[ 9] = v[ 9] + v[14];
1576 | v[ 4] ^= v[ 9];
1577 | v[ 4] = ( v[ 4] << 1 ) | ( v[ 4] >>> 63 );
1578 | }
1579 | private void round_9(final long[] v, final long[] m) {
1580 | v[ 0] = v[ 0] + v[ 4] + m[10];
1581 | v[12] ^= v[ 0];
1582 | v[12] = ( v[12] << 32 ) | ( v[12] >>> 32 );
1583 | v[ 8] = v[ 8] + v[12];
1584 | v[ 4] ^= v[ 8];
1585 | v[ 4] = ( v[ 4] >>> 24 ) | ( v[ 4] << 40 );
1586 | v[ 0] = v[ 0] + v[ 4] + m [2];
1587 | v[12] ^= v[ 0];
1588 | v[12] = ( v[12] >>> 16 ) | ( v[12] << 48 );
1589 | v[ 8] = v[ 8] + v[12];
1590 | v[ 4] ^= v[ 8];
1591 | v[ 4] = ( v[ 4] << 1 ) | ( v[ 4] >>> 63 );
1592 |
1593 | v[ 1] = v[ 1] + v[ 5] + m[8];
1594 | v[13] ^= v[ 1];
1595 | v[13] = ( v[13] << 32 ) | ( v[13] >>> 32 );
1596 | v[ 9] = v[ 9] + v[13];
1597 | v[ 5] ^= v[ 9];
1598 | v[ 5] = ( v[ 5] >>> 24 ) | ( v[ 5] << 40 );
1599 | v[ 1] = v[ 1] + v[ 5] + m[4];
1600 | v[13] ^= v[ 1];
1601 | v[13] = ( v[13] >>> 16 ) | ( v[13] << 48 );
1602 | v[ 9] = v[ 9] + v[13];
1603 | v[ 5] ^= v[ 9];
1604 | v[ 5] = ( v[ 5] << 1 ) | ( v[ 5] >>> 63 );
1605 |
1606 | v[ 2] = v[ 2] + v[ 6] + m[7];
1607 | v[14] ^= v[ 2];
1608 | v[14] = ( v[14] << 32 ) | ( v[14] >>> 32 );
1609 | v[10] = v[10] + v[14];
1610 | v[ 6] ^= v[10];
1611 | v[ 6] = ( v[ 6] >>> 24 ) | ( v[ 6] << 40 );
1612 | v[ 2] = v[ 2] + v[ 6] + m[6];
1613 | v[14] ^= v[ 2];
1614 | v[14] = ( v[14] >>> 16 ) | ( v[14] << 48 );
1615 | v[10] = v[10] + v[14];
1616 | v[ 6] ^= v[10];
1617 | v[ 6] = ( v[ 6] << 1 ) | ( v[ 6] >>> 63 );
1618 |
1619 | v[ 3] = v[ 3] + v[ 7] + m[1];
1620 | v[15] ^= v[ 3];
1621 | v[15] = ( v[15] << 32 ) | ( v[15] >>> 32 );
1622 | v[11] = v[11] + v[15];
1623 | v[ 7] ^= v[11];
1624 | v[ 7] = ( v[ 7] >>> 24 ) | ( v[ 7] << 40 );
1625 | v[ 3] = v[ 3] + v[ 7] + m[5];
1626 | v[15] ^= v[ 3];
1627 | v[15] = ( v[15] >>> 16 ) | ( v[15] << 48 );
1628 | v[11] = v[11] + v[15];
1629 | v[ 7] ^= v[11];
1630 | v[ 7] = ( v[ 7] << 1 ) | ( v[ 7] >>> 63 );
1631 |
1632 | v[ 0] = v[ 0] + v[ 5] + m[15];
1633 | v[15] ^= v[ 0];
1634 | v[15] = ( v[15] << 32 ) | ( v[15] >>> 32 );
1635 | v[10] = v[10] + v[15];
1636 | v[ 5] ^= v[10];
1637 | v[ 5] = ( v[ 5] >>> 24 ) | ( v[ 5] << 40 );
1638 | v[ 0] = v[ 0] + v[ 5] + m[11];
1639 | v[15] ^= v[ 0];
1640 | v[15] = ( v[15] >>> 16 ) | ( v[15] << 48 );
1641 | v[10] = v[10] + v[15];
1642 | v[ 5] ^= v[10];
1643 | v[ 5] = ( v[ 5] << 1 ) | ( v[ 5] >>> 63 );
1644 |
1645 | v[ 1] = v[ 1] + v[ 6] + m[9];
1646 | v[12] ^= v[ 1];
1647 | v[12] = ( v[12] << 32 ) | ( v[12] >>> 32 );
1648 | v[11] = v[11] + v[12];
1649 | v[ 6] ^= v[11];
1650 | v[ 6] = ( v[ 6] >>> 24 ) | ( v[ 6] << 40 );
1651 | v[ 1] = v[ 1] + v[ 6] + + m[14];
1652 | v[12] ^= v[ 1];
1653 | v[12] = ( v[12] >>> 16 ) | ( v[12] << 48 );
1654 | v[11] = v[11] + v[12];
1655 | v[ 6] ^= v[11];
1656 | v[ 6] = ( v[ 6] << 1 ) | ( v[ 6] >>> 63 );
1657 |
1658 | v[ 2] = v[ 2] + v[ 7] + m[3];
1659 | v[13] ^= v[ 2];
1660 | v[13] = ( v[13] << 32 ) | ( v[13] >>> 32 );
1661 | v[ 8] = v[ 8] + v[13];
1662 | v[ 7] ^= v[ 8];
1663 | v[ 7] = ( v[ 7] >>> 24 ) | ( v[ 7] << 40 );
1664 | v[ 2] = v[ 2] + v[ 7] + m[12];
1665 | v[13] ^= v[ 2];
1666 | v[13] = ( v[13] >>> 16 ) | ( v[13] << 48 );
1667 | v[ 8] = v[ 8] + v[13];
1668 | v[ 7] ^= v[ 8];
1669 | v[ 7] = ( v[ 7] << 1 ) | ( v[ 7] >>> 63 );
1670 |
1671 | v[ 3] = v[ 3] + v[ 4] + m[13];
1672 | v[14] ^= v[ 3];
1673 | v[14] = ( v[14] << 32 ) | ( v[14] >>> 32 );
1674 | v[ 9] = v[ 9] + v[14];
1675 | v[ 4] ^= v[ 9];
1676 | v[ 4] = ( v[ 4] >>> 24 ) | ( v[ 4] << 40 );
1677 | v[ 3] = v[ 3] + v[ 4] + m[0];
1678 | v[14] ^= v[ 3];
1679 | v[14] = ( v[14] >>> 16 ) | ( v[14] << 48 );
1680 | v[ 9] = v[ 9] + v[14];
1681 | v[ 4] ^= v[ 9];
1682 | v[ 4] = ( v[ 4] << 1 ) | ( v[ 4] >>> 63 );
1683 | }
1684 |
1685 | ////////////////////////////////////////////////////////////////////////
1686 | /// Compression Kernel //////////////////////////////////////////// FINI
1687 | ////////////////////////////////////////////////////////////////////////
1688 |
1689 | /* TEMP - remove at will */
1690 | public static class Debug {
1691 | public static void dumpState (Blake2b.Engine e, final String mark) {
1692 | System.out.format("-- MARK == @ %s @ ===========\n", mark);
1693 | dumpArray("register t", e.state.t);
1694 | dumpArray("register h", e.state.h);
1695 | dumpArray("register f", e.state.f);
1696 | dumpArray("register offset", new long[]{e.state.buflen});
1697 | System.out.format("-- END MARK =================\n");
1698 | }
1699 | public static void dumpArray (final String label, final long[] b) {
1700 | System.out.format ( "-- %s -- :\n{\n", label );
1701 | for( int j = 0; j < b.length ; ++j ) {
1702 | System.out.format ( " [%2d] : %016X\n", j, b[j]);
1703 | }
1704 | System.out.format ( "}\n" );
1705 | }
1706 | public static void dumpBuffer (final PrintStream out, final String label, final byte[] b) {
1707 | dumpBuffer(out, label, b, 0, b.length);
1708 | }
1709 | public static void dumpBuffer (final PrintStream out, final byte[] b) {
1710 | dumpBuffer(out, null, b, 0, b.length);
1711 | }
1712 | public static void dumpBuffer (final PrintStream out, final byte[] b, final int offset, final int len) {
1713 | dumpBuffer(out, null, b, offset, len);
1714 | }
1715 | public static void dumpBuffer (final PrintStream out, final String label, final byte[] b, final int offset, final int len) {
1716 | if(label != null)
1717 | out.format ( "-- %s -- :\n", label );
1718 | out.format("{\n ", label);
1719 | for( int j = 0; j < len ; ++j ) {
1720 | out.format ("%02X", b[j + offset]);
1721 | if(j+1 < len) {
1722 | if ((j+1)%8==0) out.print("\n ");
1723 | else out.print(' ');
1724 | }
1725 | }
1726 | out.format("\n}\n");
1727 | }
1728 | }
1729 | /* TEMP - remove at will */
1730 |
1731 | // ---------------------------------------------------------------------
1732 | // Helper for assert error messages
1733 | // ---------------------------------------------------------------------
1734 | public static final class Assert {
1735 | public final static String exclusiveUpperBound = "'%s' %d is >= %d";
1736 | public final static String inclusiveUpperBound = "'%s' %d is > %d";
1737 | public final static String exclusiveLowerBound = "'%s' %d is <= %d";
1738 | public final static String inclusiveLowerBound = "'%s' %d is < %d";
1739 | static String assertFail(final String name, final T v, final String err, final T spec) {
1740 | new Exception().printStackTrace();
1741 | return String.format(err, name, v, spec);
1742 | }
1743 | }
1744 | // ---------------------------------------------------------------------
1745 | // Little Endian Codecs (inlined in the compressor)
1746 | /*
1747 | * impl note: these are not library funcs and used in hot loops, so no
1748 | * null or bounds checks are performed. For our purposes, this is OK.
1749 | */
1750 | // ---------------------------------------------------------------------
1751 |
1752 | public static class LittleEndian {
1753 | private static final byte[] hex_digits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
1754 | private static final byte[] HEX_digits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
1755 | /** @return hex rep of byte (lower case). */
1756 | static public String toHexStr (final byte[] b) {
1757 | return toHexStr (b, false); // because String class is slower.
1758 | }
1759 | static public String toHexStr (final byte[] b, boolean upperCase) {
1760 | final int len = b.length;
1761 | final byte[] digits = new byte[ len * 2 ];
1762 | final byte[] hex_rep = upperCase ? HEX_digits : hex_digits ;
1763 | for (int i = 0; i < len; i++) {
1764 | digits [ i*2 ] = hex_rep [ (byte) (b[i] >> 4 & 0x0F) ];
1765 | digits [ i*2+1 ] = hex_rep [ (byte) (b[i] & 0x0F) ];
1766 | }
1767 | return new String(digits);
1768 | }
1769 | public static int readInt (final byte[] b, final int off) {
1770 | int v0 = ((int)b [ off ] & 0xFF );
1771 | v0 |= ((int)b [ off + 1 ] & 0xFF ) << 8;
1772 | v0 |= ((int)b [ off + 2 ] & 0xFF ) << 16;
1773 | return v0 | ((int)b [ off + 3 ] ) << 24;
1774 | }
1775 | /** Little endian - byte[] to long */
1776 | public static long readLong (final byte[] b, final int off) {
1777 | long v0 = ((long)b [ off ] & 0xFF );
1778 | v0 |= ((long)b [ off + 1 ] & 0xFF ) << 8;
1779 | v0 |= ((long)b [ off + 2 ] & 0xFF ) << 16;
1780 | v0 |= ((long)b [ off + 3 ] & 0xFF ) << 24;
1781 | v0 |= ((long)b [ off + 4 ] & 0xFF ) << 32;
1782 | v0 |= ((long)b [ off + 5 ] & 0xFF ) << 40;
1783 | v0 |= ((long)b [ off + 6 ] & 0xFF ) << 48;
1784 | return v0 | ((long)b [ off + 7 ] ) << 56;
1785 | }
1786 | /** Little endian - long to byte[] */
1787 | public static void writeLong (long v, final byte[] b, final int off) {
1788 | b [ off ] = (byte) v; v >>>= 8;
1789 | b [ off + 1 ] = (byte) v; v >>>= 8;
1790 | b [ off + 2 ] = (byte) v; v >>>= 8;
1791 | b [ off + 3 ] = (byte) v; v >>>= 8;
1792 | b [ off + 4 ] = (byte) v; v >>>= 8;
1793 | b [ off + 5 ] = (byte) v; v >>>= 8;
1794 | b [ off + 6 ] = (byte) v; v >>>= 8;
1795 | b [ off + 7 ] = (byte) v;
1796 | }
1797 | /** Little endian - int to byte[] */
1798 | public static void writeInt (int v, final byte[] b, final int off) {
1799 | b [ off ] = (byte) v; v >>>= 8;
1800 | b [ off + 1 ] = (byte) v; v >>>= 8;
1801 | b [ off + 2 ] = (byte) v; v >>>= 8;
1802 | b [ off + 3 ] = (byte) v;
1803 | }
1804 | }
1805 | }
1806 | // ---------------------------------------------------------------------
1807 | // digest parameter (block)
1808 | // ---------------------------------------------------------------------
1809 | /** Blake2b configuration parameters block per spec */
1810 | // REVU: need to review a revert back to non-lazy impl TODO: do & bench
1811 | public static class Param implements AlgorithmParameterSpec {
1812 | interface Xoff {
1813 | int digest_length = 0;
1814 | int key_length = 1;
1815 | int fanout = 2;
1816 | int depth = 3;
1817 | int leaf_length = 4;
1818 | int node_offset = 8;
1819 | int node_depth = 16;
1820 | int inner_length = 17;
1821 | int reserved = 18;
1822 | int salt = 32;
1823 | int personal = 48;
1824 | }
1825 | public interface Default {
1826 | byte digest_length = Spec.max_digest_bytes;
1827 | byte key_length = 0;
1828 | byte fanout = 1;
1829 | byte depth = 1;
1830 | int leaf_length = 0;
1831 | long node_offset = 0;
1832 | byte node_depth = 0;
1833 | byte inner_length = 0;
1834 | }
1835 | /** default bytes of Blake2b parameter block */
1836 | final static byte[] default_bytes = new byte[ Spec.param_bytes ];
1837 | /** initialize default_bytes */
1838 | static {
1839 | default_bytes [ Xoff.digest_length ] = Default.digest_length;
1840 | default_bytes [ Xoff.key_length ] = Default.key_length;
1841 | default_bytes [ Xoff.fanout ] = Default.fanout;
1842 | default_bytes [ Xoff.depth ] = Default.depth;
1843 | /* def. leaf_length is 0 fill and already set by new byte[] */
1844 | /* def. node_offset is 0 fill and already set by new byte[] */
1845 | default_bytes [ Xoff.node_depth ] = Default.node_depth;
1846 | default_bytes [ Xoff.inner_length] = Default.inner_length;
1847 | /* def. salt is 0 fill and already set by new byte[] */
1848 | /* def. personal is 0 fill and already set by new byte[] */
1849 | }
1850 | /** default Blake2b h vector */
1851 | final static long[] default_h = new long [ Spec.state_space_len ];
1852 | static {
1853 | default_h [0] = readLong( default_bytes, 0 );
1854 | default_h [1] = readLong( default_bytes, 8 );
1855 | default_h [2] = readLong( default_bytes, 16 );
1856 | default_h [3] = readLong( default_bytes, 24 );
1857 | default_h [4] = readLong( default_bytes, 32 );
1858 | default_h [5] = readLong( default_bytes, 40 );
1859 | default_h [6] = readLong( default_bytes, 48 );
1860 | default_h [7] = readLong( default_bytes, 56 );
1861 |
1862 | default_h [0] ^= Spec.IV [0];
1863 | default_h [1] ^= Spec.IV [1];
1864 | default_h [2] ^= Spec.IV [2];
1865 | default_h [3] ^= Spec.IV [3];
1866 | default_h [4] ^= Spec.IV [4];
1867 | default_h [5] ^= Spec.IV [5];
1868 | default_h [6] ^= Spec.IV [6];
1869 | default_h [7] ^= Spec.IV [7];
1870 | }
1871 |
1872 | /** */
1873 | private boolean hasKey = false;
1874 | /** not sure how to make this secure - TODO */
1875 | private byte[] key_bytes = null;
1876 | /** */
1877 | private byte[] bytes = null;
1878 | /** */
1879 | private final long[] h = new long [ Spec.state_space_len ];
1880 |
1881 | /** */
1882 | public Param() {
1883 | System.arraycopy( default_h, 0, h, 0, Spec.state_space_len );
1884 | }
1885 | /** */
1886 | public long[] initialized_H () {
1887 | return h;
1888 | }
1889 | /** package only - copy returned - do not use in functional loops */
1890 | public byte[] getBytes() {
1891 | lazyInitBytes();
1892 | byte[] copy = new byte[ bytes.length ];
1893 | System.arraycopy( bytes, 0, copy, 0, bytes.length );
1894 | return copy;
1895 | }
1896 |
1897 | final byte getByteParam (final int xoffset) {
1898 | byte[] _bytes = bytes;
1899 | if(_bytes == null) _bytes = Param.default_bytes;
1900 | return _bytes[ xoffset];
1901 | }
1902 | final int getIntParam (final int xoffset) {
1903 | byte[] _bytes = bytes;
1904 | if(_bytes == null) _bytes = Param.default_bytes;
1905 | return readInt ( _bytes, xoffset);
1906 | }
1907 | final long getLongParam (final int xoffset) {
1908 | byte[] _bytes = bytes;
1909 | if(_bytes == null) _bytes = Param.default_bytes;
1910 | return readLong ( _bytes, xoffset);
1911 | }
1912 | // TODO same for tree params depth, fanout, inner, node-depth, node-offset
1913 | public final int getDigestLength() {
1914 | return (int) getByteParam ( Xoff.digest_length );
1915 | }
1916 | public final int getKeyLength() {
1917 | return (int) getByteParam ( Xoff.key_length );
1918 | }
1919 | public final int getFanout() {
1920 | return (int) getByteParam ( Xoff.fanout );
1921 | }
1922 | public final int getDepth() {
1923 | return (int) getByteParam ( Xoff.depth );
1924 | }
1925 | public final int getLeafLength() {
1926 | return getIntParam ( Xoff.leaf_length );
1927 | }
1928 | public final long getNodeOffset() {
1929 | return getLongParam ( Xoff.node_offset );
1930 | }
1931 | public final int getNodeDepth() {
1932 | return (int) getByteParam ( Xoff.node_depth );
1933 | }
1934 | public final int getInnerLength() {
1935 | return (int) getByteParam ( Xoff.inner_length );
1936 | }
1937 |
1938 | public final boolean hasKey() { return this.hasKey; }
1939 |
1940 | @Override public Param clone() {
1941 | final Param clone = new Param();
1942 | System.arraycopy(this.h, 0, clone.h, 0, h.length);
1943 | clone.lazyInitBytes();
1944 | System.arraycopy(this.bytes, 0, clone.bytes, 0, this.bytes.length);
1945 |
1946 | if(this.hasKey){
1947 | clone.hasKey = this.hasKey;
1948 | clone.key_bytes = new byte [Spec.max_key_bytes * 2];
1949 | System.arraycopy(this.key_bytes, 0, clone.key_bytes, 0, this.key_bytes.length);
1950 | }
1951 | return clone;
1952 | }
1953 | ////////////////////////////////////////////////////////////////////////
1954 | /// lazy setters - write directly to the bytes image of param block ////
1955 | ////////////////////////////////////////////////////////////////////////
1956 | final void lazyInitBytes () {
1957 | if( bytes == null ) {
1958 | bytes = new byte [ Spec.param_bytes ];
1959 | System.arraycopy(Param.default_bytes, 0, bytes, 0, Spec.param_bytes);
1960 | }
1961 | }
1962 | /* 0-7 inclusive */
1963 | public final Param setDigestLength(int len) {
1964 | assert len > 0 : assertFail("len", len, exclusiveLowerBound, 0);
1965 | assert len <= Spec.max_digest_bytes : assertFail("len", len, inclusiveUpperBound, Spec.max_digest_bytes);
1966 |
1967 | lazyInitBytes();
1968 | bytes[ Xoff.digest_length ] = (byte) len;
1969 | h[ 0 ] = readLong( bytes, 0 );
1970 | h[ 0 ] ^= Spec.IV [ 0 ];
1971 | return this;
1972 | }
1973 | public final Param setKey (final Key key) {
1974 | assert key != null : "key is null";
1975 | final byte[] keybytes = key.getEncoded();
1976 | assert keybytes != null : "key.encoded() is null";
1977 |
1978 | return this.setKey(keybytes);
1979 | }
1980 | public final Param setKey (final byte[] key) {
1981 | assert key != null : "key is null";
1982 | assert key.length >= 0 : assertFail("key.length", key.length, inclusiveUpperBound, 0);
1983 | assert key.length <= Spec.max_key_bytes : assertFail("key.length", key.length, inclusiveUpperBound, Spec.max_key_bytes);
1984 |
1985 | // zeropad keybytes
1986 | this.key_bytes = new byte [Spec.max_key_bytes * 2];
1987 | System.arraycopy ( key, 0, this.key_bytes, 0, key.length );
1988 | lazyInitBytes();
1989 | bytes[ Xoff.key_length ] = (byte) key.length; // checked c ref; this is correct
1990 | h[ 0 ] = readLong( bytes, 0 );
1991 | h[ 0 ] ^= Spec.IV [ 0 ];
1992 | this.hasKey = true;
1993 | return this;
1994 | }
1995 | public final Param setFanout(int fanout) {
1996 | assert fanout > 0 : assertFail("fanout", fanout, exclusiveLowerBound, 0);
1997 |
1998 | lazyInitBytes();
1999 | bytes[ Xoff.fanout ] = (byte) fanout;
2000 | h[ 0 ] = readLong( bytes, 0 );
2001 | h[ 0 ] ^= Spec.IV [ 0 ];
2002 | return this;
2003 | }
2004 | public final Param setDepth(int depth) {
2005 | assert depth > 0 : assertFail("depth", depth, exclusiveLowerBound, 0);
2006 |
2007 | lazyInitBytes();
2008 | bytes[ Xoff.depth ] = (byte) depth;
2009 | h[ 0 ] = readLong( bytes, 0 );
2010 | h[ 0 ] ^= Spec.IV [ 0 ];
2011 | return this;
2012 | }
2013 | public final Param setLeafLength(int leaf_length) {
2014 | assert leaf_length >= 0 : assertFail("leaf_length", leaf_length, inclusiveLowerBound, 0);
2015 |
2016 | lazyInitBytes();
2017 | writeInt (leaf_length, bytes, Xoff.leaf_length);
2018 | h[ 0 ] = readLong( bytes, 0 );
2019 | h[ 0 ] ^= Spec.IV [ 0 ];
2020 | return this;
2021 | }
2022 |
2023 | /* 8-15 inclusive */
2024 | public final Param setNodeOffset(long node_offset) {
2025 | assert node_offset >= 0 : assertFail("node_offset", node_offset, inclusiveLowerBound, 0);
2026 |
2027 | lazyInitBytes();
2028 | writeLong(node_offset, bytes, Xoff.node_offset);
2029 | h[ 1 ] = readLong( bytes, Xoff.node_offset );
2030 | h[ 1 ] ^= Spec.IV [ 1 ];
2031 | return this;
2032 | }
2033 |
2034 | /* 16-23 inclusive */
2035 | public final Param setNodeDepth(int node_depth) {
2036 | assert node_depth >= 0 : assertFail("node_depth", node_depth, inclusiveLowerBound, 0);
2037 |
2038 | lazyInitBytes();
2039 | bytes[ Xoff.node_depth ] = (byte) node_depth;
2040 | h[ 2 ] = readLong( bytes, Xoff.node_depth );
2041 | h[ 2 ] ^= Spec.IV [ 2 ];
2042 | h[ 3 ] = readLong( bytes, Xoff.node_depth + 8);
2043 | h[ 3 ] ^= Spec.IV [ 3 ];
2044 | return this;
2045 | }
2046 | public final Param setInnerLength(int inner_length) {
2047 | assert inner_length >= 0 : assertFail("inner_length", inner_length, inclusiveLowerBound, 0);
2048 |
2049 | lazyInitBytes();
2050 | bytes[ Xoff.inner_length] = (byte) inner_length;
2051 | h[ 2 ] = readLong( bytes, Xoff.node_depth );
2052 | h[ 2 ] ^= Spec.IV [ 2 ];
2053 | h[ 3 ] = readLong( bytes, Xoff.node_depth + 8);
2054 | h[ 3 ] ^= Spec.IV [ 3 ];
2055 | return this;
2056 | }
2057 |
2058 | /* 24-31 masked by reserved and remain unchanged */
2059 |
2060 | /* 32-47 inclusive */
2061 | public final Param setSalt(final byte[] salt) {
2062 | assert salt != null : "salt is null";
2063 | assert salt.length <= Spec.max_salt_bytes : assertFail("salt.length", salt.length, inclusiveUpperBound, Spec.max_salt_bytes);
2064 |
2065 | lazyInitBytes();
2066 | Arrays.fill ( bytes, Xoff.salt, Xoff.salt + Spec.max_salt_bytes, (byte)0);
2067 | System.arraycopy( salt, 0, bytes, Xoff.salt, salt.length );
2068 | h[ 4 ] = readLong( bytes, Xoff.salt );
2069 | h[ 4 ] ^= Spec.IV [ 4 ];
2070 | h[ 5 ] = readLong( bytes, Xoff.salt + 8 );
2071 | h[ 5 ] ^= Spec.IV [ 5 ];
2072 | return this;
2073 | }
2074 |
2075 | /* 48-63 inclusive */
2076 | public final Param setPersonal(byte[] personal) {
2077 | assert personal != null : "personal is null";
2078 | assert personal.length <= Spec.max_personalization_bytes : assertFail("personal.length", personal.length, inclusiveUpperBound, Spec.max_personalization_bytes);
2079 |
2080 | lazyInitBytes();
2081 | Arrays.fill ( bytes, Xoff.personal, Xoff.personal + Spec.max_personalization_bytes, (byte)0);
2082 | System.arraycopy( personal, 0, bytes, Xoff.personal, personal.length );
2083 | h[ 6 ] = readLong( bytes, Xoff.personal );
2084 | h[ 6 ] ^= Spec.IV [ 6 ];
2085 | h[ 7 ] = readLong( bytes, Xoff.personal + 8 );
2086 | h[ 7 ] ^= Spec.IV [ 7 ];
2087 | return this;
2088 | }
2089 | ////////////////////////////////////////////////////////////////////////
2090 | /// lazy setters /////////////////////////////////////////////////// END
2091 | ////////////////////////////////////////////////////////////////////////
2092 | }
2093 | }
2094 |
--------------------------------------------------------------------------------