mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-11-29 07:42:06 +01:00
Initial commit
This commit is contained in:
commit
6dd2e83acf
27 changed files with 1325 additions and 0 deletions
14
.gitignore
vendored
Normal file
14
.gitignore
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
.idea
|
||||||
|
.gradle
|
||||||
|
|
||||||
|
out/
|
||||||
|
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.class
|
||||||
|
*.log
|
||||||
|
*.jar
|
||||||
|
|
||||||
|
|
||||||
|
!gradle-wrapper.jar
|
18
build.gradle
Normal file
18
build.gradle
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
plugins {
|
||||||
|
id 'java'
|
||||||
|
}
|
||||||
|
|
||||||
|
group 'de.vanitasvitae.crypto'
|
||||||
|
version '0.1-SNAPSHOT'
|
||||||
|
|
||||||
|
sourceCompatibility = 1.8
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
testCompile group: 'junit', name: 'junit', version: '4.12'
|
||||||
|
compile 'org.bouncycastle:bcprov-jdk15on:1.59'
|
||||||
|
compile 'org.bouncycastle:bcpg-jdk15on:1.59'
|
||||||
|
}
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
5
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-bin.zip
|
172
gradlew
vendored
Executable file
172
gradlew
vendored
Executable file
|
@ -0,0 +1,172 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
##
|
||||||
|
## Gradle start up script for UN*X
|
||||||
|
##
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
PRG="$0"
|
||||||
|
# Need this for relative symlinks.
|
||||||
|
while [ -h "$PRG" ] ; do
|
||||||
|
ls=`ls -ld "$PRG"`
|
||||||
|
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||||
|
if expr "$link" : '/.*' > /dev/null; then
|
||||||
|
PRG="$link"
|
||||||
|
else
|
||||||
|
PRG=`dirname "$PRG"`"/$link"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
SAVED="`pwd`"
|
||||||
|
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||||
|
APP_HOME="`pwd -P`"
|
||||||
|
cd "$SAVED" >/dev/null
|
||||||
|
|
||||||
|
APP_NAME="Gradle"
|
||||||
|
APP_BASE_NAME=`basename "$0"`
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS=""
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD="maximum"
|
||||||
|
|
||||||
|
warn () {
|
||||||
|
echo "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
die () {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "`uname`" in
|
||||||
|
CYGWIN* )
|
||||||
|
cygwin=true
|
||||||
|
;;
|
||||||
|
Darwin* )
|
||||||
|
darwin=true
|
||||||
|
;;
|
||||||
|
MINGW* )
|
||||||
|
msys=true
|
||||||
|
;;
|
||||||
|
NONSTOP* )
|
||||||
|
nonstop=true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||||
|
else
|
||||||
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD="java"
|
||||||
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||||
|
MAX_FD_LIMIT=`ulimit -H -n`
|
||||||
|
if [ $? -eq 0 ] ; then
|
||||||
|
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||||
|
MAX_FD="$MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
ulimit -n $MAX_FD
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Darwin, add options to specify how the application appears in the dock
|
||||||
|
if $darwin; then
|
||||||
|
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Cygwin, switch paths to Windows format before running java
|
||||||
|
if $cygwin ; then
|
||||||
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
|
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||||
|
|
||||||
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
|
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||||
|
SEP=""
|
||||||
|
for dir in $ROOTDIRSRAW ; do
|
||||||
|
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||||
|
SEP="|"
|
||||||
|
done
|
||||||
|
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||||
|
# Add a user-defined pattern to the cygpath arguments
|
||||||
|
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||||
|
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||||
|
fi
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
i=0
|
||||||
|
for arg in "$@" ; do
|
||||||
|
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||||
|
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||||
|
|
||||||
|
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||||
|
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||||
|
else
|
||||||
|
eval `echo args$i`="\"$arg\""
|
||||||
|
fi
|
||||||
|
i=$((i+1))
|
||||||
|
done
|
||||||
|
case $i in
|
||||||
|
(0) set -- ;;
|
||||||
|
(1) set -- "$args0" ;;
|
||||||
|
(2) set -- "$args0" "$args1" ;;
|
||||||
|
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||||
|
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||||
|
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||||
|
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||||
|
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||||
|
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||||
|
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Escape application args
|
||||||
|
save () {
|
||||||
|
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||||
|
echo " "
|
||||||
|
}
|
||||||
|
APP_ARGS=$(save "$@")
|
||||||
|
|
||||||
|
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||||
|
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||||
|
|
||||||
|
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||||
|
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
84
gradlew.bat
vendored
Normal file
84
gradlew.bat
vendored
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
@if "%DEBUG%" == "" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS=
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if "%ERRORLEVEL%" == "0" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:init
|
||||||
|
@rem Get command-line arguments, handling Windows variants
|
||||||
|
|
||||||
|
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||||
|
|
||||||
|
:win9xME_args
|
||||||
|
@rem Slurp the command line arguments.
|
||||||
|
set CMD_LINE_ARGS=
|
||||||
|
set _SKIP=2
|
||||||
|
|
||||||
|
:win9xME_args_slurp
|
||||||
|
if "x%~1" == "x" goto execute
|
||||||
|
|
||||||
|
set CMD_LINE_ARGS=%*
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
2
settings.gradle
Normal file
2
settings.gradle
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
rootProject.name = 'pgpainless'
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless;
|
||||||
|
|
||||||
|
public class EncryptionBuilder {
|
||||||
|
|
||||||
|
}
|
44
src/main/java/de/vanitasvitae/crypto/pgpainless/Main.java
Normal file
44
src/main/java/de/vanitasvitae/crypto/pgpainless/Main.java
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.NoSuchProviderException;
|
||||||
|
import java.security.Security;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.algorithm.KeyFlag;
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.generation.KeySpec;
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.generation.type.DSA;
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.generation.type.RSA_GENERAL;
|
||||||
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
|
||||||
|
public static void main(String[] args)
|
||||||
|
throws NoSuchAlgorithmException, PGPException, NoSuchProviderException, IOException {
|
||||||
|
Security.addProvider(new BouncyCastleProvider());
|
||||||
|
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing()
|
||||||
|
.generateCompositeKeyRing()
|
||||||
|
.withSubKey(
|
||||||
|
KeySpec.getBuilder()
|
||||||
|
.ofType(RSA_GENERAL._4096)
|
||||||
|
.withKeyFlags(KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE)
|
||||||
|
.withStandardConfiguration())
|
||||||
|
.done()
|
||||||
|
.withCertificationKeyType(
|
||||||
|
KeySpec.getBuilder()
|
||||||
|
.ofType(DSA._3072)
|
||||||
|
.withKeyFlags(KeyFlag.SIGN_DATA)
|
||||||
|
.withStandardConfiguration())
|
||||||
|
.withPrimaryUserId("Test123")
|
||||||
|
.done()
|
||||||
|
.withoutPassphrase()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
byte[] base64 = Base64.getEncoder().encode(secretKeys.getEncoded());
|
||||||
|
|
||||||
|
System.out.println(new String(base64));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless;
|
||||||
|
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.generation.KeyRingBuilder;
|
||||||
|
|
||||||
|
public class PGPainless {
|
||||||
|
|
||||||
|
public static KeyRingBuilder generateKeyRing() {
|
||||||
|
return new KeyRingBuilder();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class PainlessResult {
|
||||||
|
Set<Long> signingKeys;
|
||||||
|
Long decryptingKey;
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.algorithm;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.sun.istack.internal.NotNull;
|
||||||
|
|
||||||
|
public class AlgorithmSuite {
|
||||||
|
|
||||||
|
private static AlgorithmSuite defaultAlgorithmSuite = new AlgorithmSuite(
|
||||||
|
Arrays.asList(
|
||||||
|
SymmetricKeyAlgorithm.AES_256,
|
||||||
|
SymmetricKeyAlgorithm.AES_192,
|
||||||
|
SymmetricKeyAlgorithm.AES_128),
|
||||||
|
Arrays.asList(
|
||||||
|
HashAlgorithm.SHA512,
|
||||||
|
HashAlgorithm.SHA384,
|
||||||
|
HashAlgorithm.SHA256,
|
||||||
|
HashAlgorithm.SHA224,
|
||||||
|
HashAlgorithm.SHA1),
|
||||||
|
Arrays.asList(
|
||||||
|
CompressionAlgorithm.ZLIB,
|
||||||
|
CompressionAlgorithm.BZIP2,
|
||||||
|
CompressionAlgorithm.ZIP,
|
||||||
|
CompressionAlgorithm.UNCOMPRESSED)
|
||||||
|
);
|
||||||
|
|
||||||
|
private List<SymmetricKeyAlgorithm> symmetricKeyAlgorithms;
|
||||||
|
private List<HashAlgorithm> hashAlgorithms;
|
||||||
|
private List<CompressionAlgorithm> compressionAlgorithms;
|
||||||
|
|
||||||
|
public AlgorithmSuite(@NotNull List<SymmetricKeyAlgorithm> symmetricKeyAlgorithms,
|
||||||
|
@NotNull List<HashAlgorithm> hashAlgorithms,
|
||||||
|
@NotNull List<CompressionAlgorithm> compressionAlgorithms) {
|
||||||
|
this.symmetricKeyAlgorithms = Collections.unmodifiableList(symmetricKeyAlgorithms);
|
||||||
|
this.hashAlgorithms = Collections.unmodifiableList(hashAlgorithms);
|
||||||
|
this.compressionAlgorithms = Collections.unmodifiableList(compressionAlgorithms);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSymmetricKeyAlgorithms(@NotNull List<SymmetricKeyAlgorithm> symmetricKeyAlgorithms) {
|
||||||
|
this.symmetricKeyAlgorithms = symmetricKeyAlgorithms;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<SymmetricKeyAlgorithm> getSymmetricKeyAlgorithms() {
|
||||||
|
return new ArrayList<>(symmetricKeyAlgorithms);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getSymmetricKeyAlgorithmIds() {
|
||||||
|
int[] array = new int[symmetricKeyAlgorithms.size()];
|
||||||
|
for (int i = 0; i < array.length; i++) {
|
||||||
|
array[i] = symmetricKeyAlgorithms.get(i).getAlgorithmId();
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHashAlgorithms(@NotNull List<HashAlgorithm> hashAlgorithms) {
|
||||||
|
this.hashAlgorithms = hashAlgorithms;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<HashAlgorithm> getHashAlgorithms() {
|
||||||
|
return hashAlgorithms;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getHashAlgorithmIds() {
|
||||||
|
int[] array = new int[hashAlgorithms.size()];
|
||||||
|
for (int i = 0; i < array.length; i++) {
|
||||||
|
array[i] = hashAlgorithms.get(i).getAlgorithmId();
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCompressionAlgorithms(@NotNull List<CompressionAlgorithm> compressionAlgorithms) {
|
||||||
|
this.compressionAlgorithms = compressionAlgorithms;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<CompressionAlgorithm> getCompressionAlgorithms() {
|
||||||
|
return compressionAlgorithms;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getCompressionAlgorithmIds() {
|
||||||
|
int[] array = new int[compressionAlgorithms.size()];
|
||||||
|
for (int i = 0; i < array.length; i++) {
|
||||||
|
array[i] = compressionAlgorithms.get(i).getAlgorithmId();
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AlgorithmSuite getDefaultAlgorithmSuite() {
|
||||||
|
return defaultAlgorithmSuite;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.algorithm;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.bouncycastle.bcpg.CompressionAlgorithmTags;
|
||||||
|
|
||||||
|
public enum CompressionAlgorithm {
|
||||||
|
|
||||||
|
UNCOMPRESSED( CompressionAlgorithmTags.UNCOMPRESSED),
|
||||||
|
ZIP( CompressionAlgorithmTags.ZIP),
|
||||||
|
ZLIB( CompressionAlgorithmTags.ZLIB),
|
||||||
|
BZIP2( CompressionAlgorithmTags.BZIP2),
|
||||||
|
;
|
||||||
|
|
||||||
|
private static final Map<Integer, CompressionAlgorithm> MAP = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
for (CompressionAlgorithm c : CompressionAlgorithm.values()) {
|
||||||
|
MAP.put(c.algorithmId, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CompressionAlgorithm fromId(int id) {
|
||||||
|
return MAP.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final int algorithmId;
|
||||||
|
|
||||||
|
CompressionAlgorithm(int id) {
|
||||||
|
this.algorithmId = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAlgorithmId() {
|
||||||
|
return algorithmId;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.algorithm;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.bouncycastle.bcpg.sig.Features;
|
||||||
|
|
||||||
|
public enum Feature {
|
||||||
|
MODIFICATION_DETECTION(Features.FEATURE_MODIFICATION_DETECTION),
|
||||||
|
;
|
||||||
|
|
||||||
|
private static final Map<Byte, Feature> MAP = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
for (Feature f : Feature.values()) {
|
||||||
|
MAP.put(f.featureId, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Feature fromId(byte id) {
|
||||||
|
return MAP.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final byte featureId;
|
||||||
|
|
||||||
|
Feature(byte featureId) {
|
||||||
|
this.featureId = featureId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getFeatureId() {
|
||||||
|
return featureId;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.algorithm;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.bouncycastle.bcpg.HashAlgorithmTags;
|
||||||
|
|
||||||
|
public enum HashAlgorithm {
|
||||||
|
|
||||||
|
MD5( HashAlgorithmTags.MD5),
|
||||||
|
SHA1( HashAlgorithmTags.SHA1),
|
||||||
|
RIPEMD160( HashAlgorithmTags.RIPEMD160),
|
||||||
|
DOUBLE_SHA( HashAlgorithmTags.DOUBLE_SHA),
|
||||||
|
MD2( HashAlgorithmTags.MD2),
|
||||||
|
TIGER_192( HashAlgorithmTags.TIGER_192),
|
||||||
|
HAVAL_5_160(HashAlgorithmTags.HAVAL_5_160),
|
||||||
|
SHA256( HashAlgorithmTags.SHA256),
|
||||||
|
SHA384( HashAlgorithmTags.SHA384),
|
||||||
|
SHA512( HashAlgorithmTags.SHA512),
|
||||||
|
SHA224( HashAlgorithmTags.SHA224),
|
||||||
|
;
|
||||||
|
// Coincidence? I don't this so...
|
||||||
|
private static final Map<Integer, HashAlgorithm> MAP = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
for (HashAlgorithm h : HashAlgorithm.values()) {
|
||||||
|
MAP.put(h.algorithmId, h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HashAlgorithm fromId(int id) {
|
||||||
|
return MAP.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final int algorithmId;
|
||||||
|
|
||||||
|
HashAlgorithm(int id) {
|
||||||
|
this.algorithmId = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAlgorithmId() {
|
||||||
|
return algorithmId;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.algorithm;
|
||||||
|
|
||||||
|
import org.bouncycastle.bcpg.sig.KeyFlags;
|
||||||
|
|
||||||
|
public enum KeyFlag {
|
||||||
|
|
||||||
|
CERTIFY_OTHER( KeyFlags.CERTIFY_OTHER),
|
||||||
|
SIGN_DATA( KeyFlags.SIGN_DATA),
|
||||||
|
ENCRYPT_COMMS( KeyFlags.ENCRYPT_COMMS),
|
||||||
|
ENCRYPT_STORAGE(KeyFlags.ENCRYPT_STORAGE),
|
||||||
|
SPLIT( KeyFlags.SPLIT),
|
||||||
|
AUTHENTICATION( KeyFlags.AUTHENTICATION),
|
||||||
|
SHARED( KeyFlags.SHARED),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final int flag;
|
||||||
|
|
||||||
|
KeyFlag(int flag) {
|
||||||
|
this.flag = flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFlag() {
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.algorithm;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
|
||||||
|
|
||||||
|
public enum PublicKeyAlgorithm {
|
||||||
|
|
||||||
|
RSA_GENERAL( PublicKeyAlgorithmTags.RSA_GENERAL),
|
||||||
|
RSA_ENCRYPT( PublicKeyAlgorithmTags.RSA_ENCRYPT),
|
||||||
|
RSA_SIGN( PublicKeyAlgorithmTags.RSA_SIGN),
|
||||||
|
ELGAMAL_ENCRYPT(PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT),
|
||||||
|
DSA(PublicKeyAlgorithmTags.DSA),
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link #ECDH} instead.
|
||||||
|
*/
|
||||||
|
EC( PublicKeyAlgorithmTags.EC),
|
||||||
|
ECDH( PublicKeyAlgorithmTags.ECDH),
|
||||||
|
ECDSA( PublicKeyAlgorithmTags.ECDSA),
|
||||||
|
ELGAMAL_GENERAL(PublicKeyAlgorithmTags.ELGAMAL_GENERAL),
|
||||||
|
DIFFIE_HELLMAN( PublicKeyAlgorithmTags.DIFFIE_HELLMAN),
|
||||||
|
;
|
||||||
|
|
||||||
|
private static final Map<Integer, PublicKeyAlgorithm> MAP = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
for (PublicKeyAlgorithm p : PublicKeyAlgorithm.values()) {
|
||||||
|
MAP.put(p.algorithmId, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PublicKeyAlgorithm fromId(int id) {
|
||||||
|
return MAP.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final int algorithmId;
|
||||||
|
|
||||||
|
PublicKeyAlgorithm(int algorithmId) {
|
||||||
|
this.algorithmId = algorithmId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAlgorithmId() {
|
||||||
|
return algorithmId;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.algorithm;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
|
||||||
|
|
||||||
|
public enum SymmetricKeyAlgorithm {
|
||||||
|
|
||||||
|
NULL( SymmetricKeyAlgorithmTags.NULL),
|
||||||
|
IDEA( SymmetricKeyAlgorithmTags.IDEA),
|
||||||
|
TRIPLE_DES( SymmetricKeyAlgorithmTags.TRIPLE_DES),
|
||||||
|
CAST5( SymmetricKeyAlgorithmTags.CAST5),
|
||||||
|
BLOWFISH( SymmetricKeyAlgorithmTags.BLOWFISH),
|
||||||
|
SAFER( SymmetricKeyAlgorithmTags.SAFER),
|
||||||
|
DES( SymmetricKeyAlgorithmTags.DES),
|
||||||
|
AES_128( SymmetricKeyAlgorithmTags.AES_128),
|
||||||
|
AES_192( SymmetricKeyAlgorithmTags.AES_192),
|
||||||
|
AES_256( SymmetricKeyAlgorithmTags.AES_256),
|
||||||
|
TWOFISH( SymmetricKeyAlgorithmTags.TWOFISH),
|
||||||
|
CAMELLIA_128( SymmetricKeyAlgorithmTags.CAMELLIA_128),
|
||||||
|
CAMELLIA_192( SymmetricKeyAlgorithmTags.CAMELLIA_192),
|
||||||
|
CAMELLIA_256( SymmetricKeyAlgorithmTags.CAMELLIA_256),
|
||||||
|
;
|
||||||
|
|
||||||
|
private static final Map<Integer, SymmetricKeyAlgorithm> MAP = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
for (SymmetricKeyAlgorithm s : SymmetricKeyAlgorithm.values()) {
|
||||||
|
MAP.put(s.algorithmId, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SymmetricKeyAlgorithm forId(int id) {
|
||||||
|
return MAP.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final int algorithmId;
|
||||||
|
|
||||||
|
SymmetricKeyAlgorithm(int algorithmId) {
|
||||||
|
this.algorithmId = algorithmId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAlgorithmId() {
|
||||||
|
return algorithmId;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,213 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.generation;
|
||||||
|
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.security.KeyPair;
|
||||||
|
import java.security.KeyPairGenerator;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.NoSuchProviderException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.algorithm.KeyFlag;
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.generation.type.KeyType;
|
||||||
|
import org.bouncycastle.bcpg.HashAlgorithmTags;
|
||||||
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
|
import org.bouncycastle.openpgp.PGPEncryptedData;
|
||||||
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
|
import org.bouncycastle.openpgp.PGPKeyPair;
|
||||||
|
import org.bouncycastle.openpgp.PGPKeyRingGenerator;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
|
import org.bouncycastle.openpgp.PGPSignature;
|
||||||
|
import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator;
|
||||||
|
import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor;
|
||||||
|
import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder;
|
||||||
|
import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
|
||||||
|
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
|
||||||
|
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
|
||||||
|
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair;
|
||||||
|
import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder;
|
||||||
|
|
||||||
|
public class KeyRingBuilder implements KeyRingBuilderInterface {
|
||||||
|
|
||||||
|
private final Charset UTF8 = Charset.forName("UTF-8");
|
||||||
|
|
||||||
|
private List<KeySpec> keySpecs = new ArrayList<>();
|
||||||
|
private List<String> userIds = new ArrayList<>();
|
||||||
|
private char[] passphrase;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WithSubKeyType generateCompositeKeyRing() {
|
||||||
|
return new WithSubKeyTypeImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WithCertificationKeyType generateSingleKeyKeyRing() {
|
||||||
|
return new WithCertificationKeyTypeImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
class WithSubKeyTypeImpl implements WithSubKeyType {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WithSubKeyType withSubKey(KeySpec type) {
|
||||||
|
KeyRingBuilder.this.keySpecs.add(type);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WithCertificationKeyType done() {
|
||||||
|
return new WithCertificationKeyTypeImpl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class WithCertificationKeyTypeImpl implements WithCertificationKeyType {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WithPrimaryUserId withCertificationKeyType(KeySpec spec) {
|
||||||
|
if ((spec.getKeyFlags() & KeyFlag.CERTIFY_OTHER.getFlag()) == 0) {
|
||||||
|
throw new IllegalArgumentException("Certification Key MUST have KeyFlag CERTIFY_OTHER");
|
||||||
|
}
|
||||||
|
KeyRingBuilder.this.keySpecs.add(spec);
|
||||||
|
return new WithPrimaryUserIdImpl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class WithPrimaryUserIdImpl implements WithPrimaryUserId {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WithAdditionalUserIds withPrimaryUserId(String userId) {
|
||||||
|
KeyRingBuilder.this.userIds.add(userId);
|
||||||
|
return new WithAdditionalUserIdsImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WithAdditionalUserIds withPrimaryUserId(byte[] userId) {
|
||||||
|
return withPrimaryUserId(new String(userId, UTF8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class WithAdditionalUserIdsImpl implements WithAdditionalUserIds {
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
@Override
|
||||||
|
public WithAdditionalUserIds withAdditionalUserId(String userId) {
|
||||||
|
KeyRingBuilder.this.userIds.add(userId);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
@Override
|
||||||
|
public WithAdditionalUserIds withAdditionalUserId(byte[] userId) {
|
||||||
|
return withAdditionalUserId(new String(userId, UTF8));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WithPassphrase done() {
|
||||||
|
return new WithPassphraseImpl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class WithPassphraseImpl implements WithPassphrase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Build withPassphrase(String passphrase) {
|
||||||
|
return withPassphrase(passphrase.toCharArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Build withPassphrase(char[] passphrase) {
|
||||||
|
KeyRingBuilder.this.passphrase = passphrase;
|
||||||
|
return new BuildImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Build withoutPassphrase() {
|
||||||
|
KeyRingBuilder.this.passphrase = null;
|
||||||
|
return new BuildImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
class BuildImpl implements Build {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PGPSecretKeyRing build() throws NoSuchAlgorithmException, PGPException, NoSuchProviderException {
|
||||||
|
|
||||||
|
// Hash Calculator
|
||||||
|
PGPDigestCalculator calculator = new JcaPGPDigestCalculatorProviderBuilder()
|
||||||
|
.setProvider(BouncyCastleProvider.PROVIDER_NAME)
|
||||||
|
.build()
|
||||||
|
.get(HashAlgorithmTags.SHA1);
|
||||||
|
|
||||||
|
// Encryptor for encrypting secret keys
|
||||||
|
PBESecretKeyEncryptor encryptor = passphrase == null ?
|
||||||
|
null : // unencrypted key pair, otherwise AES-256 encrypted
|
||||||
|
new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256, calculator)
|
||||||
|
.setProvider(BouncyCastleProvider.PROVIDER_NAME)
|
||||||
|
.build(passphrase);
|
||||||
|
|
||||||
|
// First key is the Master Key
|
||||||
|
KeySpec certKeySpec = keySpecs.get(0);
|
||||||
|
KeyType certKeyType = certKeySpec.getKeyType();
|
||||||
|
keySpecs.remove(0); // Remove master key, so that we later only add sub keys.
|
||||||
|
|
||||||
|
// Generate Master Key
|
||||||
|
PGPKeyPair certKey = generateKeyPair(certKeySpec);
|
||||||
|
|
||||||
|
// Signer for creating self-signature
|
||||||
|
PGPContentSignerBuilder signer = new JcaPGPContentSignerBuilder(
|
||||||
|
certKey.getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA256);
|
||||||
|
|
||||||
|
// Mimic GnuPGs signature sub packets
|
||||||
|
PGPSignatureSubpacketGenerator hashedSubPackets = new PGPSignatureSubpacketGenerator();
|
||||||
|
|
||||||
|
// Key flags
|
||||||
|
hashedSubPackets.setKeyFlags(true, certKeySpec.getKeyFlags());
|
||||||
|
|
||||||
|
// Encryption Algorithms
|
||||||
|
hashedSubPackets.setPreferredSymmetricAlgorithms(true,
|
||||||
|
certKeySpec.getPreferredAlgorithms().getSymmetricKeyAlgorithmIds());
|
||||||
|
|
||||||
|
// Hash Algorithms
|
||||||
|
hashedSubPackets.setPreferredHashAlgorithms(true,
|
||||||
|
certKeySpec.getPreferredAlgorithms().getHashAlgorithmIds());
|
||||||
|
|
||||||
|
// Compression Algorithms
|
||||||
|
hashedSubPackets.setPreferredCompressionAlgorithms(true,
|
||||||
|
certKeySpec.getPreferredAlgorithms().getCompressionAlgorithmIds());
|
||||||
|
|
||||||
|
// Modification Detection
|
||||||
|
hashedSubPackets.setFeature(true, certKeySpec.getFeatures());
|
||||||
|
|
||||||
|
// Generator which the user can get the key pair from
|
||||||
|
PGPKeyRingGenerator ringGenerator = new PGPKeyRingGenerator(
|
||||||
|
PGPSignature.POSITIVE_CERTIFICATION, certKey,
|
||||||
|
userIds.get(0), calculator,
|
||||||
|
hashedSubPackets.generate(), null, signer, encryptor);
|
||||||
|
|
||||||
|
for (KeySpec subKeySpec : keySpecs) {
|
||||||
|
PGPKeyPair subKey = generateKeyPair(subKeySpec);
|
||||||
|
ringGenerator.addSubKey(subKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ringGenerator.generateSecretKeyRing();
|
||||||
|
}
|
||||||
|
|
||||||
|
private PGPKeyPair generateKeyPair(KeySpec spec)
|
||||||
|
throws NoSuchProviderException, NoSuchAlgorithmException, PGPException {
|
||||||
|
KeyType type = spec.getKeyType();
|
||||||
|
KeyPairGenerator certKeyGenerator = KeyPairGenerator.getInstance(
|
||||||
|
type.getName(), BouncyCastleProvider.PROVIDER_NAME);
|
||||||
|
certKeyGenerator.initialize(type.getLength());
|
||||||
|
|
||||||
|
// Create raw Key Pair
|
||||||
|
KeyPair rawKeyPair = certKeyGenerator.generateKeyPair();
|
||||||
|
|
||||||
|
// Form PGP key pair
|
||||||
|
PGPKeyPair pgpKeyPair = new JcaPGPKeyPair(type.getAlgorithm().getAlgorithmId(),
|
||||||
|
rawKeyPair, new Date());
|
||||||
|
|
||||||
|
return pgpKeyPair;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.generation;
|
||||||
|
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.NoSuchProviderException;
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
|
|
||||||
|
public interface KeyRingBuilderInterface {
|
||||||
|
|
||||||
|
WithSubKeyType generateCompositeKeyRing();
|
||||||
|
|
||||||
|
WithCertificationKeyType generateSingleKeyKeyRing();
|
||||||
|
|
||||||
|
interface WithSubKeyType {
|
||||||
|
|
||||||
|
WithSubKeyType withSubKey(KeySpec keySpec);
|
||||||
|
|
||||||
|
WithCertificationKeyType done();
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WithCertificationKeyType {
|
||||||
|
WithPrimaryUserId withCertificationKeyType(KeySpec keySpec);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WithPrimaryUserId {
|
||||||
|
|
||||||
|
WithAdditionalUserIds withPrimaryUserId(String userId);
|
||||||
|
|
||||||
|
WithAdditionalUserIds withPrimaryUserId(byte[] userId);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WithAdditionalUserIds {
|
||||||
|
|
||||||
|
WithAdditionalUserIds withAdditionalUserId(String userId);
|
||||||
|
|
||||||
|
WithAdditionalUserIds withAdditionalUserId(byte[] userId);
|
||||||
|
|
||||||
|
WithPassphrase done();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WithPassphrase {
|
||||||
|
|
||||||
|
Build withPassphrase(String passphrase);
|
||||||
|
|
||||||
|
Build withPassphrase(char[] passphrase);
|
||||||
|
|
||||||
|
Build withoutPassphrase();
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Build {
|
||||||
|
|
||||||
|
PGPSecretKeyRing build() throws NoSuchAlgorithmException, PGPException, NoSuchProviderException;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.generation;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.algorithm.AlgorithmSuite;
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.algorithm.Feature;
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.generation.type.KeyType;
|
||||||
|
|
||||||
|
public class KeySpec {
|
||||||
|
|
||||||
|
private final KeyType keyType;
|
||||||
|
private final int keyFlags;
|
||||||
|
private final AlgorithmSuite algorithmSuite;
|
||||||
|
private final Set<Feature> features;
|
||||||
|
|
||||||
|
KeySpec(KeyType type,
|
||||||
|
int keyFlags,
|
||||||
|
AlgorithmSuite preferredAlgorithms,
|
||||||
|
Set<Feature> features) {
|
||||||
|
this.keyType = type;
|
||||||
|
this.keyFlags = keyFlags;
|
||||||
|
this.algorithmSuite = preferredAlgorithms;
|
||||||
|
this.features = features;
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyType getKeyType() {
|
||||||
|
return keyType;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getKeyFlags() {
|
||||||
|
return keyFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
AlgorithmSuite getPreferredAlgorithms() {
|
||||||
|
return algorithmSuite;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte getFeatures() {
|
||||||
|
byte val = 0;
|
||||||
|
for (Feature f : features) {
|
||||||
|
val |= f.getFeatureId();
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeySpecBuilder getBuilder() {
|
||||||
|
return new KeySpecBuilder();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,140 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.generation;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.algorithm.AlgorithmSuite;
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.algorithm.CompressionAlgorithm;
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.algorithm.Feature;
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.algorithm.HashAlgorithm;
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.algorithm.KeyFlag;
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.algorithm.SymmetricKeyAlgorithm;
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.generation.type.KeyType;
|
||||||
|
|
||||||
|
public class KeySpecBuilder implements KeySpecBuilderInterface {
|
||||||
|
|
||||||
|
private KeyType type;
|
||||||
|
private int keyFlags;
|
||||||
|
private AlgorithmSuite algorithmSuite = AlgorithmSuite.getDefaultAlgorithmSuite();
|
||||||
|
private Set<Feature> features = new HashSet<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WithKeyFlags ofType(KeyType type) {
|
||||||
|
KeySpecBuilder.this.type = type;
|
||||||
|
return new WithKeyFlagsImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
class WithKeyFlagsImpl implements WithKeyFlags {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WithDetailedConfiguration withKeyFlags(KeyFlag... flags) {
|
||||||
|
int val = 0;
|
||||||
|
for (KeyFlag f : flags) {
|
||||||
|
val |= f.getFlag();
|
||||||
|
}
|
||||||
|
KeySpecBuilder.this.keyFlags = val;
|
||||||
|
return new WithDetailedConfigurationImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WithDetailedConfiguration withDefaultKeyFlags() {
|
||||||
|
return withKeyFlags(
|
||||||
|
KeyFlag.CERTIFY_OTHER,
|
||||||
|
KeyFlag.SIGN_DATA,
|
||||||
|
KeyFlag.ENCRYPT_COMMS,
|
||||||
|
KeyFlag.ENCRYPT_STORAGE,
|
||||||
|
KeyFlag.AUTHENTICATION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class WithDetailedConfigurationImpl implements WithDetailedConfiguration {
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
@Override
|
||||||
|
public WithPreferredSymmetricAlgorithms withDetailedConfiguration() {
|
||||||
|
return new WithPreferredSymmetricAlgorithmsImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KeySpec withStandardConfiguration() {
|
||||||
|
return new KeySpec(
|
||||||
|
KeySpecBuilder.this.type,
|
||||||
|
KeySpecBuilder.this.keyFlags,
|
||||||
|
KeySpecBuilder.this.algorithmSuite,
|
||||||
|
KeySpecBuilder.this.features);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class WithPreferredSymmetricAlgorithmsImpl implements WithPreferredSymmetricAlgorithms {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WithPreferredHashAlgorithms withPreferredSymmetricAlgorithms(SymmetricKeyAlgorithm... algorithms) {
|
||||||
|
KeySpecBuilder.this.algorithmSuite.setSymmetricKeyAlgorithms(Arrays.asList(algorithms));
|
||||||
|
return new WithPreferredHashAlgorithmsImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WithPreferredHashAlgorithms withDefaultSymmetricAlgorithms() {
|
||||||
|
KeySpecBuilder.this.algorithmSuite.setSymmetricKeyAlgorithms(
|
||||||
|
AlgorithmSuite.getDefaultAlgorithmSuite().getSymmetricKeyAlgorithms());
|
||||||
|
return new WithPreferredHashAlgorithmsImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WithFeatures withDefaultAlgorithms() {
|
||||||
|
KeySpecBuilder.this.algorithmSuite = AlgorithmSuite.getDefaultAlgorithmSuite();
|
||||||
|
return new WithFeaturesImpl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class WithPreferredHashAlgorithmsImpl implements WithPreferredHashAlgorithms {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WithPreferredCompressionAlgorithms withPreferredHashAlgorithms(HashAlgorithm... algorithms) {
|
||||||
|
KeySpecBuilder.this.algorithmSuite.setHashAlgorithms(Arrays.asList(algorithms));
|
||||||
|
return new WithPreferredCompressionAlgorithmsImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WithPreferredCompressionAlgorithms withDefaultHashAlgorithms() {
|
||||||
|
KeySpecBuilder.this.algorithmSuite.setHashAlgorithms(
|
||||||
|
AlgorithmSuite.getDefaultAlgorithmSuite().getHashAlgorithms());
|
||||||
|
return new WithPreferredCompressionAlgorithmsImpl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class WithPreferredCompressionAlgorithmsImpl implements WithPreferredCompressionAlgorithms {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WithFeatures withPreferredCompressionAlgorithms(CompressionAlgorithm... algorithms) {
|
||||||
|
KeySpecBuilder.this.algorithmSuite.setCompressionAlgorithms(Arrays.asList(algorithms));
|
||||||
|
return new WithFeaturesImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WithFeatures withDefaultCompressionAlgorithms() {
|
||||||
|
KeySpecBuilder.this.algorithmSuite.setCompressionAlgorithms(
|
||||||
|
AlgorithmSuite.getDefaultAlgorithmSuite().getCompressionAlgorithms());
|
||||||
|
return new WithFeaturesImpl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class WithFeaturesImpl implements WithFeatures {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WithFeatures withFeature(Feature feature) {
|
||||||
|
KeySpecBuilder.this.features.add(feature);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KeySpec done() {
|
||||||
|
return new KeySpec(
|
||||||
|
KeySpecBuilder.this.type,
|
||||||
|
KeySpecBuilder.this.keyFlags,
|
||||||
|
KeySpecBuilder.this.algorithmSuite,
|
||||||
|
KeySpecBuilder.this.features);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.generation;
|
||||||
|
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.algorithm.AlgorithmSuite;
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.algorithm.CompressionAlgorithm;
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.algorithm.Feature;
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.algorithm.HashAlgorithm;
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.algorithm.KeyFlag;
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.algorithm.SymmetricKeyAlgorithm;
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.generation.type.KeyType;
|
||||||
|
|
||||||
|
public interface KeySpecBuilderInterface {
|
||||||
|
|
||||||
|
WithKeyFlags ofType(KeyType type);
|
||||||
|
|
||||||
|
interface WithKeyFlags {
|
||||||
|
|
||||||
|
WithDetailedConfiguration withKeyFlags(KeyFlag... flags);
|
||||||
|
|
||||||
|
WithDetailedConfiguration withDefaultKeyFlags();
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WithDetailedConfiguration {
|
||||||
|
|
||||||
|
WithPreferredSymmetricAlgorithms withDetailedConfiguration();
|
||||||
|
|
||||||
|
KeySpec withStandardConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WithPreferredSymmetricAlgorithms {
|
||||||
|
|
||||||
|
WithPreferredHashAlgorithms withPreferredSymmetricAlgorithms(SymmetricKeyAlgorithm... algorithms);
|
||||||
|
|
||||||
|
WithPreferredHashAlgorithms withDefaultSymmetricAlgorithms();
|
||||||
|
|
||||||
|
WithFeatures withDefaultAlgorithms();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WithPreferredHashAlgorithms {
|
||||||
|
|
||||||
|
WithPreferredCompressionAlgorithms withPreferredHashAlgorithms(HashAlgorithm... algorithms);
|
||||||
|
|
||||||
|
WithPreferredCompressionAlgorithms withDefaultHashAlgorithms();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WithPreferredCompressionAlgorithms {
|
||||||
|
|
||||||
|
WithFeatures withPreferredCompressionAlgorithms(CompressionAlgorithm... algorithms);
|
||||||
|
|
||||||
|
WithFeatures withDefaultCompressionAlgorithms();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WithFeatures {
|
||||||
|
|
||||||
|
WithFeatures withFeature(Feature feature);
|
||||||
|
|
||||||
|
KeySpec done();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.generation.type;
|
||||||
|
|
||||||
|
import java.security.KeyPairGenerator;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.algorithm.PublicKeyAlgorithm;
|
||||||
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
|
|
||||||
|
public enum DSA implements KeyType {
|
||||||
|
|
||||||
|
_1024(1024),
|
||||||
|
_2048(2048),
|
||||||
|
_3072(3072),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final int length;
|
||||||
|
|
||||||
|
DSA(int length) {
|
||||||
|
this.length = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLength() {
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "DSA";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PublicKeyAlgorithm getAlgorithm() {
|
||||||
|
return PublicKeyAlgorithm.DSA;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.generation.type;
|
||||||
|
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.algorithm.PublicKeyAlgorithm;
|
||||||
|
|
||||||
|
public enum ElGamal_ENCRYPT implements KeyType {
|
||||||
|
|
||||||
|
_1024(1024),
|
||||||
|
_2048(2048),
|
||||||
|
_3072(3072),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final int length;
|
||||||
|
|
||||||
|
ElGamal_ENCRYPT(int length) {
|
||||||
|
this.length = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLength() {
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "ElGamal";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PublicKeyAlgorithm getAlgorithm() {
|
||||||
|
return PublicKeyAlgorithm.ELGAMAL_ENCRYPT;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.generation.type;
|
||||||
|
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.algorithm.PublicKeyAlgorithm;
|
||||||
|
|
||||||
|
public interface KeyType {
|
||||||
|
|
||||||
|
int getLength();
|
||||||
|
|
||||||
|
String getName();
|
||||||
|
|
||||||
|
PublicKeyAlgorithm getAlgorithm();
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.generation.type;
|
||||||
|
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.algorithm.PublicKeyAlgorithm;
|
||||||
|
|
||||||
|
public enum RSA_GENERAL implements KeyType {
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
_1024(1024),
|
||||||
|
@Deprecated
|
||||||
|
_2048(2048),
|
||||||
|
_3072(3072),
|
||||||
|
_4096(4096),
|
||||||
|
_8192(8192),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final int length;
|
||||||
|
|
||||||
|
RSA_GENERAL(int length) {
|
||||||
|
this.length = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLength() {
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "RSA";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PublicKeyAlgorithm getAlgorithm() {
|
||||||
|
return PublicKeyAlgorithm.RSA_GENERAL;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue