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