├── .github └── workflows │ └── docker-push.yml ├── Dockerfile ├── JavaCryptoDemo ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src │ └── main │ └── java │ ├── UseCaseEncryptionDecryption.java │ └── UseCasePasswordStorage.java ├── JavaCryptoModule ├── SecureJavaCrypto │ ├── bin │ │ └── main │ │ │ └── com │ │ │ └── secure │ │ │ └── crypto │ │ │ ├── cipher │ │ │ └── symmetric │ │ │ │ └── CipherAPI.class │ │ │ └── utils │ │ │ └── ReadPropertiesFile.class │ ├── build.gradle │ └── src │ │ └── main │ │ ├── java │ │ ├── com │ │ │ └── secure │ │ │ │ └── crypto │ │ │ │ ├── cipher │ │ │ │ └── symmetric │ │ │ │ │ ├── AESCipherAPI.java │ │ │ │ │ ├── ChaChaCipherAPI.java │ │ │ │ │ └── CipherAPI.java │ │ │ │ ├── digital_signature │ │ │ │ ├── ECDigitalSignatureAPI.java │ │ │ │ └── EdDigitalSignatureAPI.java │ │ │ │ ├── key_generation │ │ │ │ ├── AsymmetricKeyGeneration.java │ │ │ │ └── SymmetricKeyGeneration.java │ │ │ │ ├── key_management │ │ │ │ └── KeyManagementAPI.java │ │ │ │ ├── mac │ │ │ │ └── MACComputationAPI.java │ │ │ │ ├── message_digest │ │ │ │ └── MessageDigestAPI.java │ │ │ │ ├── password_storage │ │ │ │ ├── Argon2idPasswdStorage.java │ │ │ │ ├── BCryptPasswdStorage.java │ │ │ │ ├── PBKDF2PasswdStorage.java │ │ │ │ └── ScryptPasswdStorage.java │ │ │ │ ├── secure_random │ │ │ │ └── SecureRandomAPI.java │ │ │ │ └── utils │ │ │ │ └── ReadPropertiesFile.java │ │ └── module-info.java │ │ └── resources │ │ └── cryptoConfig.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew └── settings.gradle ├── ReadMe.md ├── SecureCryptoMicroservice ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── settings.gradle └── src │ └── main │ ├── java │ └── com │ │ └── secure │ │ └── crypto │ │ └── microservice │ │ └── securecryptomicroservice │ │ ├── SecureCryptoMicroServiceApplication.java │ │ ├── cipher │ │ └── symmetric │ │ │ ├── controller │ │ │ └── SymmetricEncryptionController.java │ │ │ └── entity │ │ │ └── SymmetricEncryption.java │ │ ├── digital_signature │ │ ├── controller │ │ │ └── DigitalSignatureController.java │ │ └── entity │ │ │ └── DigitalSignature.java │ │ ├── key_management │ │ ├── controller │ │ │ └── KeyManagementController.java │ │ └── entity │ │ │ └── KeyStoreEntity.java │ │ ├── mac │ │ ├── controller │ │ │ └── HmacController.java │ │ └── entity │ │ │ └── Hmac.java │ │ ├── message_digest │ │ ├── controller │ │ │ └── MessageDigestController.java │ │ └── entity │ │ │ └── Digest.java │ │ └── password_storage │ │ ├── controller │ │ └── PasswordStorageController.java │ │ └── entity │ │ └── KDFPasswordStorageEntity.java │ └── resources │ └── application.properties └── doc ├── api ├── digital_signature.md ├── encryption_decryption.md ├── hashing.md ├── key_management.md ├── message_authentication_code.md └── password_storage.md └── images └── JavaCrypto-Architecture.png /.github/workflows/docker-push.yml: -------------------------------------------------------------------------------- 1 | name: Secure Java Crypto 2 | 3 | on : push 4 | 5 | jobs: 6 | main: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - 10 | name: Setup QEMU 11 | uses: docker/setup-qemu-action@v1 12 | - 13 | name: Set up Docker Buildx 14 | uses: docker/setup-buildx-action@v1 15 | - 16 | name: Login to DockerHub 17 | uses: docker/login-action@v1 18 | with: 19 | #registry: index.docker.io 20 | username: ${{ secrets.DOCKERHUB_USERNAME }} 21 | password: ${{ secrets.DOCKERHUB_PASSWORD }} 22 | - 23 | name: Build and push 24 | id: docker_build 25 | uses: docker/build-push-action@v2 26 | with: 27 | push: true 28 | tags: 1mansis/javacrypto:latest 29 | build-args: | 30 | arg1=value1 31 | arg2=value2 32 | - 33 | name: Image digest 34 | run: echo ${{ steps.docker_build.outputs.digest }} 35 | 36 | #jobs: 37 | # main: 38 | # runs-on: ubuntu-latest 39 | # steps: 40 | # - uses: docker/build-push-action@v2 41 | # name: Pushing to Docker Hub 42 | # with: 43 | # push: true 44 | # #image: 1mansis/javacrypto 45 | # tags: 1mansis/javacrypto:latest 46 | # registry: hub.docker.com 47 | # username: ${{ secrets.DOCKERHUB_USERNAME }} 48 | # password: ${{ secrets.DOCKERHUB_PASSWORD }} 49 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:18-alpine 2 | RUN apk update && apk add git zip unzip curl 3 | WORKDIR /gradle 4 | RUN curl -L https://services.gradle.org/distributions/gradle-7.4.2-bin.zip -o gradle-7.4.2-bin.zip 5 | RUN unzip gradle-7.4.2-bin.zip 6 | ENV GRADLE_HOME=/gradle/gradle-7.4.2 7 | ENV PATH=$PATH:$GRADLE_HOME/bin 8 | 9 | RUN git clone https://github.com/1MansiS/JavaCrypto.git 10 | WORKDIR JavaCrypto/JavaCryptoModule 11 | RUN gradle clean compileJava assemble --stacktrace 12 | WORKDIR ../SecureCryptoMicroservice 13 | RUN gradle clean compileJava assemble --stacktrace 14 | ENTRYPOINT ["java", "-jar" , "build/libs/SecureCryptoMicroservice-0.0.2-SNAPSHOT.jar"] 15 | EXPOSE 8080 16 | 17 | -------------------------------------------------------------------------------- /JavaCryptoDemo/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | } 4 | 5 | group 'com.secure.crypto' 6 | version '1.0-SNAPSHOT' 7 | 8 | repositories { 9 | mavenCentral() 10 | } 11 | 12 | dependencies { 13 | testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1' 14 | testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' 15 | } 16 | 17 | test { 18 | useJUnitPlatform() 19 | } -------------------------------------------------------------------------------- /JavaCryptoDemo/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1MansiS/JavaCrypto/7a70c0241501c4ac7fcd25fcf033325f8bf33f8c/JavaCryptoDemo/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /JavaCryptoDemo/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /JavaCryptoDemo/gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 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 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 84 | 85 | APP_NAME="Gradle" 86 | APP_BASE_NAME=${0##*/} 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 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 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | MAX_FD=$( ulimit -H -n ) || 147 | warn "Could not query maximum file descriptor limit" 148 | esac 149 | case $MAX_FD in #( 150 | '' | soft) :;; #( 151 | *) 152 | ulimit -n "$MAX_FD" || 153 | warn "Could not set maximum file descriptor limit to $MAX_FD" 154 | esac 155 | fi 156 | 157 | # Collect all arguments for the java command, stacking in reverse order: 158 | # * args from the command line 159 | # * the main class name 160 | # * -classpath 161 | # * -D...appname settings 162 | # * --module-path (only if needed) 163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 164 | 165 | # For Cygwin or MSYS, switch paths to Windows format before running java 166 | if "$cygwin" || "$msys" ; then 167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 169 | 170 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 171 | 172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 173 | for arg do 174 | if 175 | case $arg in #( 176 | -*) false ;; # don't mess with options #( 177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 178 | [ -e "$t" ] ;; #( 179 | *) false ;; 180 | esac 181 | then 182 | arg=$( cygpath --path --ignore --mixed "$arg" ) 183 | fi 184 | # Roll the args list around exactly as many times as the number of 185 | # args, so each arg winds up back in the position where it started, but 186 | # possibly modified. 187 | # 188 | # NB: a `for` loop captures its iteration list before it begins, so 189 | # changing the positional parameters here affects neither the number of 190 | # iterations, nor the values presented in `arg`. 191 | shift # remove old arg 192 | set -- "$@" "$arg" # push replacement arg 193 | done 194 | fi 195 | 196 | # Collect all arguments for the java command; 197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 198 | # shell script including quotes and variable substitutions, so put them in 199 | # double quotes to make sure that they get re-expanded; and 200 | # * put everything else in single quotes, so that it's not re-expanded. 201 | 202 | set -- \ 203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 204 | -classpath "$CLASSPATH" \ 205 | org.gradle.wrapper.GradleWrapperMain \ 206 | "$@" 207 | 208 | # Use "xargs" to parse quoted args. 209 | # 210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 211 | # 212 | # In Bash we could simply go: 213 | # 214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 215 | # set -- "${ARGS[@]}" "$@" 216 | # 217 | # but POSIX shell has neither arrays nor command substitution, so instead we 218 | # post-process each arg (as a line of input to sed) to backslash-escape any 219 | # character that might be a shell metacharacter, then use eval to reverse 220 | # that process (while maintaining the separation between arguments), and wrap 221 | # the whole thing up as a single "set" statement. 222 | # 223 | # This will of course break if any of these variables contains a newline or 224 | # an unmatched quote. 225 | # 226 | 227 | eval "set -- $( 228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 229 | xargs -n1 | 230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 231 | tr '\n' ' ' 232 | )" '"$@"' 233 | 234 | exec "$JAVACMD" "$@" 235 | -------------------------------------------------------------------------------- /JavaCryptoDemo/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 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /JavaCryptoDemo/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'JavaCryptoDemo' 2 | 3 | -------------------------------------------------------------------------------- /JavaCryptoDemo/src/main/java/UseCaseEncryptionDecryption.java: -------------------------------------------------------------------------------- 1 | package PACKAGE_NAME;public class UseCaseEncryptionDecryption { 2 | } 3 | -------------------------------------------------------------------------------- /JavaCryptoDemo/src/main/java/UseCasePasswordStorage.java: -------------------------------------------------------------------------------- 1 | import org.bouncycastle.crypto.generators.Argon2BytesGenerator; 2 | import org.bouncycastle.crypto.params.Argon2Parameters; 3 | 4 | import java.security.DrbgParameters; 5 | import java.security.NoSuchAlgorithmException; 6 | import java.security.SecureRandom; 7 | import java.util.Base64; 8 | 9 | import static java.security.DrbgParameters.Capability.PR_AND_RESEED; 10 | 11 | public class JavaCryptoDemo { 12 | public static void main(String args[]) { 13 | 14 | String plainTextPasswd = args[0]; 15 | 16 | // Step 1. Generate Salt 17 | SecureRandom drbgSecureRandom = null; 18 | try { 19 | drbgSecureRandom = SecureRandom.getInstance("DRBG", // Uses default configured DRBG mechanism which is usually SHA-256 Hash. Good idea to check in your java.security file. 20 | DrbgParameters.instantiation(256, // Security strength, default is 128 as configured in java.security 21 | PR_AND_RESEED, // prediction resistance, and re-seeding support. 22 | // Prediction Resistance == compromise of the DRBG internal state has no effect on the security of future DRBG outputs. 23 | // Reseeding == Periodic reseeding, to avoid too many output from a seed 24 | "any_hardcoded_string".getBytes())); 25 | } catch (NoSuchAlgorithmException e) { System.out.println("DRBG algorithm for generating CSPRNG is not supported"); } 26 | byte[] salt = new byte[32]; 27 | drbgSecureRandom.nextBytes(salt); 28 | 29 | /* 30 | curl 'http://localhost:8080/compute-salt' -s | json_pp 31 | */ 32 | 33 | // Step 2. Compute Password hash for storage using Argon2 algorithm 34 | int NO_OF_ITERATIONS = 10; 35 | int ALLOCATED_MEMORY = 16777; 36 | int PARALLELISM = 4; 37 | 38 | Argon2Parameters.Builder argon2Parameters = (new Argon2Parameters.Builder()). 39 | withVersion(Argon2Parameters.ARGON2_id) // For password storage recommended mode of operation to protect against both side-channel and timing attacks. 40 | .withIterations(NO_OF_ITERATIONS) // No of times memory array will be filled 41 | .withMemoryAsKB(ALLOCATED_MEMORY) // Amount of memory assigned, in KB 42 | .withParallelism(PARALLELISM) // # of Parallel processing units 43 | .withSecret(plainTextPasswd.getBytes()) //password 44 | .withSalt(Base64.getDecoder().decode(salt)); // 256 bits of CSPRNG unique salt 45 | 46 | Argon2BytesGenerator argon2passwordGenerator = new Argon2BytesGenerator(); 47 | argon2passwordGenerator.init(argon2Parameters.build()); // Initializing Argon2 algorithm with configured parameters 48 | 49 | // Array to store computed hash 50 | byte[] passwdHash = new byte[32]; 51 | 52 | 53 | argon2passwordGenerator.generateBytes(plainTextPasswd.getBytes(), passwdHash); // Finally, putting it all together to compute the password hash 54 | String passwordHash = Base64.getEncoder().encodeToString(passwdHash); 55 | System.out.println("Argon2 computed Password Hash == " + passwordHash); 56 | 57 | /* 58 | curl 'http://localhost:8080/compute-kdf-passwd' -X POST -H "Content-type: application/json" -s \ 59 | -d '{"base64-salt":"...", 60 | "passwd":"mysupersecretpasswordtobestored!!!"}'| json_pp 61 | */ 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /JavaCryptoModule/SecureJavaCrypto/bin/main/com/secure/crypto/cipher/symmetric/CipherAPI.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1MansiS/JavaCrypto/7a70c0241501c4ac7fcd25fcf033325f8bf33f8c/JavaCryptoModule/SecureJavaCrypto/bin/main/com/secure/crypto/cipher/symmetric/CipherAPI.class -------------------------------------------------------------------------------- /JavaCryptoModule/SecureJavaCrypto/bin/main/com/secure/crypto/utils/ReadPropertiesFile.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1MansiS/JavaCrypto/7a70c0241501c4ac7fcd25fcf033325f8bf33f8c/JavaCryptoModule/SecureJavaCrypto/bin/main/com/secure/crypto/utils/ReadPropertiesFile.class -------------------------------------------------------------------------------- /JavaCryptoModule/SecureJavaCrypto/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | // id "com.zyxist.chainsaw" version "0.3.1" 4 | } 5 | 6 | /*configurations { 7 | testCompile 8 | }*/ 9 | 10 | version '3.0-RELEASE' 11 | 12 | sourceCompatibility = JavaVersion.VERSION_18 13 | targetCompatibility = JavaVersion.VERSION_18 14 | 15 | repositories { 16 | mavenCentral() 17 | } 18 | 19 | dependencies { 20 | // Mainly for Argon2id, bcrypt and scrypt algorithms 21 | implementation group: 'org.bouncycastle', name: 'bcprov-jdk18on', version: '1.71' 22 | } 23 | 24 | -------------------------------------------------------------------------------- /JavaCryptoModule/SecureJavaCrypto/src/main/java/com/secure/crypto/cipher/symmetric/AESCipherAPI.java: -------------------------------------------------------------------------------- 1 | package com.secure.crypto.cipher.symmetric; 2 | 3 | import com.secure.crypto.secure_random.SecureRandomAPI; 4 | import com.secure.crypto.utils.ReadPropertiesFile; 5 | 6 | import javax.crypto.*; 7 | import javax.crypto.spec.GCMParameterSpec; 8 | import javax.crypto.spec.SecretKeySpec; 9 | import java.security.*; 10 | import java.util.Base64; 11 | 12 | public class AESCipherAPI { 13 | 14 | private ReadPropertiesFile readPropertiesFile = new ReadPropertiesFile(); 15 | 16 | /*** 17 | * Encrypt using AES-GCM Authenticated Encryption with Associated Data 18 | * @param base64EncodeKey : Symmetric Key, base64 encoded 19 | * @param initializationVector : Initialization Vector 20 | * @param aad : Associated Data 21 | * @param plainText : Plain Text message to be encrypted 22 | * @return : Cipher Text, base64 encoded 23 | */ 24 | public String encrypt(String base64EncodeKey, String initializationVector, String aad, String plainText) { 25 | Cipher cipher = initializeCipher(base64EncodeKey, initializationVector, aad, Cipher.ENCRYPT_MODE); 26 | 27 | byte[] cipherArray = null ; 28 | try { 29 | cipherArray = cipher.doFinal(plainText.getBytes()); 30 | } catch (IllegalBlockSizeException | BadPaddingException e) {System.out.println("Exception: while trying to perform encryption. Error message " + e.getMessage());} 31 | 32 | return Base64.getEncoder().encodeToString(cipherArray); 33 | } 34 | 35 | /*** 36 | * Decrypt using AES-GCM Authenticated Encryption with Associated Data 37 | * @param base64EncodedKey : Symmetric Key, base64 encoded, same as used in encryption 38 | * @param base64EncodedIV : initialization vector, same as used in encryption 39 | * @param aad : Associated Data 40 | * @param cipherText : cipher text, base64 encoded 41 | * @return : Plain text string 42 | */ 43 | public String decrypt(String base64EncodedKey, String base64EncodedIV, String aad, String cipherText) { 44 | Cipher cipher = initializeCipher(base64EncodedKey,base64EncodedIV, aad, Cipher.DECRYPT_MODE ); 45 | 46 | byte[] plainTextArray = null; 47 | 48 | try { 49 | plainTextArray = cipher.doFinal(Base64.getDecoder().decode(cipherText)); 50 | } catch (IllegalBlockSizeException | BadPaddingException e) {System.out.println("Exception: while trying to perform encryption. Error message " + e.getMessage() );} 51 | 52 | return new String(plainTextArray); 53 | 54 | } 55 | 56 | /* 57 | To avoid code duplication, since Cipher initialization is almost identical for encryption & decryption. 58 | */ 59 | private Cipher initializeCipher(String base64EncodeKey, String base64EncodedIV, String aad, int mode) { 60 | 61 | Cipher cipher = null ; 62 | SecureRandomAPI aesRandomizer = new SecureRandomAPI(); 63 | 64 | // Initialize GCM Parameters 65 | // Same base64EncodeKey, IV and GCM Specs are to be used for encryption and decryption. 66 | GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(Integer.parseInt(readPropertiesFile.getValue("TAG_BIT_LENGTH")), Base64.getDecoder().decode(base64EncodedIV)); 67 | 68 | try { 69 | cipher = Cipher.getInstance(readPropertiesFile.getValue("AES_ENC_TRANSFORMATION_STRING")); 70 | } catch (NoSuchAlgorithmException |NoSuchPaddingException e) {System.out.println("Exception: While trying to get Cipher instance with " + readPropertiesFile.getValue("AES_ENC_TRANSFORMATION_STRING") + "transformation. Error message " + e.getMessage()); } 71 | 72 | SecretKey aesKey = new SecretKeySpec(Base64.getDecoder().decode(base64EncodeKey), readPropertiesFile.getValue("DEFAULT_ENC_ALGO")); 73 | 74 | try { 75 | cipher.init(mode, aesKey, gcmParameterSpec, aesRandomizer.drbgSecureRandom()); // Using DRBG mechanism based CSPRNG 76 | } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {System.out.println("Exception: While trying to instantiate Cipher with " +readPropertiesFile.getValue("AES_ENC_TRANSFORMATION_STRING") + "transformation for encryption. Error message " + e.getMessage()); } 77 | 78 | cipher.updateAAD(aad.getBytes()); // add AAD tag data before encrypting or decryption 79 | 80 | return cipher; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /JavaCryptoModule/SecureJavaCrypto/src/main/java/com/secure/crypto/cipher/symmetric/ChaChaCipherAPI.java: -------------------------------------------------------------------------------- 1 | package com.secure.crypto.cipher.symmetric; 2 | 3 | 4 | import com.secure.crypto.secure_random.SecureRandomAPI; 5 | 6 | import javax.crypto.*; 7 | import javax.crypto.spec.IvParameterSpec; 8 | import javax.crypto.spec.SecretKeySpec; 9 | import java.security.InvalidAlgorithmParameterException; 10 | import java.security.InvalidKeyException; 11 | import java.security.NoSuchAlgorithmException; 12 | import java.security.spec.AlgorithmParameterSpec; 13 | import java.util.Base64; 14 | 15 | public class ChaChaCipherAPI { 16 | 17 | private String CHACHA20_POLY1305_TRANSFORMATION_STRING = "ChaCha20-Poly1305/None/NoPadding"; 18 | private String CHACHA20_ENC_ALGO = "ChaCha20"; 19 | 20 | /*** 21 | * Encrypt using ChaCha20-Poly1305 Authenticated Encryption 22 | * @param base64EncodeKey : Symmetric Key, base64 encoded 23 | * @param base64EncodeIV : 12 byte initialization vector 24 | * @param plainText : Plain Text message to be encoded 25 | * @return : Cipher Text, base64 encoded 26 | */ 27 | public String encrypt(String base64EncodeKey, String base64EncodeIV, String plainText) { 28 | Cipher chachaCipher = initChaChaCipher(Cipher.ENCRYPT_MODE,base64EncodeKey,base64EncodeIV); 29 | byte[] cipherTextArray = null; 30 | try { 31 | cipherTextArray = chachaCipher.doFinal(plainText.getBytes()); 32 | } catch (IllegalBlockSizeException | BadPaddingException e) {System.out.println("Issues in encrypting with " + CHACHA20_POLY1305_TRANSFORMATION_STRING + " " + e.getMessage()) ;} 33 | return Base64.getEncoder().encodeToString(cipherTextArray); 34 | } 35 | 36 | /*** 37 | * Decrypt using ChaCha20-Poly1305 Authenticated Decryption 38 | * @param base64EncodeKey : Symmetric Key, base64 encoded, same as used in encryption 39 | * @param base64EncodeIV : 12 byte initialization vector, same as used in encryption 40 | * @param base64EncodedCipherText : cipher text, base64 encoded 41 | * @return : Plain text string 42 | */ 43 | public String decrypt(String base64EncodeKey, String base64EncodeIV, String base64EncodedCipherText) { 44 | Cipher chachaCipher = initChaChaCipher(Cipher.DECRYPT_MODE, base64EncodeKey, base64EncodeIV); 45 | byte[] plainTextArray = null; 46 | try { 47 | plainTextArray = chachaCipher.doFinal(Base64.getDecoder().decode(base64EncodedCipherText)); 48 | } catch (IllegalBlockSizeException | BadPaddingException e) {System.out.println("Issues decrypting with " + CHACHA20_POLY1305_TRANSFORMATION_STRING + " " + e.getMessage() ); } 49 | return new String(plainTextArray); 50 | } 51 | 52 | /*** 53 | * Since initializing a cipher is similar for encryption and decryption, created a common method for code reuse 54 | * @param mode 55 | * @param base64EncodeKey 56 | * @param base64EncodeIV 57 | * @return 58 | */ 59 | private Cipher initChaChaCipher(int mode, String base64EncodeKey, String base64EncodeIV) { 60 | 61 | Cipher cipher = null; 62 | 63 | SecureRandomAPI chachaRandomizer = new SecureRandomAPI(); 64 | try { 65 | cipher = Cipher.getInstance(CHACHA20_POLY1305_TRANSFORMATION_STRING); 66 | } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {System.out.println(CHACHA20_POLY1305_TRANSFORMATION_STRING + " has some issues") ;} 67 | 68 | // Transparent specification for configuring 12 byte nonce 69 | AlgorithmParameterSpec ivParameterSpec = new IvParameterSpec(Base64.getDecoder().decode(base64EncodeIV)) ; 70 | 71 | // Getting Symmetric Key spec from base64 encoded string 72 | SecretKeySpec secretKeySpec = new SecretKeySpec(Base64.getDecoder().decode(base64EncodeKey),CHACHA20_ENC_ALGO); 73 | 74 | try { 75 | cipher.init(mode, secretKeySpec, ivParameterSpec, chachaRandomizer.drbgSecureRandom()); // Using DRBG mechanism based randomizer 76 | } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {System.out.println("Issues in initializing " + CHACHA20_POLY1305_TRANSFORMATION_STRING + " " + e.getMessage()); } 77 | 78 | return cipher; 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /JavaCryptoModule/SecureJavaCrypto/src/main/java/com/secure/crypto/cipher/symmetric/CipherAPI.java: -------------------------------------------------------------------------------- 1 | package com.secure.crypto.cipher.symmetric; 2 | 3 | import java.util.Base64; 4 | 5 | public class CipherAPI { 6 | private AESCipherAPI aesCipherAPI = new AESCipherAPI(); 7 | private ChaChaCipherAPI chaChaCipherAPI = new ChaChaCipherAPI(); 8 | 9 | public String encrypt(String base64EncodeKey, String base64EncodedInitializationVector, String aad, String plainText) { 10 | String base64EncoderCipherText = ""; 11 | 12 | if(Base64.getDecoder().decode(base64EncodedInitializationVector).length == 16) { // IV == 16 bytes for AES 13 | base64EncoderCipherText = aesCipherAPI.encrypt( 14 | base64EncodeKey, 15 | base64EncodedInitializationVector, 16 | aad, 17 | plainText 18 | ); 19 | } else { 20 | base64EncoderCipherText = chaChaCipherAPI.encrypt(base64EncodeKey, 21 | base64EncodedInitializationVector, 22 | plainText); 23 | } 24 | 25 | return base64EncoderCipherText; 26 | } 27 | 28 | public String decrypt(String base64EncodedKey, String base64EncodedIV, String aad, String base64EncodedCipherText) { 29 | String plainText = ""; 30 | 31 | if(Base64.getDecoder().decode(base64EncodedIV).length == 16) { // IV == 16 bytes for AES 32 | plainText = aesCipherAPI.decrypt( 33 | base64EncodedKey, 34 | base64EncodedIV, 35 | aad, 36 | base64EncodedCipherText 37 | ); 38 | } else { 39 | plainText = chaChaCipherAPI.decrypt( 40 | base64EncodedKey, 41 | base64EncodedIV, 42 | base64EncodedCipherText 43 | ); 44 | } 45 | 46 | return plainText; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /JavaCryptoModule/SecureJavaCrypto/src/main/java/com/secure/crypto/digital_signature/ECDigitalSignatureAPI.java: -------------------------------------------------------------------------------- 1 | package com.secure.crypto.digital_signature; 2 | 3 | import com.secure.crypto.utils.ReadPropertiesFile; 4 | 5 | import java.security.*; 6 | import java.security.spec.InvalidKeySpecException; 7 | import java.security.spec.PKCS8EncodedKeySpec; 8 | import java.security.spec.X509EncodedKeySpec; 9 | import java.util.Base64; 10 | 11 | public class ECDigitalSignatureAPI { 12 | 13 | private ReadPropertiesFile readPropertiesFile = new ReadPropertiesFile(); 14 | private String ECC_ALGO = readPropertiesFile.getValue("ECC_ALGO"); 15 | private String ECC_ALGO_KEY_NAME = readPropertiesFile.getValue("ECC_ALGO_KEY_NAME"); 16 | 17 | /*** 18 | * This method digitally signs input plain text message using ECDSA using NIST curves. 19 | * @param message : Plain text message to be signed 20 | * @param base64PrivateKey : Generated private key (base64) 21 | * @return : base64 encoded signature 22 | */ 23 | public String sign(String message, String base64PrivateKey) { 24 | 25 | Signature sign = null; 26 | try { 27 | sign = Signature.getInstance(ECC_ALGO); 28 | } catch (NoSuchAlgorithmException e) {System.out.println("Exception: While initializing " + ECC_ALGO + " algorithm");} 29 | 30 | PrivateKey privateKey = null; 31 | 32 | try { 33 | privateKey = KeyFactory.getInstance(ECC_ALGO_KEY_NAME).generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(base64PrivateKey))); 34 | } catch (InvalidKeySpecException | NoSuchAlgorithmException e) {System.out.println("Exception: While retrieving private key");} 35 | 36 | try { 37 | sign.initSign(privateKey); 38 | } catch (InvalidKeyException e) {System.out.println("Exception: While initializing signature object with private key");} 39 | 40 | try { 41 | sign.update(message.getBytes()); 42 | } catch (SignatureException e) {System.out.println("Exception: while updating message");} 43 | 44 | byte[] signArray = new byte[0]; 45 | 46 | try { 47 | signArray = sign.sign(); 48 | } catch (SignatureException e) {System.out.println("Exception: while signing");} 49 | 50 | return Base64.getEncoder().encodeToString(signArray); 51 | } 52 | 53 | /*** 54 | * This method verifies if signature matches with input message. 55 | * @param message : Input plain text message 56 | * @param base64PublicKey: Generated public key (base64 encoded), of corresponding private key used to sign the message 57 | * @param base64Signature : Base64 encoded signature received while signing 58 | * @return : If signature matches or not, establishing authenticity, integrity and non-repudiation of the input message. 59 | */ 60 | public boolean verify(String message, String base64PublicKey, String base64Signature) { 61 | Signature verify = null; 62 | try { 63 | verify = Signature.getInstance(ECC_ALGO); 64 | } catch (NoSuchAlgorithmException e) {System.out.println("Exception: while initializing signature object withh " + ECC_ALGO + " algorithn");} 65 | 66 | PublicKey publicKey = null; 67 | 68 | try { 69 | publicKey = KeyFactory.getInstance(ECC_ALGO_KEY_NAME).generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(base64PublicKey))); 70 | } catch (InvalidKeySpecException | NoSuchAlgorithmException e) {System.out.println("Exception: while retrieving public key");} 71 | 72 | try { 73 | verify.initVerify(publicKey); 74 | } catch (InvalidKeyException e) {System.out.println("Exception: while preparing for verification, initializing with public key ");} 75 | 76 | try { 77 | verify.update(message.getBytes()); 78 | } catch (SignatureException e) {System.out.println("Exception: while updating plain text message");} 79 | 80 | boolean isVerified = false; 81 | 82 | try { 83 | isVerified = verify.verify(Base64.getDecoder().decode(base64Signature)); 84 | } catch (SignatureException e) {System.out.println("Exception: while verifying");} 85 | 86 | return isVerified; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /JavaCryptoModule/SecureJavaCrypto/src/main/java/com/secure/crypto/digital_signature/EdDigitalSignatureAPI.java: -------------------------------------------------------------------------------- 1 | package com.secure.crypto.digital_signature; 2 | 3 | import com.secure.crypto.utils.ReadPropertiesFile; 4 | 5 | import java.security.*; 6 | import java.security.spec.InvalidKeySpecException; 7 | import java.security.spec.PKCS8EncodedKeySpec; 8 | import java.security.spec.X509EncodedKeySpec; 9 | import java.util.Base64; 10 | 11 | public class EdDigitalSignatureAPI { 12 | private ReadPropertiesFile readPropertiesFile = new ReadPropertiesFile(); 13 | 14 | private String EDDSA_ALGO = readPropertiesFile.getValue("EDDSA_ALGO"); 15 | 16 | /*** 17 | * This method digitally signs input plain text message using Edward Curve Ed25519. 18 | * @param message : Plain text message to be signed 19 | * @param base64PrivateKey : Generated private key (base64) 20 | * @return : base64 encoded signature 21 | */ 22 | public String sign(String message, String base64PrivateKey) { 23 | 24 | Signature sign = null; 25 | try { 26 | sign = Signature.getInstance(EDDSA_ALGO); 27 | } catch (NoSuchAlgorithmException e) {System.out.println("Problem initializing " + EDDSA_ALGO);} 28 | 29 | PrivateKey privateKey = null; 30 | try { 31 | privateKey = KeyFactory.getInstance(EDDSA_ALGO).generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(base64PrivateKey))); 32 | } catch (InvalidKeySpecException | NoSuchAlgorithmException e) {System.out.println("Exception: While retrieving private key using PKCS8 specs for " + EDDSA_ALGO);} 33 | 34 | try { 35 | sign.initSign(privateKey); 36 | } catch (InvalidKeyException e) {System.out.println("Exception: While signing using " + EDDSA_ALGO);} 37 | 38 | try { 39 | sign.update(message.getBytes()); 40 | } catch (SignatureException e) {System.out.println("Exception: While updating plaintext message ");} 41 | 42 | byte[] signArray = new byte[0]; 43 | 44 | try { 45 | signArray = sign.sign(); 46 | } catch (SignatureException e) {System.out.println("Exception: while signing using " + EDDSA_ALGO);} 47 | 48 | return Base64.getEncoder().encodeToString(signArray); 49 | } 50 | 51 | /*** 52 | * This method verifies if signature matches with input message. 53 | * @param message : Input plain text message 54 | * @param base64PublicKey: Generated public key (base64 encoded), of corresponding private key used to sign the message 55 | * @param base64Signature : Base64 encoded signature received while signing 56 | * @return : If signature matches or not, establishing authenticity, integrity and non-repudiation of the input message. 57 | */ 58 | public boolean verify(String message, String base64PublicKey, String base64Signature) { 59 | 60 | Signature verify = null; 61 | try { 62 | verify = Signature.getInstance(EDDSA_ALGO); 63 | } catch (NoSuchAlgorithmException e) {System.out.println("Exception: While initializing " + EDDSA_ALGO);} 64 | 65 | PublicKey publicKey = null; 66 | try { 67 | publicKey = KeyFactory.getInstance(EDDSA_ALGO).generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(base64PublicKey))); 68 | } catch (InvalidKeySpecException | NoSuchAlgorithmException e) {System.out.println("Exception: While retrieving public key using X509 spec for " + EDDSA_ALGO);e.printStackTrace();} 69 | 70 | try { 71 | verify.initVerify(publicKey); 72 | } catch (InvalidKeyException e) {System.out.println("Exception: While initializing with Public Key for usage with "+ EDDSA_ALGO);} 73 | 74 | try { 75 | verify.update(message.getBytes()); 76 | } catch (SignatureException e) {System.out.println("Exception : While updating with message");} 77 | 78 | boolean isVerified = false; 79 | 80 | try { 81 | isVerified = verify.verify(Base64.getDecoder().decode(base64Signature)); 82 | } catch (SignatureException e) {System.out.println("Exception: While, verifying signature");} 83 | 84 | return isVerified; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /JavaCryptoModule/SecureJavaCrypto/src/main/java/com/secure/crypto/key_generation/AsymmetricKeyGeneration.java: -------------------------------------------------------------------------------- 1 | package com.secure.crypto.key_generation; 2 | 3 | import java.security.*; 4 | import java.security.spec.ECGenParameterSpec; 5 | 6 | public class AsymmetricKeyGeneration { 7 | 8 | private String EC_CURVE_NAME = "secp384r1" ; 9 | private String ECC_ALGO = "EC" ; 10 | 11 | private String EDWARD_CURVE = "Ed25519" ; 12 | 13 | /** 14 | * Generated asymmetric keys to be used with NIST curves 15 | * @return 16 | */ 17 | public KeyPair generateECAsymmetricKey() { 18 | KeyPairGenerator keyPairGenerator = null; 19 | 20 | try { 21 | keyPairGenerator = KeyPairGenerator.getInstance(ECC_ALGO); 22 | } catch (NoSuchAlgorithmException e) {System.out.println(ECC_ALGO + " is initialized");} 23 | 24 | ECGenParameterSpec egps = new ECGenParameterSpec(EC_CURVE_NAME); 25 | 26 | try { 27 | keyPairGenerator.initialize(egps); 28 | } catch (InvalidAlgorithmParameterException e) {System.out.println(EC_CURVE_NAME + " not able to be initialized");} 29 | 30 | return keyPairGenerator.generateKeyPair(); 31 | } 32 | 33 | /*** 34 | * Generates asymmetric keys to be used with Edward Curves 35 | * @return 36 | */ 37 | public KeyPair generateEdAsymmetricKey() { 38 | KeyPairGenerator keyPairGenerator = null; 39 | try { 40 | keyPairGenerator = KeyPairGenerator.getInstance(EDWARD_CURVE); // Unlike any other key generation no extra initialization required such as key size, or actual curve name 41 | } catch (NoSuchAlgorithmException e) {System.out.println("Exception: While initializing " + EDWARD_CURVE) ;} 42 | 43 | return keyPairGenerator.generateKeyPair(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /JavaCryptoModule/SecureJavaCrypto/src/main/java/com/secure/crypto/key_generation/SymmetricKeyGeneration.java: -------------------------------------------------------------------------------- 1 | package com.secure.crypto.key_generation; 2 | 3 | import com.secure.crypto.utils.ReadPropertiesFile; 4 | 5 | import javax.crypto.KeyGenerator; 6 | import javax.crypto.SecretKey; 7 | import java.security.NoSuchAlgorithmException; 8 | import java.security.SecureRandom; 9 | import java.util.Base64; 10 | 11 | public class SymmetricKeyGeneration { 12 | 13 | private ReadPropertiesFile readPropertiesFile = new ReadPropertiesFile(); 14 | /*** 15 | * Returns a Base64 encoded Symmetric Key of provided algorithm and key size. 16 | * @param encryptionAlgo supported encrypted algorithm 17 | * @param symmetricKeySize required key size. 18 | * @param secRandom Provided configured instance of SecureRandom 19 | * @return base64 encoded version of generated symmetric key 20 | */ 21 | public String generateSymmetricKey(String encryptionAlgo, int symmetricKeySize, SecureRandom secRandom) { 22 | 23 | SecretKey secretKey = null; 24 | KeyGenerator keyGenerator = null ; 25 | 26 | if(encryptionAlgo == null) {encryptionAlgo = readPropertiesFile.getValue("DEFAULT_ENC_ALGO");} 27 | else {encryptionAlgo = "ChaCha20";} 28 | 29 | // Preparing Key generation object 30 | try { 31 | keyGenerator = KeyGenerator.getInstance(encryptionAlgo); 32 | } catch (NoSuchAlgorithmException e) { System.out.println(encryptionAlgo + "is not supported"); } 33 | 34 | keyGenerator.init(symmetricKeySize , secRandom); 35 | 36 | // Key generation 37 | secretKey = keyGenerator.generateKey(); 38 | 39 | return Base64.getEncoder().encodeToString(secretKey.getEncoded()); 40 | } 41 | } -------------------------------------------------------------------------------- /JavaCryptoModule/SecureJavaCrypto/src/main/java/com/secure/crypto/key_management/KeyManagementAPI.java: -------------------------------------------------------------------------------- 1 | package com.secure.crypto.key_management; 2 | 3 | import javax.crypto.SecretKey; 4 | import javax.crypto.spec.SecretKeySpec; 5 | import java.io.FileNotFoundException; 6 | import java.io.FileOutputStream; 7 | import java.io.IOException; 8 | import java.security.KeyStore; 9 | import java.security.KeyStoreException; 10 | import java.security.NoSuchAlgorithmException; 11 | import java.security.cert.CertificateException; 12 | 13 | public class KeyManagementAPI { 14 | private String KEY_STORE_FILE = "keystore.p12"; 15 | 16 | public boolean addSecretKey(String keyStorePassword, String entryPassword, String alias, byte[] secretKey) { 17 | KeyStore keyStore = null; 18 | 19 | try { 20 | // This will give us PKCS12 keystore initialized object with encryption and hashing setup as shown in above diagram, unless changed 21 | keyStore = KeyStore.getInstance(KeyStore.getDefaultType()) ; 22 | 23 | // null could be deceiving, but it just means empty keystore. Using a password which is used just for keystore and is different from each individual entries. 24 | keyStore.load(null, keyStorePassword.toCharArray()); 25 | } catch (KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException e) { 26 | System.out.println("Exception: Problem creating KeyStore file" + e.getMessage()); 27 | System.exit(0); 28 | } 29 | 30 | // Assuming secret key is computed outside this code, and passed here as a byte array. So some key transformation 31 | KeyStore.SecretKeyEntry secretKeyEntry = new KeyStore.SecretKeyEntry( 32 | new SecretKeySpec( 33 | secretKey, 34 | 0, 35 | secretKey.length, 36 | "AES") 37 | ); 38 | 39 | try { 40 | keyStore.setEntry( 41 | alias, // Entry specific alias. 42 | secretKeyEntry, 43 | new KeyStore.PasswordProtection(entryPassword.toCharArray()) // Entry specific password 44 | 45 | ); 46 | 47 | } catch (KeyStoreException e) { 48 | System.out.println("Exception: while storing secret key with alias " + alias + " with exception" + e.getMessage()); 49 | System.exit(0); 50 | } 51 | 52 | try (FileOutputStream fos = new FileOutputStream(KEY_STORE_FILE)) { 53 | keyStore.store(fos, keyStorePassword.toCharArray()); // Using keystore password 54 | } catch (IOException | KeyStoreException | NoSuchAlgorithmException | CertificateException e) { 55 | System.out.println("Exception: while storing keystore file with secret key " + e.getMessage()); 56 | System.exit(0); 57 | } 58 | 59 | boolean retVal = false; 60 | try { 61 | if(keyStore.isKeyEntry(alias)) { 62 | retVal = true; 63 | } else { 64 | retVal = false; 65 | } 66 | } catch (KeyStoreException e) { 67 | System.out.println("Exception: key with alias " + alias + " not found. Exception : " + e.getMessage()); 68 | } 69 | 70 | return retVal; 71 | } 72 | } -------------------------------------------------------------------------------- /JavaCryptoModule/SecureJavaCrypto/src/main/java/com/secure/crypto/mac/MACComputationAPI.java: -------------------------------------------------------------------------------- 1 | package com.secure.crypto.mac; 2 | 3 | import com.secure.crypto.key_generation.SymmetricKeyGeneration; 4 | import com.secure.crypto.secure_random.SecureRandomAPI; 5 | import com.secure.crypto.utils.ReadPropertiesFile; 6 | 7 | import javax.crypto.Mac; 8 | import javax.crypto.SecretKey; 9 | import javax.crypto.spec.SecretKeySpec; 10 | import java.security.InvalidKeyException; 11 | import java.security.NoSuchAlgorithmException; 12 | import java.util.Base64; 13 | 14 | public class MACComputationAPI { 15 | 16 | private SymmetricKeyGeneration symmetricKeyGeneration = new SymmetricKeyGeneration(); 17 | private ReadPropertiesFile readPropertiesFile = new ReadPropertiesFile(); 18 | 19 | private SecureRandomAPI secureRandomAPI = new SecureRandomAPI(); 20 | 21 | public String computeMacKey(String encryptionAlgo) { 22 | 23 | if(encryptionAlgo == null) {encryptionAlgo = readPropertiesFile.getValue("DEFAULT_HMAC_ALGO");} 24 | 25 | int symmetricKeySize = 256; // ToDo: Assign Key size based on selected block size of HMAC ALGO choosen 26 | 27 | return symmetricKeyGeneration.generateSymmetricKey(encryptionAlgo, 28 | symmetricKeySize, 29 | secureRandomAPI.drbgSecureRandom()); 30 | } 31 | 32 | /*** 33 | * Provided plain text message, symmetric key and hmac algorithm, compute HMAC 34 | * @param base64SymmKey : Symmetric key generated 35 | * @param content : Plain text message to be hmaced 36 | * @param hmacAlgo : Algorithm to use to compute HMAC, note: symm key should be generated using same algorithm 37 | * @return : base64 encoded HMAC value 38 | */ 39 | public String computeMac(String base64SymmKey, String content, String hmacAlgo) { 40 | if(hmacAlgo == null) {hmacAlgo = readPropertiesFile.getValue("DEFAULT_HMAC_ALGO");} 41 | 42 | SecretKey secretKey = new SecretKeySpec( 43 | Base64.getDecoder().decode(base64SymmKey), 44 | 0, 45 | Base64.getDecoder().decode(base64SymmKey).length, 46 | hmacAlgo); 47 | 48 | Mac mac = null; 49 | try { 50 | mac = Mac.getInstance(hmacAlgo); 51 | } catch (NoSuchAlgorithmException e) {System.out.println("Exception: Unable to initialize " + hmacAlgo);} 52 | 53 | try { 54 | mac.init(secretKey); 55 | } catch (InvalidKeyException e) {System.out.println("Exception: Unable to initialize with provided secrey key");} 56 | 57 | mac.update(content.getBytes()); 58 | 59 | return Base64.getEncoder().encodeToString(mac.doFinal()) ; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /JavaCryptoModule/SecureJavaCrypto/src/main/java/com/secure/crypto/message_digest/MessageDigestAPI.java: -------------------------------------------------------------------------------- 1 | package com.secure.crypto.message_digest; 2 | 3 | import com.secure.crypto.utils.ReadPropertiesFile; 4 | 5 | import java.io.BufferedInputStream; 6 | import java.io.ByteArrayInputStream; 7 | import java.io.IOException; 8 | import java.security.MessageDigest; 9 | import java.security.NoSuchAlgorithmException; 10 | import java.util.Base64; 11 | 12 | public class MessageDigestAPI { 13 | 14 | private ReadPropertiesFile readPropertiesFile = new ReadPropertiesFile(); 15 | 16 | /* 17 | This API generates the message digest on input data, using configured Message Digest algorithm. 18 | 19 | @param data : Base64 encode 20 | @return : Base64 encoded hash 21 | */ 22 | public String generateMessageDigest(String data, String hashingAlgo) { 23 | 24 | 25 | BufferedInputStream bis = new BufferedInputStream(new ByteArrayInputStream(data.getBytes())); 26 | 27 | byte[] buff = new byte[Integer.parseInt(readPropertiesFile.getValue("MD_DATA_READ_BUFF"))]; // read configured no of bytes at a time 28 | if(hashingAlgo == null) {hashingAlgo = readPropertiesFile.getValue("MD_ALGO");} 29 | 30 | int count = 0; 31 | 32 | MessageDigest digest = null; 33 | 34 | try { 35 | digest = MessageDigest.getInstance(hashingAlgo); // Returns instance of configured algorithm implementation, from the first provider configured in java.security config file. 36 | } catch (NoSuchAlgorithmException e) {System.out.println("Algorithm " + hashingAlgo + " not supported by default provider. Error message " + e.getMessage()); System.exit(0);} 37 | 38 | try { 39 | while ((count = bis.read()) > 0) { 40 | digest.update(buff, 0, count); // repeated apply update method, till all content of this string is bundled up for digesting 41 | } 42 | } catch(IOException io) {System.out.println("Exception: while reading from data string. Error message "+ io.getMessage());} 43 | 44 | byte[] hash = digest.digest(); // once u have all content bundled up, than only apply digesting. 45 | 46 | return Base64.getEncoder().encodeToString(hash); // to return in a human readable format 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /JavaCryptoModule/SecureJavaCrypto/src/main/java/com/secure/crypto/password_storage/Argon2idPasswdStorage.java: -------------------------------------------------------------------------------- 1 | package com.secure.crypto.password_storage; 2 | 3 | import com.secure.crypto.utils.ReadPropertiesFile; 4 | import org.bouncycastle.crypto.generators.Argon2BytesGenerator; 5 | import org.bouncycastle.crypto.params.Argon2Parameters; 6 | 7 | import java.util.Base64; 8 | 9 | public class Argon2idPasswdStorage { 10 | 11 | private ReadPropertiesFile readPropertiesFile = new ReadPropertiesFile(); 12 | 13 | /* 14 | This API, returns Argonid version of plain text password ready for storage 15 | 16 | @param plainTextPasswd: Clear text password 17 | @param salt: Base64 encoded salt value 18 | 19 | @return : Base64 Encoded password to be stored 20 | */ 21 | 22 | public String generatePasswdForStorage(String plainTextPasswd, String salt) { 23 | 24 | // Build Argon2 Parameters 25 | Argon2Parameters.Builder argon2Parameters = (new Argon2Parameters.Builder()). 26 | withVersion(Argon2Parameters.ARGON2_id) // For password storage recommended mode of operation to protect against both side-channel and timing attacks. 27 | .withIterations(Integer.parseInt(readPropertiesFile.getValue("NO_OF_ITERATIONS"))) // No of times memory array will be filled 28 | .withMemoryAsKB(Integer.parseInt(readPropertiesFile.getValue("ALLOCATED_MEMORY"))) // Amount of memory assigned, in KB 29 | .withParallelism(Integer.parseInt(readPropertiesFile.getValue("PARALLELISM"))) // # of Parallel processing units 30 | .withSecret(plainTextPasswd.getBytes()) //password 31 | .withSalt(Base64.getDecoder().decode(salt)); // 256 bits of CSPRNG unique salt 32 | 33 | Argon2BytesGenerator argon2passwordGenerator = new Argon2BytesGenerator(); 34 | argon2passwordGenerator.init(argon2Parameters.build()); // Initializing Argon2 algorithm with configured parameters 35 | 36 | // Array to store computed hash 37 | byte[] passwdHash = new byte[32]; 38 | 39 | 40 | argon2passwordGenerator.generateBytes(plainTextPasswd.getBytes(), passwdHash); // Finally, putting it all together to compute the password hash 41 | 42 | return Base64.getEncoder().encodeToString(passwdHash); 43 | 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /JavaCryptoModule/SecureJavaCrypto/src/main/java/com/secure/crypto/password_storage/BCryptPasswdStorage.java: -------------------------------------------------------------------------------- 1 | package com.secure.crypto.password_storage; 2 | 3 | import com.secure.crypto.utils.ReadPropertiesFile; 4 | import org.bouncycastle.crypto.generators.BCrypt; 5 | import java.util.Base64; 6 | 7 | public class BCryptPasswdStorage { 8 | 9 | private ReadPropertiesFile readPropertiesFile = new ReadPropertiesFile(); 10 | 11 | public String generatePasswdForStorage(String plainTextPasswd, String salt) { 12 | 13 | byte[] passwd = BCrypt.generate( 14 | plainTextPasswd.getBytes(), // byte array of user supplied, low entropy password 15 | Base64.getDecoder().decode(salt), // 256 bit (16 byte), CSPRNG generated salt 16 | Integer.parseInt(readPropertiesFile.getValue("COST_FACTOR")) // cost factor, performs 2^14 iterations. 17 | ); 18 | 19 | return Base64.getEncoder().encodeToString(passwd); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /JavaCryptoModule/SecureJavaCrypto/src/main/java/com/secure/crypto/password_storage/PBKDF2PasswdStorage.java: -------------------------------------------------------------------------------- 1 | package com.secure.crypto.password_storage; 2 | 3 | import com.secure.crypto.utils.ReadPropertiesFile; 4 | 5 | import javax.crypto.SecretKeyFactory; 6 | import javax.crypto.spec.PBEKeySpec; 7 | import java.security.NoSuchAlgorithmException; 8 | import java.security.spec.InvalidKeySpecException; 9 | import java.util.Base64; 10 | 11 | public class PBKDF2PasswdStorage { 12 | 13 | private ReadPropertiesFile readPropertiesFile = new ReadPropertiesFile(); 14 | 15 | /* 16 | This API, returns PBKDF2 version of plain text password ready for storage 17 | 18 | @param plainTextPasswd: Clear text password 19 | @param salt: Base64 encoded salt value 20 | 21 | @return : Base64 Encoded password to be stored 22 | */ 23 | public String generatePasswdForStorage(String plainTextPasswd, String salt) { 24 | // Strings are immutatable, so there is no way to change/nullify/modify its content after use. So always, collect and store security sensitive information in a char array instead. 25 | char[] charEnteredPassword = plainTextPasswd.toCharArray() ; 26 | 27 | PBEKeySpec keySpec = null ; 28 | 29 | try { 30 | keySpec = new PBEKeySpec(charEnteredPassword, 31 | Base64.getDecoder().decode(salt), 32 | Integer.parseInt(readPropertiesFile.getValue("ITERATION_COUNT")), 33 | Integer.parseInt(readPropertiesFile.getValue("DERIVED_KEY_LENGTH")) * 8); 34 | } catch(NullPointerException|IllegalArgumentException e) {System.out.println("One of the argument is illegal. Salt " + salt + " may be of 0 length, iteration count " + readPropertiesFile.getValue("ITERATION_COUNT") + " is not positive or derived key length " + readPropertiesFile.getValue("DERIVED_KEY_LENGTH") + " is not positive." ); System.out.println("Error :" + e.getMessage()); System.exit(0);} 35 | 36 | SecretKeyFactory pbkdfKeyFactory = null ; 37 | 38 | try { 39 | pbkdfKeyFactory = SecretKeyFactory.getInstance(readPropertiesFile.getValue("PBKDF_ALGO")) ; 40 | } catch (NullPointerException|NoSuchAlgorithmException e) {System.out.println("Specified algorithm " + readPropertiesFile.getValue("PBKDF_ALGO") + "is not available by the provider " + pbkdfKeyFactory.getProvider().getName());System.out.println("Error : " + e.getMessage()); System.exit(0);} 41 | 42 | byte[] pbkdfHashedArray = null ; 43 | 44 | try { 45 | pbkdfHashedArray = pbkdfKeyFactory.generateSecret(keySpec).getEncoded() ; 46 | } catch (InvalidKeySpecException e) {System.out.println("Specified key specification is inappropriate"); System.out.println("Error : " + e.getMessage()); System.exit(0);} 47 | 48 | return Base64.getEncoder().encodeToString(pbkdfHashedArray); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /JavaCryptoModule/SecureJavaCrypto/src/main/java/com/secure/crypto/password_storage/ScryptPasswdStorage.java: -------------------------------------------------------------------------------- 1 | package com.secure.crypto.password_storage; 2 | 3 | import com.secure.crypto.utils.ReadPropertiesFile; 4 | import org.bouncycastle.crypto.generators.SCrypt; 5 | import java.util.Base64; 6 | 7 | public class ScryptPasswdStorage { 8 | 9 | private ReadPropertiesFile readPropertiesFile = new ReadPropertiesFile(); 10 | 11 | public String generatePasswdForStorage(String plainTextPasswd, String salt) { 12 | byte[] passwd = SCrypt.generate( 13 | plainTextPasswd.getBytes(), 14 | Base64.getDecoder().decode(salt), 15 | Integer.parseInt(readPropertiesFile.getValue("CPU_MEMORY_COST")), 16 | Integer.parseInt(readPropertiesFile.getValue("BLOCK_SIZE")) , 17 | Integer.parseInt(readPropertiesFile.getValue("PARALLELIZATION")), 18 | Integer.parseInt(readPropertiesFile.getValue("OUTPUT_LENGTH")) 19 | ); 20 | 21 | return Base64.getEncoder().encodeToString(passwd); 22 | 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /JavaCryptoModule/SecureJavaCrypto/src/main/java/com/secure/crypto/secure_random/SecureRandomAPI.java: -------------------------------------------------------------------------------- 1 | package com.secure.crypto.secure_random; 2 | 3 | import java.security.DrbgParameters; 4 | import java.security.NoSuchAlgorithmException; 5 | import java.security.SecureRandom; 6 | import java.security.Security; 7 | 8 | import static java.security.DrbgParameters.Capability.PR_AND_RESEED; 9 | 10 | public class SecureRandomAPI { 11 | 12 | /*** 13 | * Configure SecureRandom object, with most secure configurations. Using NIST approved DRBG mechanism (SHA-256 based), 256 bit security strength, prediction resistant and reseeding option. 14 | * @return DRBG mechanism based, 256 bit security strength, prediction resistant and reseeding complaint SecureRandom object 15 | */ 16 | public SecureRandom drbgSecureRandom() { 17 | SecureRandom drbgSecureRandom = null; 18 | try { 19 | drbgSecureRandom = SecureRandom.getInstance("DRBG" , // Uses default configured DRBG mechanism which is usually SHA-256 Hash. Good idea to check in your java.security file. 20 | DrbgParameters.instantiation(256, // Security strength, default is 128 as configured in java.security 21 | PR_AND_RESEED, // prediction resistance, and re-seeding support. 22 | // Prediction Resistance == compromise of the DRBG internal state has no effect on the security of future DRBG outputs. 23 | // Reseeding == Periodic reseeding, to avoid too many output from a seed 24 | "any_hardcoded_string".getBytes())); 25 | System.out.println("Entropy is being collected from " + Security.getProperty("securerandom.source")); 26 | } catch (NoSuchAlgorithmException e) { System.out.println("DRBG algorithm for generating CSPRNG is not supported"); } 27 | 28 | return drbgSecureRandom; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /JavaCryptoModule/SecureJavaCrypto/src/main/java/com/secure/crypto/utils/ReadPropertiesFile.java: -------------------------------------------------------------------------------- 1 | package com.secure.crypto.utils; 2 | 3 | import java.io.IOException; 4 | import java.util.Properties; 5 | 6 | public class ReadPropertiesFile { 7 | 8 | private String pathToPropertiesFile = "cryptoConfig.properties"; 9 | public String getValue(String key) { 10 | Properties prop = loadPropertiesFile(); 11 | 12 | return prop.getProperty(key); 13 | 14 | } 15 | 16 | private Properties loadPropertiesFile() { 17 | Properties prop = new Properties(); 18 | 19 | try { 20 | prop.load(getClass().getClassLoader().getResourceAsStream(pathToPropertiesFile)); 21 | 22 | } catch (IOException ioException) { 23 | System.out.println("Couldn't load properties file " + pathToPropertiesFile + " due to " + ioException); 24 | } 25 | 26 | return prop; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /JavaCryptoModule/SecureJavaCrypto/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | module SecureJavaCrypto { 2 | 3 | 4 | exports com.secure.crypto.secure_random; 5 | 6 | exports com.secure.crypto.cipher.symmetric; 7 | exports com.secure.crypto.key_generation; 8 | 9 | exports com.secure.crypto.message_digest; 10 | 11 | exports com.secure.crypto.mac; 12 | 13 | //requires bcprov.jdk16; 14 | requires org.bouncycastle.provider; 15 | exports com.secure.crypto.digital_signature; 16 | 17 | exports com.secure.crypto.password_storage; 18 | 19 | exports com.secure.crypto.key_management; 20 | } -------------------------------------------------------------------------------- /JavaCryptoModule/SecureJavaCrypto/src/main/resources/cryptoConfig.properties: -------------------------------------------------------------------------------- 1 | # Cipher Object to perform symmetric encryption/decryption 2 | 3 | # Specifying algorithm key will be used for KeyGeneration 4 | DEFAULT_ENC_ALGO=AES 5 | # Always use entire transformation string, which specifies algorithm, mode of operation and padding. 6 | # If mode and padding is not specified, it defaults to a very insecure ECB mode. 7 | AES_ENC_TRANSFORMATION_STRING=AES/GCM/NoPadding 8 | # Specifying Key size to be used 9 | AES_KEY_SIZE=256 10 | TAG_BIT_LENGTH=128 11 | 12 | # HMAC 13 | DEFAULT_HMAC_ALGO=HmacSHA512 14 | HMAC_KEY_SIZE=256 15 | 16 | # Password Storage 17 | ## PBKDF2 Algorithm Parameters 18 | PBKDF_ALGO=PBKDF2WithHmacSHA512 19 | ITERATION_COUNT=1500000 20 | DERIVED_KEY_LENGTH=256 21 | 22 | ## bcrypt Algorithm Parameters 23 | COST_FACTOR=14 24 | 25 | ## scrypt Algorithm Parameters 26 | BLOCK_SIZE=16 27 | PARALLELIZATION=1 28 | CPU_MEMORY_COST=65536 29 | OUTPUT_LENGTH=32 30 | 31 | ## Argon2 Algorithm Parameters 32 | NO_OF_ITERATIONS=10 33 | ALLOCATED_MEMORY=16777 34 | PARALLELISM=4 35 | 36 | # Message Digest 37 | MD_ALGO=SHA-512 38 | MD_DATA_READ_BUFF=8192 39 | 40 | # Digital Signatures 41 | ## ECDSA (Using NIST curves) 42 | ECC_ALGO=SHA512withECDSA 43 | ECC_ALGO_KEY_NAME=EC 44 | 45 | ## Edward Curves 46 | EDDSA_ALGO=Ed25519 -------------------------------------------------------------------------------- /JavaCryptoModule/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1MansiS/JavaCrypto/7a70c0241501c4ac7fcd25fcf033325f8bf33f8c/JavaCryptoModule/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /JavaCryptoModule/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /JavaCryptoModule/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or 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 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /JavaCryptoModule/settings.gradle: -------------------------------------------------------------------------------- 1 | include 'SecureJavaCrypto' 2 | 3 | -------------------------------------------------------------------------------- /ReadMe.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | JavaCrypto is easy-to-use, light-weight, modern library for all core cryptographic operations needed to build higher-level cryptographic tools. It's a drop-and-hook bundle of APIs responsible for performing various cryptographic primitives in the most secure way possible while using Java Cryptography Architecture (JCA). It includes APIs for: 4 | 5 | - Encryption & Decryption 6 | - Hashing 7 | - Message Authentication Code 8 | - Digital Signatures 9 | - Password Storage etc 10 | 11 | 12 | # Architecture 13 | 14 | `JavaCrypto` supports modern design principles and architecture. 15 | 16 | ![JavaCrypto Architecture](doc/images/JavaCrypto-Architecture.png) 17 | 18 | It can be esily-injected using either: 19 | 20 | 1. **JavaCryptoModule:** This module provides all all of box cryptographic primitives as an API, mainly using Java Cryptography Architecture (JCA). Some of the APIs provided are: 21 | 22 | * Generating a cryptographically secure pseudo random number, in an OS agnostic way 23 | * Encryption and decryption 24 | * Calculating message digests 25 | * Calculating message authentication codes 26 | * Signing and verifying digital signatures 27 | * Secured password storage 28 | 29 | 2 **SecureCryptoMicroservice:** Microservice wrapped around above module which exposes typical cryptographic use cases. 30 | 31 | 3 **[1MansiS/JavaCrypto docker image](https://hub.docker.com/repository/docker/1mansis/javacrypto):** Easily deployable image in any microservice or cluster environment thru your CI/CD pipeline. This image is auto-published with each new code checkin to this repo via github action. 32 | 33 | 34 | ## Getting Started 35 | 36 | Quickest way to start experimenting with the JavaCrypto's REST APIs is to pull the docker image: 37 | 38 | ```plaintext 39 | docker pull 1mansis/javacrypto 40 | docker run -p 8080:8080 1mansis/javacrypto 41 | ``` 42 | 43 | ## Build Locally 44 | 45 | You can directly access the underlying APIs via the `JavaCryptoModule`. To build the module locally, just `git clone` this repository and: 46 | 47 | ``` 48 | cd JavaCryptoModule/SecureJavaCrypto 49 | gradle clean build 50 | ``` 51 | 52 | If you wish to access the underlying APIs via `SecureCryptoMicroservice`, you can 53 | 54 | ``` 55 | cd SecureCryptoMicroservice 56 | gradle clean build 57 | ``` 58 | 59 | ### Requirements: 60 | 61 | - Java Version 18 62 | - Gradle build tool 63 | 64 | 65 | 66 | ## Everyday UseCases 67 | 68 | No better way to get cracking with any REST API than to use `curl`. Lets look at some everyday usecases using the latest docker image: 69 | 70 | ### Authentication: 71 | 72 | Core of any good authentication system is making sure passwords are stored securely, so that in an unfortunate event of a breach, passwords aren't cracked offline. The most secure way to do this is by using a memory hard Key Derivative Function. Taking away all the complexities of choosing the right algorithm and choosing its secure parameters, below is how a typical Request/Response steps would look like: 73 | 74 | 75 | 1. Generate Salt: 76 | 77 | Request: 78 | 79 | ```plaintext 80 | curl 'http://localhost:8080/compute-salt' -s | json_pp 81 | ``` 82 | 83 | Response: 84 | 85 | ```plaintext 86 | { 87 | "base64-salt" : "UIneZVONMIM4nmliROlJkMu4zkJE73TfhvFit1GW0qs=" 88 | } 89 | ``` 90 | 91 | Using the salt generated above, compute the password hash to be stored in the database: 92 | 93 | 94 | 2. Compute Hash, using above generated salt 95 | 96 | Request: 97 | 98 | ``` 99 | curl 'http://localhost:8080/compute-kdf-passwd' -X POST -H "Content-type: application/json" -s \ 100 | -d '{"base64-salt":"UIneZVONMIM4nmliROlJkMu4zkJE73TfhvFit1GW0qs=", 101 | "passwd":"mysupersecretpasswordtobestored!!!"}'| json_pp 102 | ``` 103 | 104 | Response: 105 | 106 | ```plaintext 107 | { 108 | "base64-kdf-passwd-hash" : "XdWuZ758kOai3/Mn6PmtVe1bSVtRvedpbO7KpwLFayo=", 109 | "base64-salt" : "UIneZVONMIM4nmliROlJkMu4zkJE73TfhvFit1GW0qs=", 110 | "passwd" : "mysupersecretpasswordtobestored!!!" 111 | } 112 | ``` 113 | 114 | ### Encryption: 115 | 116 | There are often situations where we need to send encrypted information over the wires. Lets see how to take away all the complexities of using the secure Cipher scheme, padding, keying material, initialization vectors etc: 117 | 118 | 119 | 1. Generate Encryption Parameters: 120 | 121 | Leaving the default secure choices to the tool, we would need just initialization vector & symmetric key for an encryption scheme. 122 | 123 | Request: 124 | 125 | ``` 126 | curl 'http://localhost:8080/generate-encryption-parameters' -s | json_pp 127 | ``` 128 | 129 | Response: 130 | 131 | ```plaintext 132 | { 133 | "base64_iv" : "FVRMdBrqSE7lLYCBkuTLZw==", 134 | "base64_symmetric_key" : "ZsLQyM8bPqts+DFcFTVhy6WZ+jpw8NDx5oNZHjq5Io4=" 135 | } 136 | ``` 137 | 138 | Using Symmetric Key and Initialization Vector generated in above request, lets see how to encrypt a secret message: 139 | 140 | 141 | 2. Encrypt: 142 | 143 | Request: 144 | 145 | ```plaintext 146 | curl 'http://localhost:8080/encrypt' -X POST -H "Content-Type: application/json" -d \ 147 | '{"base64_iv" : "FVRMdBrqSE7lLYCBkuTLZw==", 148 | "base64_symmetric_key" : "ZsLQyM8bPqts+DFcFTVhy6WZ+jpw8NDx5oNZHjq5Io4=", 149 | "plain_text":"Hello Crypto World!", 150 | "aad":"localhost"}' -s | json_pp 151 | ``` 152 | 153 | Response: 154 | 155 | ```plaintext 156 | { 157 | "aad" : "localhost", 158 | "base64_cipher_text" : "plMqkDjcqDHkeqvWnuYZH+L6Oysqf/7p4YRNdFrHWz9oqG8=", 159 | "base64_iv" : "FVRMdBrqSE7lLYCBkuTLZw==", 160 | "base64_symmetric_key" : "ZsLQyM8bPqts+DFcFTVhy6WZ+jpw8NDx5oNZHjq5Io4=", 161 | "plain_text" : "Hello Crypto World!" 162 | } 163 | ``` 164 | 165 | 3. Decryption: 166 | Similarly, using above keying materials and cipher text, lets decrypt the plaintext back. 167 | 168 | Request: 169 | 170 | ```plaintext 171 | curl 'http://localhost:8080/decrypt' -X POST -H "Content-Type: application/json" \ 172 | -d '{"base64_iv":"FVRMdBrqSE7lLYCBkuTLZw==", 173 | "base64_symmetric_key":"ZsLQyM8bPqts+DFcFTVhy6WZ+jpw8NDx5oNZHjq5Io4=", 174 | "aad":"localhost", 175 | "base64_cipher_text":"plMqkDjcqDHkeqvWnuYZH+L6Oysqf/7p4YRNdFrHWz9oqG8="}' -s | json_pp 176 | ``` 177 | 178 | Response: 179 | 180 | ```plaintext 181 | { 182 | "aad" : "localhost", 183 | "base64_cipher_text" : "plMqkDjcqDHkeqvWnuYZH+L6Oysqf/7p4YRNdFrHWz9oqG8=", 184 | "base64_iv" : "FVRMdBrqSE7lLYCBkuTLZw==", 185 | "base64_symmetric_key" : "ZsLQyM8bPqts+DFcFTVhy6WZ+jpw8NDx5oNZHjq5Io4=", 186 | "plain_text" : "Hello Crypto World!" 187 | } 188 | ``` 189 | 190 | 191 | # REST API Docs 192 | 193 | While sending REST API requests, you must include `'Content-Type':'application/json'` in the HTTP header. 194 | 195 | ## Encryption/Decryption 196 | [Encryption Decryption](doc/api/encryption_decryption.md) 197 | 198 | ## Hashing 199 | [Hashing](doc/api/hashing.md) 200 | 201 | ## Message Authentication Code 202 | [Message Authentication Code](doc/api/message_authentication_code.md) 203 | 204 | ## Digital Signatures 205 | [Digital Signatures](doc/api/digital_signature.md) 206 | 207 | ## Password Storage 208 | [Password Storage](doc/api/password_storage.md) 209 | 210 | ## Key Management 211 | [Key Management](doc/api/key_management.md) 212 | 213 | # LICENSE 214 | 215 | JavaCrypto is released under MIT License 216 | 217 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 218 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 219 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 220 | 221 | # DISCLAIMER: 222 | 223 | JavaCrypto came into existance and matured over time more as a complimenting code reference for Java Crypto blog series and numberous conference talks on this topic. Not accepting any PR/bug reports at the moment. All work done as part of this is a personal project, so direct all complaints to me. 224 | -------------------------------------------------------------------------------- /SecureCryptoMicroservice/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | springBootVersion = '2.5.5' 4 | mainClassName = 'com.secure.crypto.microservice.securecryptomicroservice.SecureCryptoMicroServiceApplication' 5 | } 6 | repositories { 7 | mavenLocal() 8 | mavenCentral() 9 | } 10 | dependencies { 11 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 12 | } 13 | } 14 | 15 | apply plugin: 'java' 16 | apply plugin: 'eclipse' 17 | apply plugin: 'org.springframework.boot' 18 | apply plugin: 'io.spring.dependency-management' 19 | 20 | 21 | group = 'com.secure.crypto.microservice' 22 | version = '0.0.2-SNAPSHOT' 23 | 24 | sourceCompatibility = JavaVersion.VERSION_18 25 | targetCompatibility = JavaVersion.VERSION_18 26 | 27 | 28 | repositories { 29 | mavenCentral() 30 | } 31 | 32 | 33 | dependencies { 34 | implementation fileTree(dir : '../JavaCryptoModule/SecureJavaCrypto/build/libs' , includes: ['*.jar']) 35 | implementation('org.springframework.boot:spring-boot-starter-web') 36 | implementation group: 'org.bouncycastle', name: 'bcprov-jdk18on', version: '1.71' 37 | } 38 | -------------------------------------------------------------------------------- /SecureCryptoMicroservice/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1MansiS/JavaCrypto/7a70c0241501c4ac7fcd25fcf033325f8bf33f8c/SecureCryptoMicroservice/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /SecureCryptoMicroservice/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /SecureCryptoMicroservice/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'SecureCryptoMicroservice' 2 | -------------------------------------------------------------------------------- /SecureCryptoMicroservice/src/main/java/com/secure/crypto/microservice/securecryptomicroservice/SecureCryptoMicroServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.secure.crypto.microservice.securecryptomicroservice; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class SecureCryptoMicroServiceApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(SecureCryptoMicroServiceApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /SecureCryptoMicroservice/src/main/java/com/secure/crypto/microservice/securecryptomicroservice/cipher/symmetric/controller/SymmetricEncryptionController.java: -------------------------------------------------------------------------------- 1 | package com.secure.crypto.microservice.securecryptomicroservice.cipher.symmetric.controller; 2 | 3 | import com.secure.crypto.cipher.symmetric.CipherAPI; 4 | import com.secure.crypto.key_generation.SymmetricKeyGeneration; 5 | import com.secure.crypto.microservice.securecryptomicroservice.cipher.symmetric.entity.SymmetricEncryption; 6 | import com.secure.crypto.secure_random.SecureRandomAPI; 7 | import org.springframework.http.MediaType; 8 | import org.springframework.web.bind.annotation.*; 9 | 10 | import java.security.SecureRandom; 11 | import java.util.Base64; 12 | 13 | 14 | @RestController 15 | public class SymmetricEncryptionController { 16 | 17 | SymmetricKeyGeneration symmetricKeyGeneration = new SymmetricKeyGeneration(); 18 | SecureRandomAPI secureRandomAPI = new SecureRandomAPI(); 19 | CipherAPI cipherAPI = new CipherAPI(); 20 | 21 | /** 22 | * This endpoint generates all the required encryption parameter depending on AES or ChaCha20 algorithm. If no algorithm is provided it defaults to AES. 23 | * Sample request: curl 'http://localhost:8080/generate-encryption-parameters/{enc_algo}' -s | json_pp 24 | * @param enc_algo: Optional encryption Algorithm to be used. Defaults to AES 25 | * @return: JSON string with symmetric key and initialization vector as required by the algorithm 26 | * { 27 | * "base64_iv" : "fpP9LW9idu4EDfWK/KbI+A==", 28 | * "base64_symmetric_key" : "N+LweaNH3UXFq4UFyBjlH7w8R4R5/1vk+JTDhMHOvxU=" 29 | * } 30 | */ 31 | @RequestMapping(value={"/generate-encryption-parameters","/generate-encryption-parameters/{enc_algo}"}) 32 | public SymmetricEncryption generateSymmetricEncryptionParameters(@PathVariable(required = false) String enc_algo) { 33 | SymmetricEncryption symmetricEncryption = new SymmetricEncryption(); 34 | 35 | int keySize = 256; // Since Key size is same for AES or ChaCha algorithms 36 | 37 | symmetricEncryption.setBase64EncodedKey( 38 | symmetricKeyGeneration.generateSymmetricKey( 39 | symmetricEncryption.getEncAlgo(), 40 | keySize, 41 | secureRandomAPI.drbgSecureRandom() 42 | )); 43 | 44 | int ivSize = 16; // Defaults to AES, which has key size = 16. 45 | 46 | if(enc_algo != null && enc_algo.toLowerCase().startsWith("chacha")){ivSize = 12;} // ChaCha20 needs IV == 12 47 | else if(enc_algo != null && enc_algo.toLowerCase().startsWith("AES")) {ivSize = 16; } 48 | else if(enc_algo == null) {ivSize = 16; } 49 | 50 | byte[] iv = new byte[ivSize]; 51 | SecureRandom secureRandom = secureRandomAPI.drbgSecureRandom(); 52 | secureRandom.nextBytes(iv); 53 | symmetricEncryption.setBase64EncodeIV(Base64.getEncoder().encodeToString(iv)); 54 | 55 | // We can figure out the Enc Algo from the length of IV, so no need to setEncAlgo for later use 56 | return symmetricEncryption; 57 | } 58 | 59 | 60 | /*** 61 | * /encrypt endpoint is called to do the actual encryption, taking in the key and iv generated thru above endpoints. It gives out the cipher text. 62 | * Sample request: curl 'http://localhost:8080/encrypt' -X POST -H "Content-Type: application/json" -d '{"symmetric_key":"...","IV":"...","plain_text":"Hello Crypto World!","aad":"localhost"}' 63 | * @param symmetricEncryption : Should pass symmetric_key, IV, plain_text, enc_algo and aad (only for AES) properties in json string 64 | * @return : Return cipher text (base 64 encoded): 65 | * { 66 | * "plain_text" : "Hello Crypto World!", 67 | * "base64_cipher_text" : "OvnpZsO0gzfZ+yRCugFWLSgl5MZmj4VZNX8tf00jCViWk4o=", 68 | * "symmetric_key" : "0pbH8pcnl51eAlUTLgcGCbR1FKFkBsLIFJ1kgAmne6Y=", 69 | * "aad" : "localhost", 70 | * "IV" : "qVsGLYhOnzBbDUIyTk595w==", 71 | * "enc_algo" : "AES" 72 | * } 73 | */ 74 | @PostMapping(value="/encrypt", 75 | consumes = MediaType.APPLICATION_JSON_VALUE, 76 | produces = MediaType.APPLICATION_JSON_VALUE) 77 | public SymmetricEncryption encrypt(@RequestBody SymmetricEncryption symmetricEncryption) { 78 | 79 | symmetricEncryption.setBase64EncodedEncryptedCipherText( 80 | cipherAPI.encrypt( 81 | symmetricEncryption.getBase64EncodedKey(), 82 | symmetricEncryption.getBase64EncodeIV(), 83 | symmetricEncryption.getAad(), 84 | symmetricEncryption.getPlainText() 85 | ) 86 | ); 87 | 88 | return symmetricEncryption; 89 | 90 | } 91 | 92 | /*** 93 | * This endpoint is called to decrypt cipher text to retrieve corresponding plain text. It expects keying material used for encryption and cipher text. 94 | * Sample request: curl 'http://localhost:8080/decrypt' -X POST -H "Content-Type: application/json" -d '{"symmetric_key":"...","IV":"...","base64_cipher_text":"OvnpZsO0gzfZ+yRCugFWLSgl5MZmj4VZNX8tf00jCViWk4o=","aad":"localhost"}' 95 | * @param symmetricEncryption : Pass in symmetric_key, IV, base64_cipher_text, enc_algo and aad (only for AES encryption) 96 | * @return : Corresponding plain text: 97 | * { 98 | * "plain_text" : "Hello Crypto World!", 99 | * "enc_algo" : "AES", 100 | * "IV" : "qVsGLYhOnzBbDUIyTk595w==", 101 | * "base64_cipher_text" : "OvnpZsO0gzfZ+yRCugFWLSgl5MZmj4VZNX8tf00jCViWk4o=", 102 | * "aad" : "localhost", 103 | * "symmetric_key" : "0pbH8pcnl51eAlUTLgcGCbR1FKFkBsLIFJ1kgAmne6Y=" 104 | * } 105 | */ 106 | @PostMapping(value="/decrypt", 107 | consumes = MediaType.APPLICATION_JSON_VALUE, 108 | produces = MediaType.APPLICATION_JSON_VALUE 109 | ) 110 | public SymmetricEncryption decrypt(@RequestBody SymmetricEncryption symmetricEncryption) { 111 | 112 | symmetricEncryption.setPlainText( 113 | cipherAPI.decrypt(symmetricEncryption.getBase64EncodedKey(), 114 | symmetricEncryption.getBase64EncodeIV(), 115 | symmetricEncryption.getAad(), 116 | symmetricEncryption.getBase64EncodedEncryptedCipherText() 117 | ) 118 | ); 119 | 120 | return symmetricEncryption; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /SecureCryptoMicroservice/src/main/java/com/secure/crypto/microservice/securecryptomicroservice/cipher/symmetric/entity/SymmetricEncryption.java: -------------------------------------------------------------------------------- 1 | package com.secure.crypto.microservice.securecryptomicroservice.cipher.symmetric.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | 6 | public class SymmetricEncryption { 7 | 8 | @JsonInclude(JsonInclude.Include.NON_NULL) 9 | @JsonProperty(value="enc_algo") 10 | private String encAlgo; 11 | 12 | @JsonInclude(JsonInclude.Include.NON_NULL) 13 | @JsonProperty(value="base64_symmetric_key") 14 | private String base64EncodedKey; 15 | 16 | @JsonInclude(JsonInclude.Include.NON_NULL) 17 | @JsonProperty(value="base64_iv") 18 | private String base64EncodeIV; 19 | 20 | @JsonInclude(JsonInclude.Include.NON_NULL) 21 | @JsonProperty(value = "plain_text") 22 | private String plainText; 23 | 24 | @JsonProperty(value="base64_cipher_text") 25 | @JsonInclude(JsonInclude.Include.NON_NULL) 26 | private String base64EncodedEncryptedCipherText; 27 | 28 | @JsonInclude(JsonInclude.Include.NON_NULL) 29 | @JsonProperty(value="aad") 30 | private String aad; 31 | 32 | public String getBase64EncodedEncryptedCipherText() { 33 | return base64EncodedEncryptedCipherText; 34 | } 35 | 36 | public void setBase64EncodedEncryptedCipherText(String base64EncodedEncryptedCipherText) { 37 | this.base64EncodedEncryptedCipherText = base64EncodedEncryptedCipherText; 38 | } 39 | 40 | public String getBase64EncodeIV() { 41 | return base64EncodeIV; 42 | } 43 | 44 | public void setBase64EncodeIV(String base64EncodeIV) { 45 | this.base64EncodeIV = base64EncodeIV; 46 | } 47 | 48 | public String getBase64EncodedKey() { 49 | return base64EncodedKey; 50 | } 51 | 52 | 53 | public String getPlainText() { 54 | return plainText; 55 | } 56 | 57 | public void setPlainText(String plainText) { 58 | this.plainText = plainText; 59 | } 60 | 61 | public void setBase64EncodedKey(String base64EncodedKey) { 62 | this.base64EncodedKey = base64EncodedKey; 63 | } 64 | 65 | public String getAad() { 66 | return aad; 67 | } 68 | 69 | public void setAad(String aad) { 70 | this.aad = aad; 71 | } 72 | 73 | public String getEncAlgo() { 74 | return encAlgo; 75 | } 76 | 77 | @JsonProperty 78 | public void setEncAlgo(String encAlgo) { 79 | if(!(encAlgo.toLowerCase().equals("aes") || encAlgo.toLowerCase().equals("chacha20"))) { 80 | throw new RuntimeException("Value " + encAlgo + " is invalid. Only valid values are AES or ChaCha20"); 81 | } 82 | this.encAlgo = encAlgo.toLowerCase(); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /SecureCryptoMicroservice/src/main/java/com/secure/crypto/microservice/securecryptomicroservice/digital_signature/controller/DigitalSignatureController.java: -------------------------------------------------------------------------------- 1 | package com.secure.crypto.microservice.securecryptomicroservice.digital_signature.controller; 2 | 3 | import com.secure.crypto.digital_signature.ECDigitalSignatureAPI; 4 | import com.secure.crypto.digital_signature.EdDigitalSignatureAPI; 5 | import com.secure.crypto.key_generation.AsymmetricKeyGeneration; 6 | import com.secure.crypto.microservice.securecryptomicroservice.digital_signature.entity.DigitalSignature; 7 | import org.springframework.http.MediaType; 8 | import org.springframework.web.bind.annotation.*; 9 | 10 | import java.security.KeyPair; 11 | import java.util.Base64; 12 | 13 | @RestController 14 | public class DigitalSignatureController { 15 | 16 | AsymmetricKeyGeneration asymmetricKeyGeneration = new AsymmetricKeyGeneration(); 17 | EdDigitalSignatureAPI edDigitalSignatureAPI = new EdDigitalSignatureAPI(); 18 | ECDigitalSignatureAPI ecDigitalSignatureAPI = new ECDigitalSignatureAPI(); 19 | 20 | /*** 21 | * Generated Asymmetric Keys. Specify the digital signature algorithm to be used. Only accepted values are ed-curve (edward curves) or eddsa(NIST curves) 22 | * Sample Request: curl -X POST 'http://localhost:8080/generate-digital-signature-parameters/{digital_signature_algo}' | json_pp 23 | * @param digital_signature_algo : Expects asymm_algo with only expects values of ed-curve or ecdsa 24 | * @return : base64 encoded public and private keys 25 | * { 26 | * "digital_signature_algo" : "ed-curve", 27 | * "base64_private_key" : "MC4CAQAwBQYDK2VwBCIEIOcF/tgt18Cv1F3i3Jw7SJL3RgbjeO9NxrfSOxVBIJ1B", 28 | * "base64_public_key" : "MCowBQYDK2VwAyEADzMUhYWEdBCl6XUlc5/PT7BuvFjFayaaCp2ktatJRxc=" 29 | * } 30 | */ 31 | @RequestMapping(value={"/generate-digital-signature-parameters","/generate-digital-signature-parameters/{digital_signature_algo}"}) 32 | public DigitalSignature generateDigitalSignatureParameters(@PathVariable(required = false)String digital_signature_algo) { 33 | DigitalSignature digitalSignature = new DigitalSignature(); 34 | 35 | KeyPair keyPair = null; 36 | 37 | if (digital_signature_algo != null && digital_signature_algo.toLowerCase().contains("ed")) {keyPair = asymmetricKeyGeneration.generateEdAsymmetricKey();} // Edward Curves 38 | else if(digital_signature_algo != null && digital_signature_algo.toLowerCase().startsWith("ecdsa")){keyPair = asymmetricKeyGeneration.generateECAsymmetricKey();} // EDDSA NIST curves 39 | else if(digital_signature_algo == null) {keyPair = asymmetricKeyGeneration.generateEdAsymmetricKey(); } // Defaults to Ed Curve 40 | 41 | digitalSignature.setBase64EncodedPublicKey(Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded())); 42 | digitalSignature.setBase64EncodedPrivateKey(Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded())); 43 | 44 | return digitalSignature; 45 | } 46 | 47 | /*** 48 | * This endpoint, generated the digital signature for the message passed 49 | * Sample Request: curl -X POST 'http://localhost:8080/sign' -H "Content-Type: application/json" \ 50 | * -d '{"digital_signature_algo":"ed-curve","base64_private_key":"MC4CAQAwBQYDK2VwBCIEIEkeQ5bKh7NQt5TxRhIEaSkpB7XY4KFZ8M9zsG0heVPS","plaintext_message":"Hello World!"}' | json_pp 51 | * @param digitalSignature: Pass the asymm_algo, base64_private_key and plaintext_message 52 | * @return : Base 64 signature value: 53 | *{ 54 | * "base64_private_key" : "MC4CAQAwBQYDK2VwBCIEIAWrd/47VIbIFtbOE34Kwsj8Is1FsLBSXDpUMNpAZ/H1", 55 | * "base64_sign" : "9dIBdU4Gjjb0BDtfmWIF1jl3ODbrAdaCjUlTfO3/JGxQu4VUW6LBiZrTTaeLMZhRdnQ+uw07uogIZey1iGlaAw==", 56 | * "digital_signature_algo" : "ed-curve", 57 | * "plaintext_message" : "Hello World!" 58 | * } 59 | */ 60 | @PostMapping(value="/sign", 61 | produces = MediaType.APPLICATION_JSON_VALUE, 62 | consumes = MediaType.APPLICATION_JSON_VALUE 63 | ) 64 | public DigitalSignature sign(@RequestBody DigitalSignature digitalSignature) { 65 | 66 | if(digitalSignature.getAsymm_algo() != null && digitalSignature.getAsymm_algo().toLowerCase().contains("ed")) { // Use Edward Curves 67 | digitalSignature.setBase64Signature( 68 | edDigitalSignatureAPI.sign( 69 | digitalSignature.getPlaintext_message(), 70 | digitalSignature.getBase64EncodedPrivateKey()) 71 | ); 72 | } else if(digitalSignature.getAsymm_algo() != null && digitalSignature.getAsymm_algo().toLowerCase().startsWith("ecdsa")){ 73 | digitalSignature.setBase64Signature( 74 | ecDigitalSignatureAPI.sign( 75 | digitalSignature.getPlaintext_message(), 76 | digitalSignature.getBase64EncodedPrivateKey() 77 | ) 78 | ); 79 | } else if(digitalSignature.getAsymm_algo() == null) { // Defaults to Ed Curves 80 | digitalSignature.setAsymm_algo("ed-curve"); 81 | digitalSignature.setBase64Signature( 82 | edDigitalSignatureAPI.sign( 83 | digitalSignature.getPlaintext_message(), 84 | digitalSignature.getBase64EncodedPrivateKey()) 85 | ); 86 | } 87 | 88 | return digitalSignature; 89 | } 90 | 91 | /*** 92 | * This endpoint, verifies the digital signature passed 93 | * Sample Request: curl -X POST 'http://localhost:8080/verify' -H "Content-Type: application/json" \ 94 | * -d '{"plaintext_message":"Hello World!","base64_public_key":"MCowBQYDK2VwAyEAJF7iwf5nmWq+5znvKj1+F4ILsKRK6QUYmEIocUNFLFc=","base64_sign":"9dIBdU4Gjjb0BDtfmWIF1jl3ODbrAdaCjUlTfO3/JGxQu4VUW6LBiZrTTaeLMZhRdnQ+uw07uogIZey1iGlaAw=="}' | json_pp 95 | * @param digitalSignature: Expects: asymm_algo, base64_public_key, plaintext_message and base64_sign 96 | * @return: If the signature is verified. Look for the value of verified key in response json string. 97 | * { 98 | * "base64_public_key" : "MCowBQYDK2VwAyEAq6ATMBErxIChQkN65+kWXr5kTXltNSkU2K7kkK/OEdU=", 99 | * "base64_sign" : "N6JMKDPJZTfmlwVga2/vJrLrnIWHmcAmIS7hUUPo8qeST3R0b5LUosYBzknbRcdj3km0zC0P195VHkd0dSJQAA==", 100 | * "digital_signature_algo" : "ed-curve", 101 | * "plaintext_message" : "Hello World!", 102 | * "verified" : true 103 | * } 104 | */ 105 | @PostMapping(value="/verify", 106 | produces = MediaType.APPLICATION_JSON_VALUE, 107 | consumes = MediaType.APPLICATION_JSON_VALUE 108 | ) 109 | public DigitalSignature verify(@RequestBody DigitalSignature digitalSignature) { 110 | 111 | if(digitalSignature.getAsymm_algo() != null && digitalSignature.getAsymm_algo().toLowerCase().contains("ed")){ // Use Edward Curves 112 | digitalSignature.setVerified( 113 | edDigitalSignatureAPI.verify( 114 | digitalSignature.getPlaintext_message(), 115 | digitalSignature.getBase64EncodedPublicKey(), 116 | digitalSignature.getBase64Signature() 117 | ) 118 | ); 119 | } else if(digitalSignature.getAsymm_algo() != null && digitalSignature.getAsymm_algo().toLowerCase().startsWith("ecdsa")){ 120 | digitalSignature.setVerified( 121 | ecDigitalSignatureAPI.verify(digitalSignature.getPlaintext_message(), 122 | digitalSignature.getBase64EncodedPublicKey(), 123 | digitalSignature.getBase64Signature() 124 | ) 125 | ); 126 | } else if(digitalSignature.getAsymm_algo() == null) { // Defaults to Ed Curves 127 | digitalSignature.setAsymm_algo("ed-curve"); 128 | digitalSignature.setVerified( 129 | edDigitalSignatureAPI.verify( 130 | digitalSignature.getPlaintext_message(), 131 | digitalSignature.getBase64EncodedPublicKey(), 132 | digitalSignature.getBase64Signature() 133 | ) 134 | ); 135 | } 136 | 137 | return digitalSignature; 138 | } 139 | } -------------------------------------------------------------------------------- /SecureCryptoMicroservice/src/main/java/com/secure/crypto/microservice/securecryptomicroservice/digital_signature/entity/DigitalSignature.java: -------------------------------------------------------------------------------- 1 | package com.secure.crypto.microservice.securecryptomicroservice.digital_signature.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | 6 | public class DigitalSignature { 7 | 8 | // Acceptable values ecdsa, eddsa 9 | @JsonProperty("digital_signature_algo") 10 | @JsonInclude(JsonInclude.Include.NON_NULL) 11 | private String asymm_algo; 12 | 13 | @JsonInclude(JsonInclude.Include.NON_NULL) 14 | @JsonProperty("base64_public_key") 15 | private String base64EncodedPublicKey; 16 | 17 | @JsonInclude(JsonInclude.Include.NON_NULL) 18 | @JsonProperty("base64_private_key") 19 | private String base64EncodedPrivateKey; 20 | 21 | 22 | @JsonInclude(JsonInclude.Include.NON_NULL) 23 | @JsonProperty("plaintext_message") 24 | private String plaintext_message; 25 | 26 | 27 | @JsonInclude(JsonInclude.Include.NON_NULL) 28 | @JsonProperty("base64_sign") 29 | private String base64Signature; 30 | 31 | 32 | @JsonInclude(JsonInclude.Include.NON_DEFAULT) 33 | @JsonProperty("verified") 34 | private boolean verified = false; 35 | 36 | public String getAsymm_algo() { 37 | return asymm_algo; 38 | } 39 | 40 | @JsonProperty 41 | public void setAsymm_algo(String asymm_algo) { 42 | 43 | if( 44 | !((asymm_algo.toLowerCase().equals("ed-curve")) || 45 | (asymm_algo.toLowerCase().equals("ecdsa"))) 46 | 47 | ) { 48 | throw new RuntimeException(asymm_algo + " should be either ed-curve or ecdsa"); 49 | } 50 | this.asymm_algo = asymm_algo; 51 | } 52 | 53 | public boolean isVerified() { 54 | return verified; 55 | } 56 | 57 | public void setVerified(boolean verified) { 58 | this.verified = verified; 59 | } 60 | 61 | public String getBase64Signature() { 62 | return base64Signature; 63 | } 64 | 65 | public void setBase64Signature(String base64Signature) { 66 | this.base64Signature = base64Signature; 67 | } 68 | 69 | public String getBase64EncodedPublicKey() { 70 | return base64EncodedPublicKey; 71 | } 72 | 73 | public void setBase64EncodedPublicKey(String base64EncodedPublicKey) { 74 | this.base64EncodedPublicKey = base64EncodedPublicKey; 75 | } 76 | 77 | public String getBase64EncodedPrivateKey() { 78 | return base64EncodedPrivateKey; 79 | } 80 | 81 | public void setBase64EncodedPrivateKey(String base64EncodedPrivateKey) { 82 | this.base64EncodedPrivateKey = base64EncodedPrivateKey; 83 | } 84 | 85 | public String getPlaintext_message() { 86 | return plaintext_message; 87 | } 88 | 89 | public void setPlaintext_message(String plaintext_message) { 90 | this.plaintext_message = plaintext_message; 91 | } 92 | 93 | 94 | } 95 | -------------------------------------------------------------------------------- /SecureCryptoMicroservice/src/main/java/com/secure/crypto/microservice/securecryptomicroservice/key_management/controller/KeyManagementController.java: -------------------------------------------------------------------------------- 1 | package com.secure.crypto.microservice.securecryptomicroservice.key_management.controller; 2 | 3 | import com.secure.crypto.key_generation.SymmetricKeyGeneration; 4 | import com.secure.crypto.key_management.KeyManagementAPI; 5 | import com.secure.crypto.microservice.securecryptomicroservice.key_management.entity.KeyStoreEntity; 6 | import com.secure.crypto.secure_random.SecureRandomAPI; 7 | import org.springframework.http.MediaType; 8 | import org.springframework.web.bind.annotation.PostMapping; 9 | import org.springframework.web.bind.annotation.RequestBody; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | import javax.crypto.SecretKey; 13 | 14 | @RestController 15 | public class KeyManagementController { 16 | private KeyManagementAPI keyManagementAPI = new KeyManagementAPI(); 17 | private SymmetricKeyGeneration symmetricKeyGeneration = new SymmetricKeyGeneration(); 18 | private SecureRandomAPI secureRandomAPI = new SecureRandomAPI(); 19 | 20 | /*** 21 | * This endpoint stores an encryption password into keystore file. 22 | * 23 | * Sample Request: curl -X POST 'http://localhost:8080/store-secret-key' -H 'Content-Type: application/json' -d '{"key-store-password":"my-keystorepassword","entry-password":"my-entrypassword","alias":"encryption-key"}' | json_pp 24 | * 25 | * @param key-store-password : Password used to encrypt the entire keystore 26 | * @param entry-password : Password to store this specific encryption key 27 | * @param alias: alias to represent this entry 28 | * @return : Returns a success or failure message 29 | * Sample Response: 30 | * { 31 | * "key-store-password" : "my-keystorepassword", 32 | * "entry-password" : "my-entrypassword", 33 | * "Response" : "Successfully saved Secret Key with alias encryption-key", 34 | * "alias" : "encryption-key" 35 | * } 36 | */ 37 | @PostMapping(value = "store-secret-key", 38 | produces = MediaType.APPLICATION_JSON_VALUE, 39 | consumes = MediaType.APPLICATION_JSON_VALUE 40 | ) 41 | public KeyStoreEntity addSecretKey(@RequestBody KeyStoreEntity keyStoreEntity) { 42 | byte[] secretKey = 43 | symmetricKeyGeneration.generateSymmetricKey( 44 | "AES", 45 | 256, 46 | secureRandomAPI.drbgSecureRandom() 47 | ).getBytes(); 48 | 49 | boolean successFullySaved = keyManagementAPI.addSecretKey(keyStoreEntity.getKeyStorePassword(), 50 | keyStoreEntity.getKeyStorePassword(), 51 | keyStoreEntity.getAlias(), 52 | secretKey 53 | ); 54 | 55 | 56 | if (successFullySaved) { 57 | keyStoreEntity.setResponse_message("Successfully saved Secret Key with alias " + keyStoreEntity.getAlias()) ; 58 | } else { 59 | keyStoreEntity.setResponse_message("Exception saving Secret Key with alias " + keyStoreEntity.getAlias()) ; 60 | } 61 | 62 | return keyStoreEntity; 63 | } 64 | } -------------------------------------------------------------------------------- /SecureCryptoMicroservice/src/main/java/com/secure/crypto/microservice/securecryptomicroservice/key_management/entity/KeyStoreEntity.java: -------------------------------------------------------------------------------- 1 | package com.secure.crypto.microservice.securecryptomicroservice.key_management.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | 6 | public class KeyStoreEntity { 7 | 8 | @JsonInclude(JsonInclude.Include.NON_NULL) 9 | @JsonProperty("key-store-password") 10 | private String keyStorePassword = null; 11 | 12 | @JsonInclude(JsonInclude.Include.NON_NULL) 13 | @JsonProperty("entry-password") 14 | private String entryPassword = null; 15 | 16 | @JsonInclude(JsonInclude.Include.NON_NULL) 17 | @JsonProperty("alias") 18 | private String alias = null; 19 | 20 | 21 | @JsonProperty("Response") 22 | private String response_message = null; 23 | 24 | public String getKeyStorePassword() { 25 | return keyStorePassword; 26 | } 27 | 28 | public void setKeyStorePassword(String keyStorePassword) { 29 | this.keyStorePassword = keyStorePassword; 30 | } 31 | 32 | public String getEntryPassword() { 33 | return entryPassword; 34 | } 35 | 36 | public void setEntryPassword(String entryPassword) { 37 | this.entryPassword = entryPassword; 38 | } 39 | 40 | public String getAlias() { 41 | return alias; 42 | } 43 | 44 | public void setAlias(String alias) { 45 | this.alias = alias; 46 | } 47 | 48 | public String getResponse_message() { 49 | return response_message; 50 | } 51 | 52 | public void setResponse_message(String response_message) { 53 | this.response_message = response_message; 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /SecureCryptoMicroservice/src/main/java/com/secure/crypto/microservice/securecryptomicroservice/mac/controller/HmacController.java: -------------------------------------------------------------------------------- 1 | package com.secure.crypto.microservice.securecryptomicroservice.mac.controller; 2 | 3 | import com.secure.crypto.mac.MACComputationAPI; 4 | import com.secure.crypto.microservice.securecryptomicroservice.mac.entity.Hmac; 5 | import org.springframework.http.MediaType; 6 | import org.springframework.web.bind.annotation.*; 7 | 8 | @RestController 9 | public class HmacController { 10 | 11 | private MACComputationAPI macComputationAPI = new MACComputationAPI(); 12 | 13 | /*** 14 | * Generate symmetric key, for configured HMAC algorithm and key size. 15 | * Choosing key size is not give to user, since key size should always be less than block size of underlying hashing algorithm. 16 | * This same key should be used on sender and receiver size, and safeguarded. 17 | * Sample Request: curl 'http://localhost:8080/compute-hmac-key/{hmac_enc_algo}' -X POST -H "Content-type: application/json" | json_pp 18 | * @param hmac_enc_algo : Optional Hmac algorithm to be used. Defaults to HmacSHA512, configured in JavaCrypto Module's DEFAULT_HMAC_ALGO property. 19 | * @return : 20 | * { 21 | * "base64-symmetric-key" : "S20l/hZnaqoAvGx9CwdmJgeWOW7bsYJYPqebcECgMQs=" 22 | * } 23 | * 24 | */ 25 | @RequestMapping(value={"/compute-hmac-key","/compute-hmac-key/{hmac_enc_algo}"}) 26 | public Hmac computeMacKey(@PathVariable(required = false)String hmac_enc_algo) { 27 | Hmac hmac = new Hmac(); 28 | 29 | hmac.setBase64SymmetricKey( 30 | macComputationAPI.computeMacKey(hmac_enc_algo) 31 | ); 32 | 33 | return hmac; 34 | } 35 | 36 | /*** 37 | * Computes MAC for passed plain text message, using computed symmetric key. 38 | * Sample Request: curl 'http://localhost:8080/compute-hmac' -X POST -H "Content-type: application/json" -d '{"message":"Hello MAC!!!","base64-symmetric-key":"S20l/hZnaqoAvGx9CwdmJgeWOW7bsYJYPqebcECgMQs="}' | json_pp 39 | * @param hmac : Pass message and base64-symmetric-key parameters 40 | * @return: 41 | * 42 | * { 43 | * "mac" : "aDJbcZOCylQzqqT+yNHDyMoghfDOGBlKl4px3DjXVew=", 44 | * "base64-symmetric-key" : "S20l/hZnaqoAvGx9CwdmJgeWOW7bsYJYPqebcECgMQs=", 45 | * "message" : "Hello MAC!!!" 46 | * } 47 | */ 48 | @PostMapping(value="compute-hmac", 49 | produces = MediaType.APPLICATION_JSON_VALUE, 50 | consumes = MediaType.APPLICATION_JSON_VALUE 51 | ) 52 | public Hmac computeMAC(@RequestBody Hmac hmac) { 53 | 54 | hmac.setMac( 55 | macComputationAPI.computeMac( 56 | hmac.getBase64SymmetricKey(), 57 | hmac.getMessage(), 58 | hmac.getMac() 59 | ) 60 | ); 61 | 62 | return hmac; 63 | } 64 | } -------------------------------------------------------------------------------- /SecureCryptoMicroservice/src/main/java/com/secure/crypto/microservice/securecryptomicroservice/mac/entity/Hmac.java: -------------------------------------------------------------------------------- 1 | package com.secure.crypto.microservice.securecryptomicroservice.mac.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | 6 | public class Hmac { 7 | 8 | @JsonInclude(JsonInclude.Include.NON_NULL) 9 | @JsonProperty("message") 10 | private String message; 11 | 12 | @JsonInclude(JsonInclude.Include.NON_NULL) 13 | @JsonProperty("base64-symmetric-key") 14 | private String base64SymmetricKey; 15 | 16 | @JsonInclude(JsonInclude.Include.NON_NULL) 17 | @JsonProperty(value="mac") 18 | private String mac; 19 | 20 | public String getMessage() { 21 | return message; 22 | } 23 | 24 | public void setMessage(String message) { 25 | this.message = message; 26 | } 27 | 28 | public String getBase64SymmetricKey() { 29 | return base64SymmetricKey; 30 | } 31 | 32 | public void setBase64SymmetricKey(String base64SymmetricKey) { 33 | this.base64SymmetricKey = base64SymmetricKey; 34 | } 35 | 36 | public String getMac() { 37 | return mac; 38 | } 39 | 40 | public void setMac(String mac) { 41 | this.mac = mac; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /SecureCryptoMicroservice/src/main/java/com/secure/crypto/microservice/securecryptomicroservice/message_digest/controller/MessageDigestController.java: -------------------------------------------------------------------------------- 1 | package com.secure.crypto.microservice.securecryptomicroservice.message_digest.controller; 2 | 3 | import com.secure.crypto.message_digest.MessageDigestAPI; 4 | import com.secure.crypto.microservice.securecryptomicroservice.message_digest.entity.Digest; 5 | 6 | import org.springframework.http.MediaType; 7 | import org.springframework.web.bind.annotation.*; 8 | 9 | @RestController 10 | public class MessageDigestController { 11 | 12 | private MessageDigestAPI messageDigestAPI = new MessageDigestAPI(); 13 | 14 | /*** 15 | * This endpoint computes SHA3-512 digest of input message. 16 | * Sample Request: curl 'http://localhost:8080/digest' -X POST -H "Content-type: application/json" -d '{"message":"Hello Hashing!!!"}' | json_pp 17 | * 18 | * @param message : Should pass "message" parameter 19 | * @param hashing-algo : Optional hashing algo 20 | * @return : Returns base64 encoded hash string 21 | * Sample Response: 22 | * { 23 | * "hash" : "Mb9x21/z6XCh3OiwzWSfkxnybuKPRe0FiSqxLDkNDGRPcRzcvEHUrSRF6iseByz/qVtgXc3qYe4U1gWZkM2B7A==", 24 | * "message" : "Hello Hashing!!!" 25 | * } 26 | */ 27 | @PostMapping(value = "digest", 28 | produces = MediaType.APPLICATION_JSON_VALUE, 29 | consumes = MediaType.APPLICATION_JSON_VALUE 30 | ) 31 | public Digest computeMessageDigest(@RequestBody Digest digest) { 32 | digest.setHash( 33 | messageDigestAPI.generateMessageDigest(digest.getMessage(), 34 | digest.getHashingAlgo()) 35 | ); 36 | 37 | return digest; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /SecureCryptoMicroservice/src/main/java/com/secure/crypto/microservice/securecryptomicroservice/message_digest/entity/Digest.java: -------------------------------------------------------------------------------- 1 | package com.secure.crypto.microservice.securecryptomicroservice.message_digest.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | 6 | public class Digest { 7 | 8 | 9 | @JsonInclude(JsonInclude.Include.NON_NULL) 10 | @JsonProperty("message") 11 | private String message; 12 | 13 | 14 | 15 | @JsonInclude(JsonInclude.Include.NON_NULL) 16 | @JsonProperty(value="hashing-algo") 17 | private String hashingAlgo; 18 | 19 | @JsonInclude(JsonInclude.Include.NON_NULL) 20 | @JsonProperty("hash") 21 | private String hash; 22 | 23 | public String getMessage() { 24 | return message; 25 | } 26 | 27 | public void setMessage(String message) { 28 | this.message = message; 29 | } 30 | 31 | public String getHash() { 32 | return hash; 33 | } 34 | 35 | public void setHash(String hash) { 36 | this.hash = hash; 37 | } 38 | 39 | public String getHashingAlgo() { 40 | return hashingAlgo; 41 | } 42 | 43 | public void setHashingAlgo(String hashingAlgo) { 44 | this.hashingAlgo = hashingAlgo; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /SecureCryptoMicroservice/src/main/java/com/secure/crypto/microservice/securecryptomicroservice/password_storage/controller/PasswordStorageController.java: -------------------------------------------------------------------------------- 1 | package com.secure.crypto.microservice.securecryptomicroservice.password_storage.controller; 2 | 3 | import com.secure.crypto.microservice.securecryptomicroservice.password_storage.entity.KDFPasswordStorageEntity; 4 | import com.secure.crypto.password_storage.PBKDF2PasswdStorage; 5 | import com.secure.crypto.password_storage.BCryptPasswdStorage; 6 | import com.secure.crypto.password_storage.ScryptPasswdStorage; 7 | import com.secure.crypto.password_storage.Argon2idPasswdStorage; 8 | 9 | import com.secure.crypto.secure_random.SecureRandomAPI; 10 | import org.springframework.http.MediaType; 11 | import org.springframework.web.bind.annotation.*; 12 | 13 | import java.security.SecureRandom; 14 | import java.util.Base64; 15 | 16 | @RestController 17 | public class PasswordStorageController { 18 | 19 | SecureRandomAPI secureRandomAPI = new SecureRandomAPI(); 20 | PBKDF2PasswdStorage pbkdf2PasswdStorage = new PBKDF2PasswdStorage(); 21 | BCryptPasswdStorage bcryptPasswdStorage = new BCryptPasswdStorage(); 22 | ScryptPasswdStorage scryptPasswdStorage = new ScryptPasswdStorage(); 23 | Argon2idPasswdStorage argon2idPasswdStorage = new Argon2idPasswdStorage() ; 24 | 25 | 26 | /*** 27 | * Compute salt to be used for compute password storage hash. 28 | * Sample Request: curl 'http://localhost:8080/compute-salt/{kdf_algo}' -s | json_pp 29 | * @param kdf_algo : "kdf_algo" to be used for computing password hash 30 | * @return: 31 | * { 32 | * "base64-salt" : "Ihg4MIicY8hrWhiBw7Ogf6FEUZ4=", 33 | * "salt-size" : "20" 34 | * } 35 | */ 36 | @RequestMapping(value={"/compute-salt", "/compute-salt/{kdf_algo}"}) 37 | public KDFPasswordStorageEntity computeSalt(@PathVariable(required = false)String kdf_algo) { 38 | 39 | KDFPasswordStorageEntity kdfPasswordStorageEntity = new KDFPasswordStorageEntity(); 40 | 41 | int saltSize = 32; 42 | 43 | if(kdf_algo != null && kdf_algo.toLowerCase().startsWith("bcrypt")) {saltSize = 16;} 44 | 45 | SecureRandom drbgSecureRandom = secureRandomAPI.drbgSecureRandom(); 46 | byte[] salt = new byte[saltSize]; 47 | drbgSecureRandom.nextBytes(salt); 48 | 49 | kdfPasswordStorageEntity.setBase64Salt(Base64.getEncoder().encodeToString(salt)); 50 | 51 | return kdfPasswordStorageEntity; 52 | } 53 | 54 | /*** 55 | * Compute hash of plain text password using a kdf function. Never store plain text password in clear, always store it by compute it using a strong kdf. 56 | * Sample Request: curl 'http://localhost:8080/compute-kdf-passwd' -X POST -H "Content-type: application/json" -d '{"base64-salt":"Ihg4MIicY8hrWhiBw7Ogf6FEUZ4=","passwd":"mysupersecretpasswordtobestored!!!","kdf-algo":"pbkdf2"}'| json_pp 57 | * @param kdfPasswordStorageEntity : "base64-salt", "kdf-algo" and "passwd" 58 | * @return : 59 | * { 60 | * "base64-kdf-passwd-hash" : "FdpfiqCAEhSZiX5u27WUV7Y0iI9Qw2huCBSNDRAGEFaZ84FmFSiU2Ws4wG9O5fBOy5bsdL7XXNhHCZvWcdXgsNjvwoKFc2muh2r0SFpm3/MbnZUrI63gsKXlcrbvpzdvArZ9DzRUz31TjyK0fKs2HcVjQ3BA4lD+4iY9HJZYDMfu/D1YMpe7MEpYhCnTfOb8FVfUsOyje0N4+zGm547XfHXIzt/JrCYgbqn5Imw7JaVmS9i9jUflgxBsc+lv2wZmbxQoJ9md/dvk4xD0P6hpT0vSKpK9uj6ZJ5sxPpOkZvpKmskSnpNamcWjw2IrbTAGi3buoDBqbPeyPuN3Spkrcw==", 61 | * "kdf-algo" : "pbkdf2", 62 | * "passwd" : "mysupersecretpasswordtobestored!!!", 63 | * "base64-salt" : "Ihg4MIicY8hrWhiBw7Ogf6FEUZ4=" 64 | * } 65 | */ 66 | @PostMapping(value="compute-kdf-passwd", 67 | produces = MediaType.APPLICATION_JSON_VALUE, 68 | consumes = MediaType.APPLICATION_JSON_VALUE 69 | 70 | ) 71 | public KDFPasswordStorageEntity computeKDFPassword(@RequestBody KDFPasswordStorageEntity kdfPasswordStorageEntity) { 72 | 73 | if(kdfPasswordStorageEntity.getPasswdHashingAlgo() == null) { // Default to Argon2 74 | kdfPasswordStorageEntity.setBase64KDFPasswd( 75 | argon2idPasswdStorage.generatePasswdForStorage( 76 | kdfPasswordStorageEntity.getPlainTextPassword(), 77 | kdfPasswordStorageEntity.getBase64Salt() 78 | ) 79 | ); 80 | } 81 | else if(kdfPasswordStorageEntity.getPasswdHashingAlgo().toLowerCase().startsWith("pbkdf")) { 82 | kdfPasswordStorageEntity.setBase64KDFPasswd( 83 | pbkdf2PasswdStorage.generatePasswdForStorage( 84 | kdfPasswordStorageEntity.getPlainTextPassword(), 85 | kdfPasswordStorageEntity.getBase64Salt() 86 | ) 87 | ); 88 | } else if(kdfPasswordStorageEntity.getPasswdHashingAlgo().toLowerCase().startsWith("bcrypt")) { 89 | kdfPasswordStorageEntity.setBase64KDFPasswd( 90 | bcryptPasswdStorage.generatePasswdForStorage( 91 | kdfPasswordStorageEntity.getPlainTextPassword(), 92 | kdfPasswordStorageEntity.getBase64Salt() 93 | ) 94 | ); 95 | } else if(kdfPasswordStorageEntity.getPasswdHashingAlgo().toLowerCase().startsWith("scrypt")) { 96 | kdfPasswordStorageEntity.setBase64KDFPasswd( 97 | scryptPasswdStorage.generatePasswdForStorage( 98 | kdfPasswordStorageEntity.getPlainTextPassword(), 99 | kdfPasswordStorageEntity.getBase64Salt() 100 | ) 101 | ); 102 | } 103 | 104 | return kdfPasswordStorageEntity; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /SecureCryptoMicroservice/src/main/java/com/secure/crypto/microservice/securecryptomicroservice/password_storage/entity/KDFPasswordStorageEntity.java: -------------------------------------------------------------------------------- 1 | package com.secure.crypto.microservice.securecryptomicroservice.password_storage.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | 6 | public class KDFPasswordStorageEntity { 7 | 8 | @JsonInclude(JsonInclude.Include.NON_NULL) 9 | @JsonProperty("base64-salt") 10 | private String base64Salt; 11 | 12 | @JsonInclude(JsonInclude.Include.NON_NULL) 13 | @JsonProperty("base64-kdf-passwd-hash") 14 | private String base64KDFPasswd; 15 | 16 | @JsonInclude(JsonInclude.Include.NON_NULL) 17 | @JsonProperty("passwd") 18 | private String plainTextPassword; 19 | 20 | @JsonInclude(JsonInclude.Include.NON_NULL) 21 | @JsonProperty(value="kdf-algo") 22 | private String passwdHashingAlgo; 23 | 24 | public String getBase64Salt() { 25 | return base64Salt; 26 | } 27 | 28 | public void setBase64Salt(String base64Salt) { 29 | this.base64Salt = base64Salt; 30 | } 31 | 32 | public String getBase64KDFPasswd() { 33 | return base64KDFPasswd; 34 | } 35 | 36 | public void setBase64KDFPasswd(String base64KDFPasswd) { 37 | this.base64KDFPasswd = base64KDFPasswd; 38 | } 39 | 40 | public String getPlainTextPassword() { 41 | return plainTextPassword; 42 | } 43 | 44 | public void setPlainTextPassword(String plainTextPassword) { 45 | this.plainTextPassword = plainTextPassword; 46 | } 47 | 48 | public String getPasswdHashingAlgo() { 49 | return passwdHashingAlgo; 50 | } 51 | 52 | @JsonProperty 53 | public void setPasswdHashingAlgo(String passwdHashingAlgo) { 54 | if(!(passwdHashingAlgo.toLowerCase().equals("argon2") || passwdHashingAlgo.toLowerCase().equals("pbkdf2") || passwdHashingAlgo.toLowerCase().equals("bcrypt") || passwdHashingAlgo.toLowerCase().equals("scrypt") )) { 55 | throw new RuntimeException(passwdHashingAlgo + " value is invalid. Only acceptable values are Argon2, bcrypt, scrypt or PBKDF2"); 56 | } 57 | this.passwdHashingAlgo = passwdHashingAlgo; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /SecureCryptoMicroservice/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1MansiS/JavaCrypto/7a70c0241501c4ac7fcd25fcf033325f8bf33f8c/SecureCryptoMicroservice/src/main/resources/application.properties -------------------------------------------------------------------------------- /doc/api/digital_signature.md: -------------------------------------------------------------------------------- 1 | # Generate Digital Signatures 2 | 3 | ## Generating Asymmetric Key 4 | 5 | Endpoint: 6 | 7 | ```plaintext 8 | GET /generate-digital-signature-parameters/{digital_signature_algo} 9 | ``` 10 | 11 | Sample Request: 12 | 13 | ```plaintext 14 | curl -X POST 'http://localhost:8080/generate-digital-signature-parameters' | json_pp 15 | ``` 16 | 17 | OR 18 | 19 | ``` 20 | curl -X POST 'http://localhost:8080/generate-digital-signature-parameters/eddsa' | json_pp 21 | ``` 22 | 23 | |Name|Type|Description| 24 | |---|---|---| 25 | |`digital_signature_algo`
(Optional)|String|Signature algorithm to use. Accepted values are `ecdsa` or `ec-curve`. Defaults to ed-curve| 26 | 27 | 28 | Response: 29 | 30 | ```plaintext 31 | { 32 | "digital_signature_algo" : "ed-curve", 33 | "base64_private_key" : "MC4CAQAwBQYDK2VwBCIEIOcF/tgt18Cv1F3i3Jw7SJL3RgbjeO9NxrfSOxVBIJ1B", 34 | "base64_public_key" : "MCowBQYDK2VwAyEADzMUhYWEdBCl6XUlc5/PT7BuvFjFayaaCp2ktatJRxc=" 35 | } 36 | ``` 37 | 38 | |Name|Type|Description| 39 | |---|---|---| 40 | |`digital_signature_algo`|String|Digital Signature Algorithm Used| 41 | |`base64_private_key`|String|Generated Private Key Base 64 encoded| 42 | |`base64_public_key`|String|Generated Public Key Base 64 encoded| 43 | 44 | ## Generating the Signature: 45 | 46 | Endpoint: 47 | 48 | ```plaintext 49 | POST /sign 50 | ``` 51 | 52 | Sample Request: 53 | 54 | ```plaintext 55 | curl -X POST 'http://localhost:8080/sign' -H "Content-Type: application/json" \ 56 | -d '{"digital_signature_algo":"ed-curve","base64_private_key":"MC4CAQAwBQYDK2VwBCIEIEkeQ5bKh7NQt5TxRhIEaSkpB7XY4KFZ8M9zsG0heVPS","plaintext_message":"Hello World!"}' | json_pp 57 | ``` 58 | 59 | 60 | |Name|Type|Description| 61 | |---|---|---| 62 | |`digital_signature_algo`
(Optional)|String|Signature Algorithm to be used. Accepted values `ecdsa` or `ed-curve`. Defaults to `ed-curve`| 63 | |`base64_private_key`
(Required)|String|Generated Private key from above step to be used to sign the message| 64 | |`plaintext_message`
(Required)|String|Message to be signed| 65 | 66 | 67 | Response: 68 | 69 | ```plaintext 70 | { 71 | "base64_private_key" : "MC4CAQAwBQYDK2VwBCIEIAWrd/47VIbIFtbOE34Kwsj8Is1FsLBSXDpUMNpAZ/H1", 72 | "base64_sign" : "9dIBdU4Gjjb0BDtfmWIF1jl3ODbrAdaCjUlTfO3/JGxQu4VUW6LBiZrTTaeLMZhRdnQ+uw07uogIZey1iGlaAw==", 73 | "digital_signature_algo" : "ed-curve", 74 | "plaintext_message" : "Hello World!" 75 | } 76 | ``` 77 | 78 | |Name|Type|Description| 79 | |---|---|---| 80 | |`digital_signature_algo`|String|Signature Algorithm to be used. Accepted values `ecdsa` or `ed-curve`. Defaults to `ed-curve`| 81 | |`base64_private_key`|String|Generated Private key from above step to be used to sign the message| 82 | |`plaintext_message`|String|Message to be signed| 83 | |`base64_sign`|String|Signature Generated| 84 | 85 | ## Verifying the Signature: 86 | 87 | ```plaintext 88 | POST /verify 89 | ``` 90 | 91 | Sample Request: 92 | 93 | ```plaintext 94 | curl -X POST 'http://localhost:8080/verify' -H "Content-Type: application/json" \ 95 | -d '{"plaintext_message":"Hello World!","base64_public_key":"MCowBQYDK2VwAyEAJF7iwf5nmWq+5znvKj1+F4ILsKRK6QUYmEIocUNFLFc=","base64_sign":"9dIBdU4Gjjb0BDtfmWIF1jl3ODbrAdaCjUlTfO3/JGxQu4VUW6LBiZrTTaeLMZhRdnQ+uw07uogIZey1iGlaAw=="}' | json_pp 96 | ``` 97 | 98 | 99 | |Name|Type|Description| 100 | |---|---|---| 101 | |`digital_signature_algo`
(Optional)|String|Signature Algorithm to be used. Accepted values `ecdsa` or `ed-curve`. Defaults to `ed-curve`| 102 | |`plaintext_message`
(Required)|String|Received message to be verified| 103 | |`base64_public_key`
(Required)|String|Corresponding Public Key to verify the message| 104 | |`base64_sign`
(Required)|String|Signature of signed message received.| 105 | 106 | Response: 107 | 108 | ```plaintext 109 | { 110 | "base64_public_key" : "MCowBQYDK2VwAyEAq6ATMBErxIChQkN65+kWXr5kTXltNSkU2K7kkK/OEdU=", 111 | "base64_sign" : "N6JMKDPJZTfmlwVga2/vJrLrnIWHmcAmIS7hUUPo8qeST3R0b5LUosYBzknbRcdj3km0zC0P195VHkd0dSJQAA==", 112 | "digital_signature_algo" : "ed-curve", 113 | "plaintext_message" : "Hello World!", 114 | "verified" : true 115 | } 116 | ``` 117 | 118 | |Name|Type|Description| 119 | |---|---|---| 120 | |`digital_signature_algo`|String|Signature Algorithm to be used. Accepted values `ecdsa` or `ed-curve`. Defaults to `ed-curve`| 121 | |`plaintext_message`|String|Received message to be verified| 122 | |`base64_public_key`|String|Corresponding Public Key to verify the message| 123 | |`base64_sign`|String|Signature of signed message received.| 124 | |`verified`|boolean|Is the signature valid, to esablish integrity, authenticity and non-repudiation| 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /doc/api/encryption_decryption.md: -------------------------------------------------------------------------------- 1 | # Encrypting/Decrypting Secret Data 2 | 3 | These APIs are used when any data needs to be encrypted or decrypted. 4 | 5 | 6 | ## Step 1: Generating Encryption Parameters 7 | 8 | Endpoint: 9 | 10 | ```plaintext 11 | GET /generate-encryption-parameters/{enc_algo} 12 | ``` 13 | 14 | Sample Request: 15 | 16 | ```plaintext 17 | curl 'http://localhost:8080/generate-encryption-parameters' 18 | ``` 19 | 20 | OR 21 | 22 | ```plaintext 23 | curl 'http://localhost:8080/generate-encryption-parameters/chacha20' 24 | ``` 25 | 26 | 27 | |Name|Type|Description| 28 | |---|---|---| 29 | |`enc_algo`
(Optional)|String|Specify the encryption algorithm being used for encryption/decryption process. Key and Initialization parameters would be constructed accordingly. **Valid values:** ChaCha20, chacha or AES. Defaults to `AES`. 30 | 31 | 32 | Response: 33 | 34 | ```plaintext 35 | { 36 | "base64_iv" : "F6VxNXu/DgeFSJN8pAzWYw==", 37 | "base64_symmetric_key" : "i/vzG5meue8XOVecwyFwDmuwvnRDUIBU5MHIrlusrFs=" 38 | } 39 | ``` 40 | 41 | |Name|Type|Description| 42 | |---|---|---| 43 | |`base64_symmetric_key`|String|Based on the algorithm choosen, 256 bits csprng symmetric key. Its Base64 encoded for transmiting purposes | 44 | |`base64_iv`|String|AES needs 16 bytes Initialization vector and ChaCha20 needs 12 bytes nonces. Based on the algorithm choosen, corresponding unique, csprng initialization vector. It is base64 encoded for transmiting purposes| 45 | 46 | 47 | 48 | ## Step 2A: Encryption Operation 49 | 50 | ```plaintext 51 | POST /encrypt 52 | ``` 53 | 54 | Sample Request 55 | 56 | ```plaintext 57 | curl 'http://localhost:8080/encrypt' -X POST -H "Content-Type: application/json" -d \ 58 | '{"base64_symmetric_key" : "i/vzG5meue8XOVecwyFwDmuwvnRDUIBU5MHIrlusrFs=", 59 | "base64_iv" : "F6VxNXu/DgeFSJN8pAzWYw==", 60 | "plain_text":"Hello Crypto World!", 61 | "aad":"localhost"}' -s | json_pp 62 | ``` 63 | 64 | |Name|Type|Description| 65 | |---|---|---| 66 | |`base64_symmetric_key`
(Required)|String|Base64 encoded symmetric key from above operation| 67 | |`base64_iv`
(Required)|String|Base64 encoded initialization vector from above operation| 68 | |`plain_text`
(Required)|String|Secret plain text message to be encrypted| 69 | |`aad`
(Required only for AES)|String|Authentication Tag of atleast 128 bits in length. Common practice is origin location.| 70 | 71 | Response: 72 | 73 | ```plaintext 74 | { 75 | "aad" : "localhost", 76 | "base64_cipher_text" : "7MHFX0GCarLb9/xporC38Ft98ZHMMZnFxqSQfazRNSFEg1I=", 77 | "base64_iv" : "F6VxNXu/DgeFSJN8pAzWYw==", 78 | "base64_symmetric_key" : "i/vzG5meue8XOVecwyFwDmuwvnRDUIBU5MHIrlusrFs=", 79 | "plain_text" : "Hello Crypto World!" 80 | } 81 | ``` 82 | 83 | |Name|Type|Description| 84 | |---|---|---| 85 | |`base64_symmetric_key`|String|Base64 encoded symmetric key from above operation| 86 | |`base64_iv`|String|Base64 encoded initialization vector from above operation| 87 | |`plain_text`|String|Secret plain text message to be encrypted| 88 | |`base64_cipher_text`|String|Corresponding Cipher text, base64 encoded for transmission| 89 | |`aad`|String|Authentication Tag of atleast 128 bits in length. Common practice is origin location.| 90 | 91 | 92 | ## Step 2B: Decryption Operation: 93 | 94 | ```plaintext 95 | POST /decrypt 96 | ``` 97 | 98 | Sample Request 99 | 100 | ```plaintext 101 | curl 'http://localhost:8080/decrypt' -X POST -H "Content-Type: application/json" \ 102 | -d '{"base64_symmetric_key":"i/vzG5meue8XOVecwyFwDmuwvnRDUIBU5MHIrlusrFs=", 103 | "base64_iv":"F6VxNXu/DgeFSJN8pAzWYw==", 104 | "aad":"localhost", 105 | "base64_cipher_text":"7MHFX0GCarLb9/xporC38Ft98ZHMMZnFxqSQfazRNSFEg1I="}' 106 | ``` 107 | 108 | |Name|Type|Description| 109 | |---|---|---| 110 | |`base64_symmetric_key`
(Required)|String|Base64 encoded symmetric key from above operation| 111 | |`base64_iv`
(Required)|String|Base64 encoded initialization vector from above operation| 112 | |`base64_cipher_text`
(Required)|String|Base64 encoded cipher text| 113 | |`aad`
(Required only for AES)|String|Authentication Tag of atleast 128 bits in length. Common practice is origin location.| 114 | 115 | Response: 116 | 117 | ```plaintext 118 | { 119 | "aad" : "localhost", 120 | "base64_cipher_text" : "7MHFX0GCarLb9/xporC38Ft98ZHMMZnFxqSQfazRNSFEg1I=", 121 | "base64_iv" : "F6VxNXu/DgeFSJN8pAzWYw==", 122 | "base64_symmetric_key" : "i/vzG5meue8XOVecwyFwDmuwvnRDUIBU5MHIrlusrFs=", 123 | "plain_text" : "Hello Crypto World!" 124 | } 125 | ``` 126 | 127 | |Name|Type|Description| 128 | |---|---|---| 129 | |`base64_symmetric_key`|String|Base64 encoded symmetric key from above operation| 130 | |`base64_iv`|String|Base64 encoded initialization vector from above operation| 131 | |`base64_cipher_text`|String|Base64 encoded cipher text| 132 | |`plaintext`|String|Original Plain Text| 133 | |`aad`|String|Authentication Tag of atleast 128 bits in length. Common practice is origin location.| -------------------------------------------------------------------------------- /doc/api/hashing.md: -------------------------------------------------------------------------------- 1 | # Generating a Hash: 2 | 3 | Endpoint: 4 | 5 | ```plaintext 6 | POST /digest 7 | ``` 8 | 9 | 10 | Sample Request: 11 | 12 | ```plaintext 13 | curl 'http://localhost:8080/digest' \ 14 | -X POST -H "Content-type: application/json" \ 15 | -d '{"message":"Hello Hashing!!!","hashing-algo":"SHA3256"}' | json_pp 16 | ``` 17 | 18 | |Name|Type|Description| 19 | |---|---|---| 20 | |`message`
(Required)|String|Message to be hashed| 21 | |`hashing-algo`
(Optional)|String|Hashing algorithm to be used. Possible values from [Java Security Standard Algorithm Names](https://docs.oracle.com/en/java/javase/18/docs/specs/security/standard-names.html#messagedigest-algorithms). Default Value: SHA-512| 22 | 23 | 24 | Response: 25 | 26 | ```plaintext 27 | { 28 | "hash" : "Mb9x21/z6XCh3OiwzWSfkxnybuKPRe0FiSqxLDkNDGRPcRzcvEHUrSRF6iseByz/qVtgXc3qYe4U1gWZkM2B7A==", 29 | "hashing-algo" : "SHA3-512", 30 | "message" : "Hello Hashing!!!" 31 | } 32 | ``` 33 | 34 | |Name|Type|Description| 35 | |---|---|---| 36 | |`message`|String|Message to be hashed| 37 | |`hashing-algo`|String|Hashing algorithm to be used. Possible values from [Java Security Standard Algorithm Names](https://docs.oracle.com/en/java/javase/18/docs/specs/security/standard-names.html#messagedigest-algorithms). Default Valye: SHA-512| 38 | |`hash`|String|Computed Hash value of above `message`| 39 | -------------------------------------------------------------------------------- /doc/api/key_management.md: -------------------------------------------------------------------------------- 1 | # Storing Encryption Keys in Key Store 2 | - Generates Symmetric Keys 3 | - Stores 4 | 5 | ```plaintext 6 | POST /store-secret-key 7 | ``` 8 | 9 | Sample Request 10 | 11 | ```plaintext 12 | ``` 13 | 14 | |Name|Type|Description| 15 | |---|---|---| 16 | 17 | 18 | Response: 19 | 20 | ```plaintext 21 | ``` 22 | 23 | |Name|Type|Description| 24 | |---|---|---| -------------------------------------------------------------------------------- /doc/api/message_authentication_code.md: -------------------------------------------------------------------------------- 1 | # Computing Hashed Message Authentication Code (MAC) 2 | 3 | ## Compute HMAC Symmetric Key 4 | 5 | 6 | Endpoint: 7 | 8 | ```plaintext 9 | GET /compute-hmac-key/{hmac_enc_algo} 10 | ``` 11 | 12 | Sample Request: 13 | 14 | ```plaintext 15 | curl 'http://localhost:8080/compute-hmac-key/' -X POST -H "Content-type: application/json" | json_pp 16 | ``` 17 | 18 | or 19 | 20 | ```plaintext 21 | curl 'http://localhost:8080/compute-hmac-key/HmacSHA256' -X POST -H "Content-type: application/json" -s | json_pp 22 | ``` 23 | 24 | |Name|Type|Description| 25 | |---|---|---| 26 | |`hmac_enc_algo`
(Optional)|String|Hmac algorithm to be used. Possible values to be choosed from [Java Security Standard Algorithm Names](https://docs.oracle.com/en/java/javase/18/docs/specs/security/standard-names.html#mac-algorithms)| 27 | 28 | 29 | Response: 30 | 31 | ```plaintext 32 | { 33 | "base64-symmetric-key" : "l+fgI0xKB/hjZTBfrXf09HxWhLdsDyzpGzA7jZf/5jo=" 34 | } 35 | ``` 36 | 37 | |Name|Type|Description| 38 | |---|---|---| 39 | |`base64-symmetric-key`|String|Symmetric Key for computing MAC| 40 | 41 | ## Compute HMAC 42 | 43 | ```plaintext 44 | POST /compute-hmac 45 | ``` 46 | 47 | Sample Request: 48 | 49 | ```plaintext 50 | curl 'http://localhost:8080/compute-hmac' -X POST -H "Content-type: application/json" \ 51 | -d '{"message":"Hello MAC!!!","base64-symmetric-key":"l+fgI0xKB/hjZTBfrXf09HxWhLdsDyzpGzA7jZf/5jo="}' | json_pp 52 | ``` 53 | 54 | 55 | |Name|Type|Description| 56 | |---|---|---| 57 | |`message`
(Required)|String|Input message whose MAC needs to be computed| 58 | |`base64-symmetric-key`
(Required)|String|Symmetric Key for computing MAC| 59 | 60 | 61 | Response: 62 | 63 | ```plaintext 64 | { 65 | "base64-symmetric-key" : "l+fgI0xKB/hjZTBfrXf09HxWhLdsDyzpGzA7jZf/5jo=", 66 | "mac" : "9BC5MixuWp6l1yiPB0ZmlsYp5bmnk2W4+U+GeFNQglv+pMhEJ2/tmudBumRvCfwhGCJ3L93xgD1oIzqe+tlN9w==", 67 | "message" : "Hello MAC!!!" 68 | } 69 | ``` 70 | 71 | |Name|Type|Description| 72 | |---|---|---| 73 | |`message`|String|Input message whose MAC needs to be computed| 74 | |`base64-symmetric-key`|String|Symmetric Key for computing MAC| 75 | |`mac`|String|Computed MAC| -------------------------------------------------------------------------------- /doc/api/password_storage.md: -------------------------------------------------------------------------------- 1 | # Generating Hashed Password using Key Derivative Functions (KDF) for Secure Storage: 2 | 3 | ## Compute salt 4 | 5 | Endpoint: 6 | 7 | ```plaintext 8 | GET /compute-salt/{kdf_algo} 9 | ``` 10 | 11 | Sample Request: 12 | 13 | ```plaintext 14 | curl 'http://localhost:8080/compute-salt' -s | json_pp 15 | ``` 16 | 17 | OR 18 | 19 | ```plaintext 20 | curl 'http://localhost:8080/compute-salt/pbkdf2' 21 | ``` 22 | 23 | |Name|Type|Description| 24 | |---|---|---| 25 | |`kdf-algo`
(Optional)|String|KDF Algorithm to be used to compute the password hash for storage. **Valid Values:**: pbkdf, bcrypt, scrypt, argon2. Default Argon2.| 26 | 27 | 28 | Response: 29 | 30 | ```plaintext 31 | { 32 | "base64-salt" : "I3+v64AxbXK9qVrvOV04H/fAHy5q/InjZe0791RzS5k=" 33 | } 34 | ``` 35 | 36 | |Name|Type|Description| 37 | |---|---|---| 38 | |`base64-salt`|String|Salt to use to compute password hash for storage| 39 | 40 | 41 | ## Compute KDFed Password 42 | 43 | ```plaintext 44 | POST /compute-kdf-passwd 45 | ``` 46 | 47 | Sample Request: 48 | 49 | ```plaintext 50 | curl 'http://localhost:8080/compute-kdf-passwd' -X POST -H "Content-type: application/json" \ 51 | -d '{"base64-salt":"I3+v64AxbXK9qVrvOV04H/fAHy5q/InjZe0791RzS5k=","passwd":"mysupersecretpasswordtobestored!!!","kdf-algo":"Argon2"}'| json_pp 52 | ``` 53 | 54 | 55 | |Name|Type|Description| 56 | |---|---|---| 57 | |`base64-salt`
(Required)|String|Salt to use to compute password hash for storage| 58 | |`kdf-algo`
(Optional)|String|KDF Algorithm to be used to compute the password hash for storage. **Valid Values:**: pbkdf, bcrypt, scrypt, argon2. Default Argon2.| 59 | |`passwd`
(Required)|String|User password to be storage. NEVER store it in plain text, store the computed hash| 60 | 61 | 62 | Response: 63 | 64 | ```plaintext 65 | { 66 | "base64-kdf-passwd-hash" : "t0YePwK9TPbtnGXqvwYU8Msp7iKLzuqdQ4VcGyW9T+s=", 67 | "base64-salt" : "I3+v64AxbXK9qVrvOV04H/fAHy5q/InjZe0791RzS5k=", 68 | "kdf-algo" : "Argon2", 69 | "passwd" : "mysupersecretpasswordtobestored!!!" 70 | } 71 | ``` 72 | |Name|Type|Description| 73 | |---|---|---| 74 | |`base64-salt`|String|Salt to use for computing password hash for storage| 75 | |`kdf-algo`|String|KDF Algorithm to be used to compute the password hash for storage| 76 | |`passwd`|String|User password to be storage. NEVER store it in plain text, store the computed hash| 77 | |`base64-kdf-passwd-hash`|String|Password Hash computed using `kdf-algo` & `base64-salt` to be stored| 78 | 79 | 80 | -------------------------------------------------------------------------------- /doc/images/JavaCrypto-Architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1MansiS/JavaCrypto/7a70c0241501c4ac7fcd25fcf033325f8bf33f8c/doc/images/JavaCrypto-Architecture.png --------------------------------------------------------------------------------