mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-11-25 13:52: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