Compare commits
9 commits
Author | SHA1 | Date | |
---|---|---|---|
Jan Dittberner | c4f16a00a6 | ||
Jan Dittberner | 26bc7c2abe | ||
13297bbe19 | |||
b009be3e17 | |||
21465a1be6 | |||
Jan Dittberner | 16dbe32f83 | ||
Jan Dittberner | 25ee9f6237 | ||
Jan Dittberner | 8800020856 | ||
Jan Dittberner | a1245cf4ae |
11
.gitignore
vendored
11
.gitignore
vendored
|
@ -1,5 +1,10 @@
|
|||
target/
|
||||
.settings/
|
||||
*.iml
|
||||
.*.swp
|
||||
.checkstyle
|
||||
.project
|
||||
.classpath
|
||||
.gradle/
|
||||
.idea/
|
||||
.project
|
||||
.settings/
|
||||
build/
|
||||
target/
|
||||
|
|
20
LICENSE.txt
Normal file
20
LICENSE.txt
Normal file
|
@ -0,0 +1,20 @@
|
|||
Copyright (c) 2011-2014 Jan Dittberner
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
18
build.gradle
Normal file
18
build.gradle
Normal file
|
@ -0,0 +1,18 @@
|
|||
apply plugin: 'java'
|
||||
|
||||
project.version = '0.3-SNAPSHOT'
|
||||
project.description = '''
|
||||
Demonstrate how to perform S/MIME encryption and decryption of mails using BouncyCastle.
|
||||
'''
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile group: 'org.bouncycastle', name: 'bcmail-jdk15on', version: '1.62'
|
||||
compile group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '1.62'
|
||||
compile group: 'javax.mail', name: 'javax.mail-api', version: '1.6.2'
|
||||
compile group: 'com.sun.mail', name: 'javax.mail', version: '1.6.2'
|
||||
testCompile group: 'junit', name: 'junit', version: '4.12'
|
||||
}
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
#Sat May 21 22:42:34 CEST 2016
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-bin.zip
|
164
gradlew
vendored
Executable file
164
gradlew
vendored
Executable file
|
@ -0,0 +1,164 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# 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
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
esac
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched.
|
||||
if $cygwin ; then
|
||||
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
fi
|
||||
|
||||
# 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\"`/" >&-
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >&-
|
||||
|
||||
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" ] ; 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"`
|
||||
|
||||
# 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
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
90
gradlew.bat
vendored
Normal file
90
gradlew.bat
vendored
Normal file
|
@ -0,0 +1,90 @@
|
|||
@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
|
||||
|
||||
@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=
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@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 Windowz variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
if "%@eval[2+2]" == "4" goto 4NT_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=%*
|
||||
goto execute
|
||||
|
||||
:4NT_args
|
||||
@rem Get arguments from the 4NT Shell from JP Software
|
||||
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
|
45
pom.xml
45
pom.xml
|
@ -21,15 +21,25 @@ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
--><modelVersion>4.0.0</modelVersion>
|
||||
-->
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>de.communardo.jdi</groupId>
|
||||
<groupId>info.dittberner</groupId>
|
||||
<artifactId>bcsmime-demo</artifactId>
|
||||
<version>0.1</version>
|
||||
<description>Demonstrate how to perform S/MIME encryption and decryption of mails using BouncyCastle</description>
|
||||
<version>0.2</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>bcsmime-demo</name>
|
||||
<url>http://maven.apache.org</url>
|
||||
<url>http://jan.dittberner.info/bcsmime-demo</url>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>MIT</name>
|
||||
<url>LICENSE.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
@ -39,19 +49,28 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<version>4.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcmail-jdk16</artifactId>
|
||||
<version>1.46</version>
|
||||
<artifactId>bcmail-jdk15on</artifactId>
|
||||
<version>1.53</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk15on</artifactId>
|
||||
<version>1.53</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.mail</groupId>
|
||||
<artifactId>mail</artifactId>
|
||||
<version>1.4.4</version>
|
||||
<scope>compile</scope>
|
||||
<artifactId>javax.mail-api</artifactId>
|
||||
<version>1.5.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.mail</groupId>
|
||||
<artifactId>javax.mail</artifactId>
|
||||
<version>1.5.4</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
@ -62,11 +81,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>2.3.2</version>
|
||||
<configuration>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
<showDeprecation>false</showDeprecation>
|
||||
|
||||
<!--<encoding>UTF-8</encoding>-->
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2011 Jan Dittberner
|
||||
* Copyright (c) 2011-2014 Jan Dittberner
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
|
@ -20,17 +20,7 @@
|
|||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package de.communardo.jdi.bcsmime_demo;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.security.KeyStore;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
package info.dittberner.bcsmime_demo;
|
||||
|
||||
import org.bouncycastle.cms.RecipientInformation;
|
||||
import org.bouncycastle.cms.RecipientInformationStore;
|
||||
|
@ -38,6 +28,14 @@ import org.bouncycastle.cms.jcajce.JceKeyTransEnvelopedRecipient;
|
|||
import org.bouncycastle.cms.jcajce.JceKeyTransRecipientId;
|
||||
import org.bouncycastle.mail.smime.SMIMEEnveloped;
|
||||
|
||||
import javax.mail.Session;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.security.KeyStore;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* S/MIME encryption using the new BouncyCastle 1.46 APIs.
|
||||
*
|
||||
|
@ -66,7 +64,7 @@ public class SMIMEDecrypt {
|
|||
* if an error occurs
|
||||
*/
|
||||
public MimeMessage decryptMessage(MimeMessage encrypted)
|
||||
throws MessagingException, Exception {
|
||||
throws Exception {
|
||||
SMIMEEnveloped message = new SMIMEEnveloped(encrypted);
|
||||
|
||||
RecipientInformationStore recinfos = message.getRecipientInfos();
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2011 Jan Dittberner
|
||||
* Copyright (c) 2011-2014 Jan Dittberner
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
|
@ -20,32 +20,28 @@
|
|||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package de.communardo.jdi.bcsmime_demo;
|
||||
package info.dittberner.bcsmime_demo;
|
||||
|
||||
import java.security.KeyStore;
|
||||
import java.security.cert.CertStore;
|
||||
import java.security.cert.CertStoreParameters;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CollectionCertStoreParameters;
|
||||
import java.security.cert.X509CertSelector;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
|
||||
import org.bouncycastle.asn1.pkcs.RSAESOAEPparams;
|
||||
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
|
||||
import org.bouncycastle.asn1.x509.GeneralName;
|
||||
import org.bouncycastle.cms.CMSAlgorithm;
|
||||
import org.bouncycastle.cms.jcajce.JceCMSContentEncryptorBuilder;
|
||||
import org.bouncycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator;
|
||||
import org.bouncycastle.mail.smime.SMIMEEnvelopedGenerator;
|
||||
import org.bouncycastle.operator.OutputEncryptor;
|
||||
|
||||
import javax.mail.Address;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeBodyPart;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
|
||||
import org.bouncycastle.asn1.x509.GeneralName;
|
||||
import org.bouncycastle.cms.CMSAlgorithm;
|
||||
import org.bouncycastle.cms.RecipientInfoGenerator;
|
||||
import org.bouncycastle.cms.jcajce.JceCMSContentEncryptorBuilder;
|
||||
import org.bouncycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator;
|
||||
import org.bouncycastle.mail.smime.SMIMEEnvelopedGenerator;
|
||||
import org.bouncycastle.operator.OutputEncryptor;
|
||||
import java.security.KeyStore;
|
||||
import java.security.cert.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* S/MIME encryption using the new BouncyCastle 1.46 APIs.
|
||||
|
@ -58,11 +54,10 @@ public class SMIMEEncrypt {
|
|||
/**
|
||||
* Creates a new SMIMEEncrypt instance.
|
||||
*
|
||||
* @param keystore
|
||||
* key store to use for recipient certificates
|
||||
* @param keystore key store to use for recipient certificates
|
||||
*/
|
||||
public SMIMEEncrypt(KeyStore keystore) {
|
||||
List<Certificate> certificates = new ArrayList<Certificate>();
|
||||
List<Certificate> certificates = new ArrayList<>();
|
||||
|
||||
try {
|
||||
Enumeration<String> aliases = keystore.aliases();
|
||||
|
@ -85,19 +80,19 @@ public class SMIMEEncrypt {
|
|||
/**
|
||||
* Encrypts a MimeMessage to all its recipients.
|
||||
*
|
||||
* @param message
|
||||
* MIME message to encrypt
|
||||
* @param message MIME message to encrypt
|
||||
* @return encrypted S/MIME message
|
||||
* @throws Exception
|
||||
* if an error occurs
|
||||
* @throws Exception if an error occurs
|
||||
*/
|
||||
public MimeMessage encryptMessage(MimeMessage message) throws Exception {
|
||||
SMIMEEnvelopedGenerator smeg = new SMIMEEnvelopedGenerator();
|
||||
for (Address recipient : message.getAllRecipients()) {
|
||||
Collection<? extends Certificate> certificates = getCertificates((InternetAddress) recipient);
|
||||
for (Certificate cert : certificates) {
|
||||
RecipientInfoGenerator recipientInfoGen = new JceKeyTransRecipientInfoGenerator(
|
||||
(X509Certificate) cert);
|
||||
RSAESOAEPparams params = new RSAESOAEPparams();
|
||||
AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_RSAES_OAEP, params);
|
||||
JceKeyTransRecipientInfoGenerator recipientInfoGen = new JceKeyTransRecipientInfoGenerator((X509Certificate) cert, algorithmIdentifier);
|
||||
recipientInfoGen.setAlgorithmMapping(PKCSObjectIdentifiers.id_RSAES_OAEP, "RSA/OAEP");
|
||||
smeg.addRecipientInfoGenerator(recipientInfoGen);
|
||||
}
|
||||
}
|
||||
|
@ -114,11 +109,9 @@ public class SMIMEEncrypt {
|
|||
/**
|
||||
* Helper method for getting certificates from a keystore.
|
||||
*
|
||||
* @param recipient
|
||||
* recipient address
|
||||
* @param recipient recipient address
|
||||
* @return X.509 certificate for recipient
|
||||
* @throws Exception
|
||||
* if an error occurs
|
||||
* @throws Exception if an error occurs
|
||||
*/
|
||||
private Collection<? extends Certificate> getCertificates(
|
||||
InternetAddress recipient) throws Exception {
|
|
@ -0,0 +1,27 @@
|
|||
package info.dittberner.jcajceprovidertest.sectest;
|
||||
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
|
||||
import java.security.Provider;
|
||||
import java.security.Security;
|
||||
|
||||
/**
|
||||
* Utility to list all available Security providers and their implemented algorithm names.
|
||||
*
|
||||
* @author Jan Dittberner <<a href="mailto:jan@dittberner.info>jan@dittberner.info</a>>
|
||||
*/
|
||||
public class ListAlgorithmNames {
|
||||
public static void main(String[] args) {
|
||||
if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
}
|
||||
|
||||
for (Provider provider : Security.getProviders()) {
|
||||
System.out.println("Provider: " + provider.getName());
|
||||
for (Provider.Service service : provider.getServices()) {
|
||||
System.out.println(" Algorithm: " + service.getAlgorithm());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -20,44 +20,31 @@
|
|||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package de.communardo.jdi.bcsmime_demo;
|
||||
package info.dittberner.bcsmime_demo;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.KeyStore;
|
||||
import java.security.Security;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.Date;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.mail.BodyPart;
|
||||
import javax.mail.Message.RecipientType;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Multipart;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.Message.RecipientType;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeBodyPart;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import javax.mail.internet.MimeMultipart;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.bouncycastle.asn1.x500.X500Name;
|
||||
import org.bouncycastle.asn1.x509.BasicConstraints;
|
||||
import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
|
||||
import org.bouncycastle.asn1.x509.GeneralName;
|
||||
import org.bouncycastle.asn1.x509.GeneralNames;
|
||||
import org.bouncycastle.asn1.x509.KeyPurposeId;
|
||||
import org.bouncycastle.asn1.x509.KeyUsage;
|
||||
import org.bouncycastle.asn1.x509.X509Extension;
|
||||
import org.bouncycastle.cert.X509CertificateHolder;
|
||||
import org.bouncycastle.cert.X509v3CertificateBuilder;
|
||||
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
|
||||
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.bouncycastle.operator.ContentSigner;
|
||||
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
* Test Encryption and Decryption.
|
||||
|
@ -66,15 +53,20 @@ import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
|||
* "mailto:jan.dittberner@t-systems.com>jan.dittberner@t-systems.com</a>
|
||||
* & g t ;
|
||||
*/
|
||||
public class EncryptDecryptTest extends TestCase {
|
||||
public class EncryptDecryptTest {
|
||||
String[][] testEntries = new String[][]{
|
||||
new String[]{"test1", "testrecpt1@example.org", "Test Recipient 1"},
|
||||
new String[]{"test2", "testrecpt2@example.org", "Test Recipient 2"}
|
||||
};
|
||||
private KeyStore keystore;
|
||||
private Logger logger = Logger.getLogger(EncryptDecryptTest.class.getName());
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see junit.framework.TestCase#setUp()
|
||||
*/
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
|
@ -86,41 +78,25 @@ public class EncryptDecryptTest extends TestCase {
|
|||
|
||||
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
|
||||
kpg.initialize(2048);
|
||||
KeyPair keypair = kpg.generateKeyPair();
|
||||
|
||||
X500Name issuer = new X500Name(
|
||||
"CN=Test Recipient,emailAddress=testrecpt@example.org");
|
||||
X500Name subject = issuer;
|
||||
X509v3CertificateBuilder certbuilder = new JcaX509v3CertificateBuilder(
|
||||
issuer, BigInteger.valueOf(System.currentTimeMillis()),
|
||||
new Date(System.currentTimeMillis() - 50000), new Date(
|
||||
System.currentTimeMillis() + 50000), subject,
|
||||
keypair.getPublic());
|
||||
certbuilder.addExtension(X509Extension.basicConstraints, true,
|
||||
new BasicConstraints(true));
|
||||
certbuilder.addExtension(X509Extension.keyUsage, true,
|
||||
new KeyUsage(KeyUsage.digitalSignature
|
||||
| KeyUsage.keyEncipherment));
|
||||
certbuilder.addExtension(X509Extension.extendedKeyUsage, true,
|
||||
new ExtendedKeyUsage(KeyPurposeId.id_kp_emailProtection));
|
||||
certbuilder.addExtension(X509Extension.subjectAlternativeName,
|
||||
false, new GeneralNames(new GeneralName(
|
||||
GeneralName.rfc822Name, "testrecpt@example.org")));
|
||||
for (String[] entry : testEntries) {
|
||||
KeyEntryData keyEntryData = new KeyEntryData(kpg, entry[1]);
|
||||
keystore.setKeyEntry(entry[0], keyEntryData.keyPair.getPrivate(), "changeit".toCharArray(), new Certificate[]{keyEntryData.getCertificate()});
|
||||
}
|
||||
|
||||
ContentSigner signer = new JcaContentSignerBuilder("SHA256WithRSA")
|
||||
.build(keypair.getPrivate());
|
||||
X509CertificateHolder certholder = certbuilder.build(signer);
|
||||
|
||||
keystore.setKeyEntry("test", keypair.getPrivate(), "changeit"
|
||||
.toCharArray(),
|
||||
new Certificate[] { (new JcaX509CertificateConverter())
|
||||
.getCertificate(certholder) });
|
||||
}
|
||||
}
|
||||
|
||||
private String messageAsString(MimeMessage message) throws IOException, MessagingException {
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
message.writeTo(byteArrayOutputStream);
|
||||
return byteArrayOutputStream.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of {@link SMIMEEncrypt} and {@link SMIMEDecrypt}.
|
||||
*/
|
||||
@Test
|
||||
public void testEncryptDecryptMail() throws Exception {
|
||||
MimeMessage message = getNewMultipartMessage();
|
||||
assertNotNull(message);
|
||||
|
@ -128,34 +104,36 @@ public class EncryptDecryptTest extends TestCase {
|
|||
SMIMEEncrypt encrypt = new SMIMEEncrypt(keystore);
|
||||
MimeMessage encrypted = encrypt.encryptMessage(message);
|
||||
assertNotNull(encrypted);
|
||||
encrypted.writeTo(System.err);
|
||||
|
||||
logger.info(messageAsString(encrypted));
|
||||
|
||||
SMIMEDecrypt decrypt = new SMIMEDecrypt(keystore);
|
||||
MimeMessage decrypted = decrypt.decryptMessage(encrypted);
|
||||
assertNotNull(decrypted);
|
||||
decrypted.writeTo(System.err);
|
||||
|
||||
logger.info(messageAsString(decrypted));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new MimeMessage with one Bodypart.
|
||||
* Creates a new MimeMessage with one body part.
|
||||
*
|
||||
* @return MimeMessage instance
|
||||
* @throws MessagingException
|
||||
* on error creating the message
|
||||
* @throws MessagingException on error creating the message
|
||||
*/
|
||||
private MimeMessage getNewMultipartMessage() throws MessagingException,
|
||||
IOException {
|
||||
MimeMessage message = new MimeMessage(Session.getDefaultInstance(System
|
||||
.getProperties()));
|
||||
Session mailsession = Session.getDefaultInstance(System.getProperties());
|
||||
MimeMessage message = new MimeMessage(mailsession);
|
||||
message.setFrom(new InternetAddress("testsender@example.org",
|
||||
"Test Sender"));
|
||||
message.addRecipient(RecipientType.TO, new InternetAddress(
|
||||
"testrecpt@example.org", "Test Recipient"));
|
||||
for (String[] entry : testEntries) {
|
||||
message.addRecipient(RecipientType.TO, new InternetAddress(entry[1], entry[2]));
|
||||
}
|
||||
message.setSubject("Test subject");
|
||||
Multipart multipart = new MimeMultipart();
|
||||
BodyPart textpart = new MimeBodyPart();
|
||||
textpart.setText("Das ist ein Text");
|
||||
multipart.addBodyPart(textpart);
|
||||
BodyPart textPart = new MimeBodyPart();
|
||||
textPart.setText("Das ist ein Text");
|
||||
multipart.addBodyPart(textPart);
|
||||
message.setContent(multipart);
|
||||
return message;
|
||||
}
|
58
src/test/java/info/dittberner/bcsmime_demo/KeyEntryData.java
Normal file
58
src/test/java/info/dittberner/bcsmime_demo/KeyEntryData.java
Normal file
|
@ -0,0 +1,58 @@
|
|||
package info.dittberner.bcsmime_demo;
|
||||
|
||||
import org.bouncycastle.asn1.x500.X500Name;
|
||||
import org.bouncycastle.asn1.x509.*;
|
||||
import org.bouncycastle.cert.CertIOException;
|
||||
import org.bouncycastle.cert.X509CertificateHolder;
|
||||
import org.bouncycastle.cert.X509v3CertificateBuilder;
|
||||
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
|
||||
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
|
||||
import org.bouncycastle.operator.ContentSigner;
|
||||
import org.bouncycastle.operator.OperatorCreationException;
|
||||
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Created by jan on 12.10.14.
|
||||
*/
|
||||
public class KeyEntryData {
|
||||
private final X509CertificateHolder certificateHolder;
|
||||
KeyPair keyPair;
|
||||
|
||||
public KeyEntryData(KeyPairGenerator kpg, String address) throws CertIOException, OperatorCreationException {
|
||||
this.keyPair = kpg.generateKeyPair();
|
||||
|
||||
X500Name issuer = new X500Name(
|
||||
String.format("CN=Test Recipient,emailAddress=%s", address));
|
||||
//noinspection UnnecessaryLocalVariable
|
||||
X500Name subject = issuer;
|
||||
X509v3CertificateBuilder certificateBuilder = new JcaX509v3CertificateBuilder(
|
||||
issuer, BigInteger.valueOf(System.currentTimeMillis()),
|
||||
new Date(System.currentTimeMillis() - 50000), new Date(
|
||||
System.currentTimeMillis() + 50000), subject,
|
||||
keyPair.getPublic());
|
||||
certificateBuilder.addExtension(Extension.basicConstraints, true,
|
||||
new BasicConstraints(true));
|
||||
certificateBuilder.addExtension(Extension.keyUsage, true,
|
||||
new KeyUsage(KeyUsage.digitalSignature
|
||||
| KeyUsage.keyEncipherment));
|
||||
certificateBuilder.addExtension(Extension.extendedKeyUsage, true,
|
||||
new ExtendedKeyUsage(KeyPurposeId.id_kp_emailProtection));
|
||||
certificateBuilder.addExtension(Extension.subjectAlternativeName,
|
||||
false, new GeneralNames(new GeneralName(
|
||||
GeneralName.rfc822Name, address)));
|
||||
|
||||
ContentSigner signer = new JcaContentSignerBuilder("SHA256WithRSA")
|
||||
.build(keyPair.getPrivate());
|
||||
this.certificateHolder = certificateBuilder.build(signer);
|
||||
}
|
||||
|
||||
public java.security.cert.Certificate getCertificate() throws CertificateException, CertIOException, OperatorCreationException {
|
||||
return (new JcaX509CertificateConverter()).getCertificate(certificateHolder);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue