├── .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 | 21 | 22 |

Usage

23 |
    24 |
  1. Browse to a website that displays Java stack traces through the Burp proxy
  2. 25 |
  3. The extension automatically detects stack traces in HTTP responses
  4. 26 |
  5. View fingerprinting results as scan issues in the Dashboard or Target tab
  6. 27 |
  7. Optional: Register for a free API key at beanstack.io to enable CVE detection
  8. 29 |
  9. Optional: Configure settings via the BeanStack menu or right-click context menu in the Issues list
  10. 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 | Installation screenshot 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 | Example issue screenshot 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 | --------------------------------------------------------------------------------