diff --git a/pom.xml b/pom.xml
index 928619b..c319fa6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -48,9 +48,7 @@
0.9.5.5
1.0.2
1.0.9
- 1.68
- 1.68
- 1.68
+ 1.81
3.1.0
@@ -67,17 +65,17 @@
org.nhind
direct-policy
- 8.0.0
+ 8.1.0-SNAPSHOT
org.nhind
direct-common
- 8.0.0
+ 8.1.0-SNAPSHOT
org.nhind
direct-msg-monitor-model
- 8.0.0
+ 8.1.0-SNAPSHOT
org.projectlombok
@@ -112,18 +110,8 @@
org.bouncycastle
- bcprov-jdk15on
- ${bcprov-jdk15on.version}
-
-
- org.bouncycastle
- bcmail-jdk15on
- ${bcmail-jdk15on.version}
-
-
- org.bouncycastle
- bcpkix-jdk15on
- ${bcpkix-jdk15on.version}
+ bcpkix-jdk18on
+ ${bcpkix-jdk18on.version}
dnsjava
@@ -164,6 +152,20 @@
org.springframework.boot
spring-boot-starter-test
test
+
+
+ org.bouncycastle
+ bcprov-jdk15on
+
+
+ org.bouncycastle
+ bcmail-jdk15on
+
+
+ org.bouncycastle
+ bcpkix-jdk15on
+
+
diff --git a/src/main/java/org/nhindirect/stagent/cryptography/EncryptionAlgorithm.java b/src/main/java/org/nhindirect/stagent/cryptography/EncryptionAlgorithm.java
index 27a2d5b..26c0db4 100644
--- a/src/main/java/org/nhindirect/stagent/cryptography/EncryptionAlgorithm.java
+++ b/src/main/java/org/nhindirect/stagent/cryptography/EncryptionAlgorithm.java
@@ -23,6 +23,7 @@ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
package org.nhindirect.stagent.cryptography;
import org.apache.commons.lang3.StringUtils;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.cms.CMSEnvelopedGenerator;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.mail.smime.SMIMEEnvelopedGenerator;
@@ -45,8 +46,10 @@ public enum EncryptionAlgorithm
DES_EDE3_CBC("DESEDE/CBC/PKCS5Padding", CMSEnvelopedGenerator.DES_EDE3_CBC),
AES128_CBC("AES/CBC/PKCS5Padding", CMSEnvelopedGenerator.AES128_CBC),
AES192_CBC("AES/CBC/PKCS5Padding", CMSEnvelopedGenerator.AES192_CBC),
- AES256_CBC("AES/CBC/PKCS5Padding", CMSEnvelopedGenerator.AES256_CBC);
-
+ AES256_CBC("AES/CBC/PKCS5Padding", CMSEnvelopedGenerator.AES256_CBC),
+ RSA_OAEP("RSA_OAEP", PKCSObjectIdentifiers.id_RSAES_OAEP.getId()),
+ RSA_PKCS1_V15("RSA_PKCS1_V15", PKCSObjectIdentifiers.rsaEncryption.getId());
+
protected final String algName;
protected final String OID;
@@ -82,7 +85,9 @@ else if (algorithmName.equalsIgnoreCase(RSA.getAlgName()))
else if (algorithmName.equalsIgnoreCase(RSAandMGF1.getAlgName()))
return RSAandMGF1;
else if (algorithmName.equalsIgnoreCase(ECDSA.getAlgName()))
- return ECDSA;
+ return ECDSA;
+ else if (algorithmName.equalsIgnoreCase(RSA_PKCS1_V15.getAlgName()))
+ return RSA_PKCS1_V15;
else
return defaultAlgorithm;
}
diff --git a/src/main/java/org/nhindirect/stagent/cryptography/SMIMECryptographerImpl.java b/src/main/java/org/nhindirect/stagent/cryptography/SMIMECryptographerImpl.java
index e95f533..0cccc82 100644
--- a/src/main/java/org/nhindirect/stagent/cryptography/SMIMECryptographerImpl.java
+++ b/src/main/java/org/nhindirect/stagent/cryptography/SMIMECryptographerImpl.java
@@ -22,6 +22,7 @@ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
package org.nhindirect.stagent.cryptography;
+import java.security.spec.MGF1ParameterSpec;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -36,6 +37,8 @@ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPublicKey;
+import javax.crypto.spec.OAEPParameterSpec;
+import javax.crypto.spec.PSource;
import javax.mail.MessagingException;
import javax.mail.internet.ContentType;
import javax.mail.internet.InternetHeaders;
@@ -47,12 +50,17 @@ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DLSequence;
import org.bouncycastle.asn1.cms.Attribute;
import org.bouncycastle.asn1.cms.AttributeTable;
import org.bouncycastle.asn1.cms.CMSAttributes;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.RSAESOAEPparams;
import org.bouncycastle.asn1.smime.SMIMECapabilitiesAttribute;
import org.bouncycastle.asn1.smime.SMIMECapability;
import org.bouncycastle.asn1.smime.SMIMECapabilityVector;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.cert.jcajce.JcaCertStore;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
@@ -70,7 +78,9 @@ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
import org.bouncycastle.mail.smime.SMIMEEnveloped;
import org.bouncycastle.mail.smime.SMIMEEnvelopedGenerator;
import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.DefaultAlgorithmNameFinder;
import org.bouncycastle.operator.OutputEncryptor;
+import org.bouncycastle.operator.jcajce.JcaAlgorithmParametersConverter;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import org.nhindirect.common.crypto.CryptoExtensions;
@@ -101,65 +111,125 @@ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
*/
@Slf4j
public class SMIMECryptographerImpl implements Cryptographer
-{
- // Using the BC PKCSObjectIdentifiers type is not compatible across versions of the BC library
- public final static ASN1ObjectIdentifier x509CertificateObjectsIdent = new ASN1ObjectIdentifier("1.2.840.113549.1.9.22.1");
-
+{
+ // Using the BC PKCSObjectIdentifiers type is not compatible across versions of the BC library
+ public final static ASN1ObjectIdentifier x509CertificateObjectsIdent = new ASN1ObjectIdentifier("1.2.840.113549.1.9.22.1");
+
public final static SMIMECryptographerImpl Default = new SMIMECryptographerImpl();
-
+
protected EncryptionAlgorithm m_encryptionAlgorithm;
+
+ protected EncryptionAlgorithm m_keyEncryptionAlgorithm;
+
+ protected DigestAlgorithm m_keyEncryptionDigestAlgorithm;
protected DigestAlgorithm m_digestAlgorithm;
protected boolean m_includeEpilogue = true;
protected boolean enforceStrongEncryption;
protected boolean enforceStrongDigests;
-
- private boolean m_logDigest = false;
-
+
+ private boolean m_logDigest = false;
+
/**
* Constructs a Cryptographer with a default EncryptionAlgorithm and DigestAlgorithm.
*/
public SMIMECryptographerImpl()
{
- OptionsParameter param = OptionsManager.getInstance().getParameter(OptionsParameter.CRYPTOGRAHPER_SMIME_ENCRYPTION_ALGORITHM);
- this.m_encryptionAlgorithm = (param == null) ? EncryptionAlgorithm.AES128 : EncryptionAlgorithm.fromString(param.getParamValue(), EncryptionAlgorithm.AES128);
-
+ OptionsParameter param = OptionsManager.getInstance().getParameter(OptionsParameter.CRYPTOGRAHPER_SMIME_ENCRYPTION_ALGORITHM);
+ this.m_encryptionAlgorithm = (param == null) ? EncryptionAlgorithm.AES128 : EncryptionAlgorithm.fromString(param.getParamValue(), EncryptionAlgorithm.AES128);
+
+ param = OptionsManager.getInstance().getParameter(OptionsParameter.CRYPTOGRAHPER_KEY_ENCRYPTION_ALGORITHM);
+ this.m_keyEncryptionAlgorithm = (param == null) ? EncryptionAlgorithm.RSA_OAEP : EncryptionAlgorithm.fromString(param.getParamValue(), EncryptionAlgorithm.RSA_OAEP);
+
+ param = OptionsManager.getInstance().getParameter(OptionsParameter.CRYPTOGRAHPER_KEY_ENCRYPTION_DIGEST_ALGORITHM);
+ this.m_keyEncryptionDigestAlgorithm = (param == null) ? DigestAlgorithm.SHA1: DigestAlgorithm.fromString(param.getParamValue(), DigestAlgorithm.SHA1);
+
param = OptionsManager.getInstance().getParameter(OptionsParameter.CRYPTOGRAHPER_SMIME_DIGEST_ALGORITHM);
this.m_digestAlgorithm = (param == null) ? DigestAlgorithm.SHA256WITHRSA : DigestAlgorithm.fromString(param.getParamValue(), DigestAlgorithm.SHA256WITHRSA);
-
+
if (!isAllowedDigestAlgorithm(m_digestAlgorithm.getOID()))
- throw new IllegalArgumentException("The digest algorithm " + m_digestAlgorithm.getAlgName() + " is not allowed");
-
+ throw new IllegalArgumentException("The digest algorithm " + m_digestAlgorithm.getAlgName() + " is not allowed");
+
param = OptionsManager.getInstance().getParameter(OptionsParameter.ENFORCE_STRONG_DIGESTS);
this.enforceStrongDigests = OptionsParameter.getParamValueAsBoolean(param, true);
-
+
param = OptionsManager.getInstance().getParameter(OptionsParameter.ENFORCE_STRONG_ENCRYPTION);
this.enforceStrongEncryption = OptionsParameter.getParamValueAsBoolean(param, true);
-
- this.m_logDigest = OptionsParameter.getParamValueAsBoolean(param, false);
+
+ this.m_logDigest = OptionsParameter.getParamValueAsBoolean(param, false);
}
/**
* Constructs a Cryptographer with an EncryptionAlgorithm and DigestAlgorithm.
* @param encryptionAlgorithm The encryption algorithm used to encrypt the message.
* @param digestAlgorithm The digest algorithm used to generate the message digest stored in the message signature.
- */
+ */
public SMIMECryptographerImpl(EncryptionAlgorithm encryptionAlgorithm, DigestAlgorithm digestAlgorithm)
{
this.m_encryptionAlgorithm = encryptionAlgorithm;
this.m_digestAlgorithm = digestAlgorithm;
-
+
+ OptionsParameter param = OptionsManager.getInstance().getParameter(OptionsParameter.ENFORCE_STRONG_DIGESTS);
+ this.enforceStrongDigests = OptionsParameter.getParamValueAsBoolean(param, true);
+
+ if (!isAllowedDigestAlgorithm(m_digestAlgorithm.getOID()))
+ throw new IllegalArgumentException("The digest algorith " + m_digestAlgorithm.getAlgName() + " is not allowed");
+
+ param = OptionsManager.getInstance().getParameter(OptionsParameter.ENFORCE_STRONG_ENCRYPTION);
+ this.enforceStrongEncryption = OptionsParameter.getParamValueAsBoolean(param, true);
+
+ this.m_logDigest = OptionsParameter.getParamValueAsBoolean(param, false);
+
+ param = OptionsManager.getInstance().getParameter(OptionsParameter.CRYPTOGRAHPER_KEY_ENCRYPTION_ALGORITHM);
+ this.m_keyEncryptionAlgorithm = (param == null) ? EncryptionAlgorithm.RSA_OAEP : EncryptionAlgorithm.fromString(param.getParamValue(), EncryptionAlgorithm.RSA_OAEP);
+
+ param = OptionsManager.getInstance().getParameter(OptionsParameter.CRYPTOGRAHPER_KEY_ENCRYPTION_DIGEST_ALGORITHM);
+ this.m_keyEncryptionDigestAlgorithm = (param == null) ? DigestAlgorithm.SHA256 : DigestAlgorithm.fromString(param.getParamValue(), DigestAlgorithm.SHA256);
+
+ }
+
+ public SMIMECryptographerImpl(EncryptionAlgorithm encryptionAlgorithm, DigestAlgorithm digestAlgorithm, EncryptionAlgorithm keyEncryptionAlgorithm)
+ {
+ this.m_encryptionAlgorithm = encryptionAlgorithm;
+ this.m_digestAlgorithm = digestAlgorithm;
+
+ OptionsParameter param = OptionsManager.getInstance().getParameter(OptionsParameter.ENFORCE_STRONG_DIGESTS);
+ this.enforceStrongDigests = OptionsParameter.getParamValueAsBoolean(param, true);
+
+ if (!isAllowedDigestAlgorithm(m_digestAlgorithm.getOID()))
+ throw new IllegalArgumentException("The digest algorith " + m_digestAlgorithm.getAlgName() + " is not allowed");
+
+ param = OptionsManager.getInstance().getParameter(OptionsParameter.ENFORCE_STRONG_ENCRYPTION);
+ this.enforceStrongEncryption = OptionsParameter.getParamValueAsBoolean(param, true);
+
+ this.m_logDigest = OptionsParameter.getParamValueAsBoolean(param, false);
+
+ this.m_keyEncryptionAlgorithm = keyEncryptionAlgorithm;
+
+ param = OptionsManager.getInstance().getParameter(OptionsParameter.CRYPTOGRAHPER_KEY_ENCRYPTION_DIGEST_ALGORITHM);
+ this.m_keyEncryptionDigestAlgorithm = (param == null) ? DigestAlgorithm.SHA256 : DigestAlgorithm.fromString(param.getParamValue(), DigestAlgorithm.SHA256);
+
+ }
+ public SMIMECryptographerImpl(EncryptionAlgorithm encryptionAlgorithm, DigestAlgorithm digestAlgorithm, EncryptionAlgorithm keyEncryptionAlgorithm, DigestAlgorithm keyEncryptionDigestAlgorithm)
+ {
+ this.m_encryptionAlgorithm = encryptionAlgorithm;
+ this.m_digestAlgorithm = digestAlgorithm;
+
OptionsParameter param = OptionsManager.getInstance().getParameter(OptionsParameter.ENFORCE_STRONG_DIGESTS);
this.enforceStrongDigests = OptionsParameter.getParamValueAsBoolean(param, true);
-
+
if (!isAllowedDigestAlgorithm(m_digestAlgorithm.getOID()))
- throw new IllegalArgumentException("The digest algorith " + m_digestAlgorithm.getAlgName() + " is not allowed");
-
+ throw new IllegalArgumentException("The digest algorith " + m_digestAlgorithm.getAlgName() + " is not allowed");
+
param = OptionsManager.getInstance().getParameter(OptionsParameter.ENFORCE_STRONG_ENCRYPTION);
this.enforceStrongEncryption = OptionsParameter.getParamValueAsBoolean(param, true);
-
- this.m_logDigest = OptionsParameter.getParamValueAsBoolean(param, false);
+
+ this.m_logDigest = OptionsParameter.getParamValueAsBoolean(param, false);
+
+ this.m_keyEncryptionAlgorithm = keyEncryptionAlgorithm;
+
+ this.m_keyEncryptionDigestAlgorithm = keyEncryptionDigestAlgorithm;
+
}
-
/**
* Gets the EncryptionAlgorithm.
* @return The EncryptionAlgorithm used to encrypt messages.
@@ -168,7 +238,25 @@ public EncryptionAlgorithm getEncryptionAlgorithm()
{
return this.m_encryptionAlgorithm;
}
-
+
+ /**
+ * Gets the KeyEncryptionAlgorithm.
+ * @return The KeyEncryptionAlgorithm used to encrypt message key.
+ */
+ public EncryptionAlgorithm getKeyEncryptionAlgorithm()
+ {
+ return this.m_keyEncryptionAlgorithm;
+ }
+
+ /**
+ * Gets the KeyEncryptionDigestAlgorithm.
+ * @return The KeyEncryptionDigestAlgorithm used to encrypt message key.
+ */
+ public DigestAlgorithm getKeyEncryptionDigestAlgorithm()
+ {
+ return this.m_keyEncryptionDigestAlgorithm;
+ }
+
/**
* Sets the EncryptionAlgorithm
* @param value The EncryptionAlgorithm used to encrypt messages.
@@ -178,81 +266,99 @@ public void setEncryptionAlgorithm(EncryptionAlgorithm value)
this.m_encryptionAlgorithm = value;
}
+ /**
+ * Sets the KeyEncryptionAlgorithm
+ * @param value The KeyEncryptionAlgorithm used to encrypt message key.
+ */
+ public void setKeyEncryptionAlgorithm(EncryptionAlgorithm value)
+ {
+ this.m_keyEncryptionAlgorithm = value;
+ }
+
+ /**
+ * Sets the KeyEncryptionDigestAlgorithm
+ * @param value The KeyEncryptionAlgorithm used to encrypt message key.
+ */
+ public void setKeyEncryptionDigestAlgorithm(DigestAlgorithm value)
+ {
+ this.m_keyEncryptionDigestAlgorithm = value;
+ }
+
/**
* Gets the DigestAlgorithm.
* @return The DigestAlgorithm used generate the message digest stored in the message signature.
*/
public DigestAlgorithm getDigestAlgorithm()
{
- return this.m_digestAlgorithm;
+ return this.m_digestAlgorithm;
}
-
+
/**
* Sets the DigestAlgorithm.
* @param value The DigestAlgorithm used generate the message digest stored in the message signature.
- */
+ */
public void setDigestAlgorithm(DigestAlgorithm value)
{
if (!isAllowedDigestAlgorithm(value.getOID()))
- throw new IllegalArgumentException("The digest algorithm " + m_digestAlgorithm.getAlgName() + " is not allowed");
-
+ throw new IllegalArgumentException("The digest algorithm " + m_digestAlgorithm.getAlgName() + " is not allowed");
+
this.m_digestAlgorithm = value;
}
-
- /**
+
+ /**
* Indicates if message digests will be logged when verifying messages.
- * @return True if the digests will be logged. False otherwise.
+ * @return True if the digests will be logged. False otherwise.
*/
public boolean isLogDigests()
{
- return this.m_logDigest;
+ return this.m_logDigest;
}
-
+
/**
* Sets the option to enforce strong message digests.
* @param value True if strong message digests are enforced. False otherwise.
- */
+ */
public void setStrongDigestEnforced(Boolean value)
{
this.enforceStrongDigests = value;
}
-
+
/**
* Indicate if strong message digests are enforced
* @return True if strong message digests are enforced. False otherwise.
*/
public boolean isStrongDigestEnforced()
{
- return this.enforceStrongDigests;
+ return this.enforceStrongDigests;
}
-
- /**
+
+ /**
* Sets if message digests will be looged.
* @param m_logDigest True if the digests will be logged. False otherwise.
*/
public void setLogDigests(boolean m_logDigest)
{
- this.m_logDigest = m_logDigest;
+ this.m_logDigest = m_logDigest;
}
-
+
/**
* Sets the option to enforce strong message encryption
* @param value True if strong encryption is enforced. False otherwise.
- */
+ */
public void setStrongEncryptionEnforced(Boolean value)
{
this.enforceStrongEncryption = value;
}
-
+
/**
* Indicate if strong message encryption is enforced
* @return True if strong encryption is enforced. False otherwise.
*/
public boolean isStrongEncryptionEnforced()
{
- return this.enforceStrongEncryption;
+ return this.enforceStrongEncryption;
}
-
+
/**
* Indicates if the the Epilogue part of a multipart entity should be used to generate the message signature.
* @return True if the the Epilogue part of a multipart entity should be used to generate the message signature. False otherwise.
@@ -260,23 +366,23 @@ public boolean isStrongEncryptionEnforced()
public boolean isIncludeMultipartEpilogueInSignature()
{
return this.m_includeEpilogue;
- }
-
+ }
+
/**
* Sets if the the Epilogue part of a multipart entity should be used to generate the message signature.
* @param value True if the the Epilogue part of a multipart entity should be used to generate the message signature. False otherwise.
- */
+ */
public void setIncludeMultipartEpilogueInSignature(boolean value)
{
this.m_includeEpilogue = value;
}
-
+
/*
* Encryption
*/
-
+
/**
- *
+ *
* Encrypts a mulit part MIME entity using the provided certificate.
* @param entity The entity that will be encrypted.
* @param encryptingCertificate The public certificates that will be used to encrypt the message.
@@ -284,12 +390,12 @@ public void setIncludeMultipartEpilogueInSignature(boolean value)
*/
public MimeEntity encrypt(MimeMultipart entity, X509Certificate encryptingCertificate)
{
- Collection certs = new ArrayList();
- certs.add(encryptingCertificate);
-
+ Collection certs = new ArrayList();
+ certs.add(encryptingCertificate);
+
return this.encrypt(entity, certs);
- }
-
+ }
+
/**
* Encrypts a mulit part MIME entity using the provided certificates.
* @param entity The entity that will be encrypted.
@@ -297,30 +403,30 @@ public MimeEntity encrypt(MimeMultipart entity, X509Certificate encryptingCertif
* @return A MimeEntity containing the encrypted part.
*/
@SuppressWarnings("deprecation")
- public MimeEntity encrypt(MimeMultipart mmEntity, Collection encryptingCertificates)
+ public MimeEntity encrypt(MimeMultipart mmEntity, Collection encryptingCertificates)
{
- MimeEntity entToEncrypt = null;
-
- ByteArrayOutputStream oStream = new ByteArrayOutputStream();
- try
- {
- mmEntity.writeTo(oStream);
- oStream.flush();
- InternetHeaders headers = new InternetHeaders();
- headers.addHeader(MimeStandard.ContentTypeHeader, mmEntity.getContentType());
-
-
- entToEncrypt = new MimeEntity(headers, oStream.toByteArray());
- IOUtils.closeQuietly(oStream);
- }
- catch (Exception e)
- {
- throw new MimeException(MimeError.InvalidMimeEntity, e);
- }
-
- return this.encrypt(entToEncrypt, encryptingCertificates);
- }
-
+ MimeEntity entToEncrypt = null;
+
+ ByteArrayOutputStream oStream = new ByteArrayOutputStream();
+ try
+ {
+ mmEntity.writeTo(oStream);
+ oStream.flush();
+ InternetHeaders headers = new InternetHeaders();
+ headers.addHeader(MimeStandard.ContentTypeHeader, mmEntity.getContentType());
+
+
+ entToEncrypt = new MimeEntity(headers, oStream.toByteArray());
+ IOUtils.closeQuietly(oStream);
+ }
+ catch (Exception e)
+ {
+ throw new MimeException(MimeError.InvalidMimeEntity, e);
+ }
+
+ return this.encrypt(entToEncrypt, encryptingCertificates);
+ }
+
/**
* Encrypts an entity using the provided certificate.
* @param entity The entity that will be encrypted.
@@ -329,13 +435,13 @@ public MimeEntity encrypt(MimeMultipart mmEntity, Collection en
*/
public MimeEntity encrypt(MimeEntity entity, X509Certificate encryptingCertificate)
{
- Collection certs = new ArrayList();
- certs.add(encryptingCertificate);
-
+ Collection certs = new ArrayList();
+ certs.add(encryptingCertificate);
+
return this.encrypt(entity, certs);
}
- /**
+ /**
* Encrypts an entity using the provided certificates.
* @param entity The entity that will be encrypted.
* @param encryptingCertificate The public certificates that will be used to encrypt the message.
@@ -347,28 +453,28 @@ public MimeEntity encrypt(MimeEntity entity, Collection encryp
{
throw new IllegalArgumentException();
}
-
- MimeBodyPart partToEncrypt = entity;
+
+ MimeBodyPart partToEncrypt = entity;
MimeBodyPart encryptedPart = this.encrypt(partToEncrypt, encryptingCertificates);
MimeEntity encryptedEntity = null;
-
+
try
{
- byte[] encBytes = EntitySerializer.Default.serializeToBytes(encryptedPart);
- ByteArrayInputStream inStream = new ByteArrayInputStream(EntitySerializer.Default.serializeToBytes(encryptedPart));
- encryptedEntity = new MimeEntity(inStream);
-
+ byte[] encBytes = EntitySerializer.Default.serializeToBytes(encryptedPart);
+ ByteArrayInputStream inStream = new ByteArrayInputStream(EntitySerializer.Default.serializeToBytes(encryptedPart));
+ encryptedEntity = new MimeEntity(inStream);
+
if (log.isDebugEnabled())
- {
- writePostEncypt(encBytes);
- }
+ {
+ writePostEncypt(encBytes);
+ }
encryptedEntity.setHeader(MimeStandard.ContentTypeHeader, SMIMEStandard.EncryptedContentTypeHeaderValue);
-
+
}
catch (Exception e)
{
- throw new MimeException(MimeError.Unexpected, e);
+ throw new MimeException(MimeError.Unexpected, e);
}
return encryptedEntity;
@@ -378,48 +484,96 @@ private MimeBodyPart encrypt(MimeBodyPart bodyPart, Collection
{
return this.createEncryptedEnvelope(bodyPart, encryptingCertificates);
}
-
+
private MimeBodyPart createEncryptedEnvelope(MimeBodyPart bodyPart, Collection encryptingCertificates)
{
if (bodyPart == null || encryptingCertificates == null || encryptingCertificates.size() == 0)
{
throw new IllegalArgumentException();
}
-
+
if (log.isDebugEnabled())
- {
- writePreEncypt(EntitySerializer.Default.serializeToBytes(bodyPart));
- }
-
+ {
+ writePreEncypt(EntitySerializer.Default.serializeToBytes(bodyPart));
+ }
+
final SMIMEEnvelopedGenerator gen = new SMIMEEnvelopedGenerator();
-
+ if (!this.isAllowedKeyEncryptionAlgorithm(m_keyEncryptionAlgorithm.getOID()))
+ throw new NHINDException(MimeError.DisallowedEncryptionAlgorithm, "The key encryption algorithm " + m_keyEncryptionAlgorithm.algName + "("+ m_keyEncryptionAlgorithm.getOID()
+ + ") is not allowed");
+ /* m_keyEncryptionDigestAlgorithm could be null if using RSA_PKCS1_V15 */
+ if (m_keyEncryptionDigestAlgorithm != null && !this.isAllowedKeyEncryptionDigestAlgorithm(m_keyEncryptionDigestAlgorithm.getOID()))
+ throw new NHINDException(MimeError.DisallowedEncryptionAlgorithm, "The key encryption algorithm " + m_keyEncryptionDigestAlgorithm.algName + "("+ m_keyEncryptionDigestAlgorithm.getOID()
+ + ") is not allowed");
+
MimeBodyPart retVal = null;
-
+
try
{
for(X509Certificate cert : encryptingCertificates)
{
- // ensure the certificates key is allowed
- if (isAllowedCertKey(cert))
- gen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(cert).setProvider(CryptoExtensions.getJCEProviderName()));
+ // ensure the certificates key is allowed
+ if (isAllowedCertKey(cert)) {
+ if (log.isDebugEnabled()) {
+ log.debug("Encrypting: Encryption algorithm is " + this.m_encryptionAlgorithm.algName + "(" + m_encryptionAlgorithm.getOID().toString() + ")");
+ log.debug("Encrypting: Key encryption algorithm is " + this.m_keyEncryptionAlgorithm.algName + "(" + this.m_keyEncryptionAlgorithm.getOID().toString() + ")");
+ }
+ JcaAlgorithmParametersConverter paramsConverter = new JcaAlgorithmParametersConverter();
+ if( m_keyEncryptionAlgorithm == EncryptionAlgorithm.RSA_OAEP) {
+ OAEPParameterSpec oaepSpec = null;
+ if( m_keyEncryptionDigestAlgorithm == DigestAlgorithm.SHA256){
+ oaepSpec = new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT);
+ }
+ if( m_keyEncryptionDigestAlgorithm == DigestAlgorithm.SHA384){
+ oaepSpec = new OAEPParameterSpec("SHA-384", "MGF1", MGF1ParameterSpec.SHA384, PSource.PSpecified.DEFAULT);
+ }
+ if( m_keyEncryptionDigestAlgorithm == DigestAlgorithm.SHA512){
+ oaepSpec = new OAEPParameterSpec("SHA-512", "MGF1", MGF1ParameterSpec.SHA512, PSource.PSpecified.DEFAULT);
+ }
+ if( m_keyEncryptionDigestAlgorithm == DigestAlgorithm.SHA1){
+ oaepSpec = new OAEPParameterSpec("SHA-1", "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT);
+ }
+
+ AlgorithmIdentifier algorithmIdentifier = paramsConverter.getAlgorithmIdentifier(PKCSObjectIdentifiers.id_RSAES_OAEP, oaepSpec);
+ if (log.isDebugEnabled()) {
+ ASN1Encodable asn1Encodable = algorithmIdentifier.getParameters();
+ RSAESOAEPparams rsaesoaePparams = (RSAESOAEPparams)asn1Encodable;
+ log.debug("Encrypting: Key encryption algorithm parameters: Hash Algorithm: " + rsaesoaePparams.getHashAlgorithm().getAlgorithm().getId() + " Mask Gen Algorithm: " + rsaesoaePparams.getMaskGenAlgorithm().getAlgorithm().getId() + " P Source Algorithm: " + rsaesoaePparams.getPSourceAlgorithm().getAlgorithm().getId());
+ }
+ // JceKeyTransRecipientInfoGenerator has at least 2 constructors
+ // with just a cert as the arg, the algorithm defaults to new JceAsymmetricKeyWrapper(recipientCert) for the AsymmetricKeyWrapper, which is RSA PKCS15
+ // you can also pass in the wrapper, RSA OAEP for example
+ JceKeyTransRecipientInfoGenerator jceKey = new JceKeyTransRecipientInfoGenerator(cert, algorithmIdentifier).setProvider(CryptoExtensions.getJCEProviderName());
+
+ // KeyEncryption set to RSA OAEP
+ gen.addRecipientInfoGenerator(jceKey);
+ }
+ if( m_keyEncryptionAlgorithm == EncryptionAlgorithm.RSA_PKCS1_V15) {
+ // Original version - KeyEncryption defaults to PKCS#1 v1.5 padding
+ gen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(cert).setProvider(CryptoExtensions.getJCEProviderName()));
+ }
+
+
+ }
}
-
- final ASN1ObjectIdentifier encryAlgOID = new ASN1ObjectIdentifier(this.m_encryptionAlgorithm.getOID());
- final OutputEncryptor encryptor = new JceCMSContentEncryptorBuilder(encryAlgOID).
- setProvider(CryptoExtensions.getJCEProviderNameForTypeAndAlgorithm("Cipher", this.m_encryptionAlgorithm.getOID())).build();
-
- retVal = gen.generate(bodyPart, encryptor);
-
-
- //encryAlgOID,
- //CryptoExtensions.getJCEProviderNameForTypeAndAlgorithm("Cipher", encryAlgOID));
+
+ final ASN1ObjectIdentifier encryAlgOID = new ASN1ObjectIdentifier(this.m_encryptionAlgorithm.getOID());
+ final OutputEncryptor encryptor = new JceCMSContentEncryptorBuilder(encryAlgOID).
+ setProvider(CryptoExtensions.getJCEProviderNameForTypeAndAlgorithm("Cipher", this.m_encryptionAlgorithm.getOID())).build();
+
+
+ retVal = gen.generate(bodyPart, encryptor);
+
+
+ //encryAlgOID,
+ //CryptoExtensions.getJCEProviderNameForTypeAndAlgorithm("Cipher", encryAlgOID));
}
catch (Exception e)
{
- throw new MimeException(MimeError.Unexpected, e);
+ throw new MimeException(MimeError.Unexpected, e);
}
-
+
return retVal;
}
@@ -434,50 +588,50 @@ private MimeBodyPart createEncryptedEnvelope(MimeBodyPart bodyPart, Collection certs = new ArrayList();
- certs.add(decryptingCertificate);
-
+
+ Collection certs = new ArrayList();
+ certs.add(decryptingCertificate);
+
MimeEntity retVal = this.decrypt(encryptedEntity, certs);
-
+
//
// And turn the decrypted bytes back into an entity
//
return retVal;
}
-
+
/**
* Decrypts an entity with the provided certificates' private key.
* @param encryptedEntity The entity that will be decrypted.
* @param decryptingCertificate The certificates whose private keys will be used to decrypt the message.
* @return A MimeEntity containing the decrypted part.
- */
+ */
public MimeEntity decrypt(MimeEntity encryptedEntity, Collection decryptingCertificates)
{
if (decryptingCertificates == null || decryptingCertificates.size() == 0)
@@ -487,62 +641,89 @@ public MimeEntity decrypt(MimeEntity encryptedEntity, Collection signingCertificates)
{
return this.sign(message.extractEntityForSignature(this.m_includeEpilogue), signingCertificates);
- }
-
+ }
+
/**
* Signs an entity with the provided certificate.
* @param message The entity that will be signed.
* @param signingCertificate The certificate used to sign the message.
- * @return A signed entity that consists of a multipart/signed entity containing the original entity and a message signature.
- */
- public SignedEntity sign(MimeEntity entity, X509Certificate signingCertificate)
+ * @return A signed entity that consists of a multipart/signed entity containing the original entity and a message signature.
+ */
+ public SignedEntity sign(MimeEntity entity, X509Certificate signingCertificate)
{
- Collection certs = new ArrayList();
- certs.add(signingCertificate);
-
+ Collection certs = new ArrayList();
+ certs.add(signingCertificate);
+
return this.sign(entity, certs);
}
-
+
/**
* Signs an entity with the provided certificates.
* @param message The entity that will be signed.
* @param signingCertificates The certificates used to sign the message.
- * @return A signed entity that consists of a multipart/signed entity containing the original entity and a message signature.
- */
+ * @return A signed entity that consists of a multipart/signed entity containing the original entity and a message signature.
+ */
public SignedEntity sign(MimeEntity entity, Collection signingCertificates)
{
if (entity == null)
@@ -616,124 +797,124 @@ public SignedEntity sign(MimeEntity entity, Collection signingC
}
byte[] messageBytes = EntitySerializer.Default.serializeToBytes(entity); // Serialize message out as ASCII encoded...
-
+
MimeMultipart mm = this.createSignatureEntity(messageBytes, signingCertificates);
SignedEntity retVal = null;
-
+
try
{
-
- retVal = new SignedEntity(new ContentType(mm.getContentType()), mm);
+
+ retVal = new SignedEntity(new ContentType(mm.getContentType()), mm);
}
catch (ParseException e)
{
- throw new MimeException(MimeError.InvalidHeader, e);
+ throw new MimeException(MimeError.InvalidHeader, e);
}
-
+
return retVal;
}
protected MimeMultipart createSignatureEntity(byte[] entity, Collection signingCertificates)
- {
- MimeMultipart retVal = null;
- try
- {
- final MimeBodyPart signedContent = new MimeBodyPart(new ByteArrayInputStream(entity));
-
- final ASN1EncodableVector signedAttrs = new ASN1EncodableVector();
- final SMIMECapabilityVector caps = new SMIMECapabilityVector();
-
- caps.addCapability(SMIMECapability.dES_EDE3_CBC);
- caps.addCapability(SMIMECapability.rC2_CBC, 128);
- caps.addCapability(SMIMECapability.dES_CBC);
- caps.addCapability(new ASN1ObjectIdentifier("1.2.840.113549.1.7.1"));
- caps.addCapability(x509CertificateObjectsIdent);
- signedAttrs.add(new SMIMECapabilitiesAttribute(caps));
-
- final List certList = new ArrayList();
- CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
- for (X509Certificate signer : signingCertificates)
- {
- if (signer instanceof X509CertificateEx && isAllowedCertKey(signer))
- {
- ContentSigner digestSigner = new JcaContentSignerBuilder(this.m_digestAlgorithm.getAlgName())
- .setProvider(CryptoExtensions.getJCESensitiveProviderName()).build(((X509CertificateEx) signer).getPrivateKey());
-
-
- gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder()
- .setProvider(CryptoExtensions.getJCEProviderName()).build())
- .build(digestSigner, signer));
-
- certList.add(signer);
- }
- }
-
- final JcaCertStore certs = new JcaCertStore(certList);
- gen.addCertificates(certs);
- final CMSProcessableByteArray content = new CMSProcessableByteArray(entity);
-
- final CMSSignedData signedData = gen.generate(content);
-
- final String header = "signed; protocol=\"application/pkcs7-signature\"; micalg=" +
- CryptoAlgorithmsHelper.toDigestAlgorithmMicalg(this.m_digestAlgorithm);
-
- final String encodedSig = StringUtils.toEncodedString(Base64.encodeBase64(signedData.getEncoded(), true), StandardCharsets.UTF_8);
-
- retVal = new MimeMultipart(header.toString());
-
- final MimeBodyPart sig = new MimeBodyPart(new InternetHeaders(), encodedSig.getBytes("ASCII"));
+ {
+ MimeMultipart retVal = null;
+ try
+ {
+ final MimeBodyPart signedContent = new MimeBodyPart(new ByteArrayInputStream(entity));
+
+ final ASN1EncodableVector signedAttrs = new ASN1EncodableVector();
+ final SMIMECapabilityVector caps = new SMIMECapabilityVector();
+
+ caps.addCapability(SMIMECapability.dES_EDE3_CBC);
+ caps.addCapability(SMIMECapability.rC2_CBC, 128);
+ caps.addCapability(SMIMECapability.dES_CBC);
+ caps.addCapability(new ASN1ObjectIdentifier("1.2.840.113549.1.7.1"));
+ caps.addCapability(x509CertificateObjectsIdent);
+ signedAttrs.add(new SMIMECapabilitiesAttribute(caps));
+
+ final List certList = new ArrayList();
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+ for (X509Certificate signer : signingCertificates)
+ {
+ if (signer instanceof X509CertificateEx && isAllowedCertKey(signer))
+ {
+ ContentSigner digestSigner = new JcaContentSignerBuilder(this.m_digestAlgorithm.getAlgName())
+ .setProvider(CryptoExtensions.getJCESensitiveProviderName()).build(((X509CertificateEx) signer).getPrivateKey());
+
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder()
+ .setProvider(CryptoExtensions.getJCEProviderName()).build())
+ .build(digestSigner, signer));
+
+ certList.add(signer);
+ }
+ }
+
+ final JcaCertStore certs = new JcaCertStore(certList);
+ gen.addCertificates(certs);
+ final CMSProcessableByteArray content = new CMSProcessableByteArray(entity);
+
+ final CMSSignedData signedData = gen.generate(content);
+
+ final String header = "signed; protocol=\"application/pkcs7-signature\"; micalg=" +
+ CryptoAlgorithmsHelper.toDigestAlgorithmMicalg(this.m_digestAlgorithm);
+
+ final String encodedSig = StringUtils.toEncodedString(Base64.encodeBase64(signedData.getEncoded(), true), StandardCharsets.UTF_8);
+
+ retVal = new MimeMultipart(header.toString());
+
+ final MimeBodyPart sig = new MimeBodyPart(new InternetHeaders(), encodedSig.getBytes("ASCII"));
sig.addHeader("Content-Type", "application/pkcs7-signature; name=smime.p7s; smime-type=signed-data");
sig.addHeader("Content-Disposition", "attachment; filename=\"smime.p7s\"");
sig.addHeader("Content-Description", "S/MIME Cryptographic Signature");
sig.addHeader("Content-Transfer-Encoding", "base64");
-
+
retVal.addBodyPart(signedContent);
retVal.addBodyPart(sig);
- }
- catch (MessagingException e)
- {
- throw new MimeException(MimeError.InvalidMimeEntity, e);
- }
- catch (IOException e)
- {
- throw new SignatureException(SignatureError.InvalidMultipartSigned, e);
- }
- catch (Exception e)
- {
- throw new NHINDException(MimeError.Unexpected, e);
- }
- return retVal;
-
+ }
+ catch (MessagingException e)
+ {
+ throw new MimeException(MimeError.InvalidMimeEntity, e);
+ }
+ catch (IOException e)
+ {
+ throw new SignatureException(SignatureError.InvalidMultipartSigned, e);
+ }
+ catch (Exception e)
+ {
+ throw new NHINDException(MimeError.Unexpected, e);
+ }
+ return retVal;
+
}
-
+
/*
* Construct an attribute table. Added private function to support multiple versions of BC libraries.
*/
public static AttributeTable createAttributeTable(ASN1EncodableVector signedAttrs)
{
- // Support for BC 146.... has a different constructor signature from 140
-
- AttributeTable retVal = null;
-
-
- if (retVal == null)
- {
- try
- {
- /*
- * 146 version
- */
- Constructor constr = AttributeTable.class.getConstructor(ASN1EncodableVector.class);
- retVal = constr.newInstance(signedAttrs);
- }
- catch (Throwable t)
- {
- log.error("Attempt to use to bcmail-jdk15-146 DERObjectIdentifier(ASN1EncodableVector constructor failed.", t);
- }
- }
-
- return retVal;
+ // Support for BC 146.... has a different constructor signature from 140
+
+ AttributeTable retVal = null;
+
+
+ if (retVal == null)
+ {
+ try
+ {
+ /*
+ * 146 version
+ */
+ Constructor constr = AttributeTable.class.getConstructor(ASN1EncodableVector.class);
+ retVal = constr.newInstance(signedAttrs);
+ }
+ catch (Throwable t)
+ {
+ log.error("Attempt to use to bcmail-jdk15-146 DERObjectIdentifier(ASN1EncodableVector constructor failed.", t);
+ }
+ }
+
+ return retVal;
}
//-----------------------------------------------------
@@ -750,52 +931,52 @@ public static AttributeTable createAttributeTable(ASN1EncodableVector signedAttr
*/
public void checkSignature(SignedEntity signedEntity, X509Certificate signerCertificate, Collection anchors) throws SignatureValidationException
{
- if (!isAllowedCertKey(signerCertificate))
- throw new SignatureValidationException("Signing certificate key size/strength is not allowed");
-
- CMSSignedData signatureEnvelope = deserializeSignatureEnvelope(signedEntity);
-
+ if (!isAllowedCertKey(signerCertificate))
+ throw new SignatureValidationException("Signing certificate key size/strength is not allowed");
+
+ CMSSignedData signatureEnvelope = deserializeSignatureEnvelope(signedEntity);
+
SignerInformation logSigInfo = null;
- try
- {
- // there may be multiple signatures in the signed part... iterate through all the signing certificates until one
- // is verified with the signerCertificate
- for (SignerInformation sigInfo : (Collection)signatureEnvelope.getSignerInfos().getSigners())
- {
- logSigInfo = sigInfo;
- // make sure the sender did not send the message with an explicitly disallowed digest algorithm
- // such as MD5
-
- if (!isAllowedDigestAlgorithm(sigInfo.getDigestAlgOID()))
- throw new SignatureValidationException("Digest algorithm " + sigInfo.getDigestAlgOID() + " is not allowed.");
-
- if (sigInfo.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(CryptoExtensions.getJCEProviderName()).build(signerCertificate)))
- {
-
- return; // verified... return
- }
-
- }
- // at this point the signerCertificate cannot be verified with one of the signing certificates....
- throw new SignatureValidationException("Signature validation failure.");
- }
- catch (SignatureValidationException sve)
- {
- throw sve;
- }
- catch (Exception e)
- {
- throw new SignatureValidationException("Signature validation failure.", e);
- }
- finally
- {
- logDigests(logSigInfo);
- }
- }
-
+ try
+ {
+ // there may be multiple signatures in the signed part... iterate through all the signing certificates until one
+ // is verified with the signerCertificate
+ for (SignerInformation sigInfo : (Collection)signatureEnvelope.getSignerInfos().getSigners())
+ {
+ logSigInfo = sigInfo;
+ // make sure the sender did not send the message with an explicitly disallowed digest algorithm
+ // such as MD5
+
+ if (!isAllowedDigestAlgorithm(sigInfo.getDigestAlgOID()))
+ throw new SignatureValidationException("Digest algorithm " + sigInfo.getDigestAlgOID() + " is not allowed.");
+
+ if (sigInfo.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(CryptoExtensions.getJCEProviderName()).build(signerCertificate)))
+ {
+
+ return; // verified... return
+ }
+
+ }
+ // at this point the signerCertificate cannot be verified with one of the signing certificates....
+ throw new SignatureValidationException("Signature validation failure.");
+ }
+ catch (SignatureValidationException sve)
+ {
+ throw sve;
+ }
+ catch (Exception e)
+ {
+ throw new SignatureValidationException("Signature validation failure.", e);
+ }
+ finally
+ {
+ logDigests(logSigInfo);
+ }
+ }
+
/**
* Determines if a specific digest algorithm is allowed by policy and in conformance with the applicability statement.
- * This check can be turned off with the ENFORCE_STRONG_DIGESTS options parameter.
+ * This check can be turned off with the ENFORCE_STRONG_DIGESTS options parameter.
* As of ANSI/DS 2019-01-100-2021 approved on May 13, 2021, certain digests are explicitly disallowed.
* The ENFORCE_STRONG_DIGESTS options parameter is only relevant of optional or digests listed as SHOULD NOT
* be used. This parameter DOES NOT apply to explicitly disallowed algorithms.
@@ -804,16 +985,16 @@ public void checkSignature(SignedEntity signedEntity, X509Certificate signerCert
protected boolean isAllowedDigestAlgorithm(String digestOID)
{
- /*
- * Dis-allow MD5 explicitly and SHA1
- * may include other algorithms in further implementations
- */
- return (digestOID.equalsIgnoreCase(DigestAlgorithm.MD5.getOID()) || digestOID.equalsIgnoreCase(DigestAlgorithm.SHA1.getOID()) ||
- digestOID.equalsIgnoreCase(DigestAlgorithm.SHA1WITHRSA.getOID())) ? false: true;
-
+ /*
+ * Dis-allow MD5 explicitly and SHA1
+ * may include other algorithms in further implementations
+ */
+ return (digestOID.equalsIgnoreCase(DigestAlgorithm.MD5.getOID()) || digestOID.equalsIgnoreCase(DigestAlgorithm.SHA1.getOID()) ||
+ digestOID.equalsIgnoreCase(DigestAlgorithm.SHA1WITHRSA.getOID())) ? false: true;
+
}
-
+
/**
* Determines if a specific encryption algorithm is allowed by policy and in conformance with the applicability statement.
* This check can be turned off with the ENFORCE_STRONG_ENCRYPTION options parameter.
@@ -821,16 +1002,54 @@ protected boolean isAllowedDigestAlgorithm(String digestOID)
*/
protected boolean isAllowedEncryptionAlgorithm(String encryptionOID)
{
- if (!this.isStrongEncryptionEnforced())
- return true;
-
- /*
- * Dis-allow those algorithms explicitly outlined as SHOULD- if section 2.7 of RFC5751
- * may include other algorithms in further implementations
- */
- return encryptionOID.equalsIgnoreCase(EncryptionAlgorithm.DES_EDE3_CBC.getOID()) ? false : true;
+ if (!this.isStrongEncryptionEnforced())
+ return true;
+
+ /*
+ * Dis-allow those algorithms explicitly outlined as SHOULD- if section 2.7 of RFC5751
+ * may include other algorithms in further implementations
+ */
+ return encryptionOID.equalsIgnoreCase(EncryptionAlgorithm.DES_EDE3_CBC.getOID()) ? false : true;
+ }
+ /**
+ * Determines if a specific key encryption algorithm is allowed by policy and in conformance with the applicability statement.
+ * This check can be turned off with the ENFORCE_STRONG_ENCRYPTION options parameter.
+ * @return
+ */
+ protected boolean isAllowedKeyEncryptionAlgorithm(String encryptionOID)
+ {
+ if (!this.isStrongEncryptionEnforced())
+ return true;
+
+ /*
+ * Dis-allow those algorithms explicitly deprecated as of NIST 800-56B
+ * may include other algorithms in further implementations
+ */
+ /* Allow RSA_PKCS1_V15 for now */
+ //return encryptionOID.equalsIgnoreCase(EncryptionAlgorithm.RSA_PKCS1_V15.getOID()) ? false : true;
+ return true;
}
-
+
+ /**
+ * Determines if a specific key encryption digest algorithm is allowed by policy and in conformance with the applicability statement.
+ * This check can be turned off with the ENFORCE_STRONG_ENCRYPTION options parameter.
+ * @return
+ */
+ protected boolean isAllowedKeyEncryptionDigestAlgorithm(String digestOID)
+ {
+ if (!this.isStrongEncryptionEnforced())
+ return true;
+
+ /*
+ * Dis-allow those algorithms explicitly deprecated as of NIST 800-56B
+ * may include other algorithms in further implementations
+ */
+ return true;
+ // allow SHA1 for now
+ //return digestOID.equalsIgnoreCase(DigestAlgorithm.SHA1.getOID()) ? false : true;
+ }
+
+
/**
* Determines if a certificate has a key of acceptable size/strength.
* RSA keys MUST be at 2048 bits in length.
@@ -839,43 +1058,43 @@ protected boolean isAllowedEncryptionAlgorithm(String encryptionOID)
*/
protected boolean isAllowedCertKey(X509Certificate cert)
{
- // Check if it's an RSA key
- if (cert.getPublicKey().getAlgorithm().contains("RSA"))
- {
- final RSAPublicKey rsaPk = (RSAPublicKey) cert.getPublicKey();
- return rsaPk.getModulus().bitLength() >= 2048;
- }
-
- return true;
+ // Check if it's an RSA key
+ if (cert.getPublicKey().getAlgorithm().contains("RSA"))
+ {
+ final RSAPublicKey rsaPk = (RSAPublicKey) cert.getPublicKey();
+ return rsaPk.getModulus().bitLength() >= 2048;
+ }
+
+ return true;
}
-
- protected void logDigests(SignerInformation sigInfo)
+
+ protected void logDigests(SignerInformation sigInfo)
{
- // it is assumed that the verify function has already been called, other wise the getContentDigest function
- // will fail
- if (this.m_logDigest && sigInfo != null)
- {
- try
- {
- //get the digests
- final Attribute digAttr = sigInfo.getSignedAttributes().get(CMSAttributes.messageDigest);
- final ASN1Encodable hashObj = digAttr.getAttrValues().getObjectAt(0);
- final byte[] signedDigest = ((ASN1OctetString)hashObj).getOctets();
- final String signedDigestHex = org.apache.commons.codec.binary.Hex.encodeHexString(signedDigest);
-
- log.info("Signed Message Digest: {}", signedDigestHex);
-
- // should have the computed digest now
- final byte[] digest = sigInfo.getContentDigest();
- final String digestHex = org.apache.commons.codec.binary.Hex.encodeHexString(digest);
- log.info("Computed Message Digest: {}", digestHex);
- }
- catch (Throwable t)
- { /* no-op.... logging digests is a quiet operation */}
- }
+ // it is assumed that the verify function has already been called, other wise the getContentDigest function
+ // will fail
+ if (this.m_logDigest && sigInfo != null)
+ {
+ try
+ {
+ //get the digests
+ final Attribute digAttr = sigInfo.getSignedAttributes().get(CMSAttributes.messageDigest);
+ final ASN1Encodable hashObj = digAttr.getAttrValues().getObjectAt(0);
+ final byte[] signedDigest = ((ASN1OctetString)hashObj).getOctets();
+ final String signedDigestHex = org.apache.commons.codec.binary.Hex.encodeHexString(signedDigest);
+
+ log.info("Signed Message Digest: {}", signedDigestHex);
+
+ // should have the computed digest now
+ final byte[] digest = sigInfo.getContentDigest();
+ final String digestHex = org.apache.commons.codec.binary.Hex.encodeHexString(digest);
+ log.info("Computed Message Digest: {}", digestHex);
+ }
+ catch (Throwable t)
+ { /* no-op.... logging digests is a quiet operation */}
+ }
}
-
-
+
+
/**
* Extracts the ASN1 encoded signature data from the signed entity.
* @param entity The entity containing the original signed part and the message signature.
@@ -884,35 +1103,35 @@ protected void logDigests(SignerInformation sigInfo)
public CMSSignedData deserializeSignatureEnvelope(SignedEntity entity)
{
-
- if (entity == null)
+
+ if (entity == null)
{
throw new NHINDException();
}
- CMSSignedData signed = null;
-
- try
- {
- //signed = new SMIMESigned(entity.getMimeMultipart());
- byte[] messageBytes = EntitySerializer.Default.serializeToBytes(entity.getContent());
+ CMSSignedData signed = null;
+
+ try
+ {
+ //signed = new SMIMESigned(entity.getMimeMultipart());
+ byte[] messageBytes = EntitySerializer.Default.serializeToBytes(entity.getContent());
MimeBodyPart signedContent = null;
-
- signedContent = new MimeBodyPart(new ByteArrayInputStream(messageBytes));
-
- signed = new CMSSignedData(new CMSProcessableBodyPart(signedContent), entity.getMimeMultipart().getBodyPart(1).getInputStream());
-
- }
- catch (Exception e)
- {
- e.printStackTrace();
- throw new MimeException(MimeError.Unexpected, e);
- }
-
- return signed;
+
+ signedContent = new MimeBodyPart(new ByteArrayInputStream(messageBytes));
+
+ signed = new CMSSignedData(new CMSProcessableBodyPart(signedContent), entity.getMimeMultipart().getBodyPart(1).getInputStream());
+
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ throw new MimeException(MimeError.Unexpected, e);
+ }
+
+ return signed;
}
-
+
public CMSSignedData deserializeEnvelopedSignature(MimeEntity envelopeEntity)
{
if (envelopeEntity == null)
@@ -932,165 +1151,171 @@ public CMSSignedData deserializeEnvelopedSignature(MimeEntity envelopeEntity)
public CMSSignedData deserializeEnvelopedSignature(byte[] messageBytes)
{
- CMSSignedData signed = null;
-
- try
- {
- signed = new CMSSignedData(messageBytes);
- }
- catch (Exception e)
- {
- e.printStackTrace();
- throw new MimeException(MimeError.Unexpected, e);
- }
-
- return signed;
- }
-
-
+ CMSSignedData signed = null;
+
+ try
+ {
+ signed = new CMSSignedData(messageBytes);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ throw new MimeException(MimeError.Unexpected, e);
+ }
+
+ return signed;
+ }
+
+
@SuppressWarnings("deprecation")
- private void writePreEncypt(byte message[])
+ private void writePreEncypt(byte message[])
{
- String path = System.getProperty("user.dir") + "/tmp";
- File tmpDir = new File(path);
-
- if (!tmpDir.exists())
- {
- if (!tmpDir.mkdir())
- return;
- }
-
- System.currentTimeMillis();
-
- File outFile = new File(path + "/preEncypt_" + System.currentTimeMillis() + ".eml");
-
-
- try
- {
- if (!outFile.exists())
- {
- if (!outFile.createNewFile())
- return;
- }
- BufferedOutputStream oStream = new BufferedOutputStream(new FileOutputStream(outFile));
-
- oStream.write(message, 0, message.length);
- oStream.flush();
- IOUtils.closeQuietly(oStream);
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
+ String path = System.getProperty("user.dir") + "/tmp";
+ File tmpDir = new File(path);
+
+ if (!tmpDir.exists())
+ {
+ if (!tmpDir.mkdir())
+ return;
+ }
+
+ System.currentTimeMillis();
+
+ File outFile = new File(path + "/preEncypt_" + System.currentTimeMillis() + ".eml");
+
+
+ try
+ {
+ if (!outFile.exists())
+ {
+ if (!outFile.createNewFile())
+ return;
+ }
+ BufferedOutputStream oStream = new BufferedOutputStream(new FileOutputStream(outFile));
+
+ oStream.write(message, 0, message.length);
+ oStream.flush();
+ IOUtils.closeQuietly(oStream);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
}
-
+
@SuppressWarnings("deprecation")
- private void writePostEncypt(byte message[])
+ private void writePostEncypt(byte message[])
{
- String path = System.getProperty("user.dir") + "/tmp";
- File tmpDir = new File(path);
-
- if (!tmpDir.exists())
- {
- if (!tmpDir.mkdir())
- return;
- }
-
- System.currentTimeMillis();
-
- File outFile = new File(path + "/postEncypt_" + System.currentTimeMillis() + ".eml");
-
-
- try
- {
- if (!outFile.exists())
- {
- if (!outFile.createNewFile())
- return;
- }
- BufferedOutputStream oStream = new BufferedOutputStream(new FileOutputStream(outFile));
-
- oStream.write(message, 0, message.length);
- oStream.flush();
- IOUtils.closeQuietly(oStream);
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
+ String path = System.getProperty("user.dir") + "/tmp";
+ File tmpDir = new File(path);
+
+ if (!tmpDir.exists())
+ {
+ if (!tmpDir.mkdir())
+ return;
+ }
+
+ System.currentTimeMillis();
+
+ File outFile = new File(path + "/postEncypt_" + System.currentTimeMillis() + ".eml");
+
+
+ try
+ {
+ if (!outFile.exists())
+ {
+ if (!outFile.createNewFile())
+ return;
+ }
+ BufferedOutputStream oStream = new BufferedOutputStream(new FileOutputStream(outFile));
+
+ oStream.write(message, 0, message.length);
+ oStream.flush();
+ IOUtils.closeQuietly(oStream);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
}
-
-
+
+
@SuppressWarnings("deprecation")
- private void writePreDecrypt(byte message[])
+ private void writePreDecrypt(byte message[])
{
- String path = System.getProperty("user.dir") + "/tmp";
- File tmpDir = new File(path);
-
- if (!tmpDir.exists())
- {
- if (!tmpDir.mkdir())
- return;
- }
-
- System.currentTimeMillis();
-
- File outFile = new File(path + "/preDecrypt_" + System.currentTimeMillis() + ".eml");
-
-
- try
- {
- if (!outFile.exists())
- {
- if (!outFile.createNewFile())
- return;
- }
- BufferedOutputStream oStream = new BufferedOutputStream(new FileOutputStream(outFile));
-
- oStream.write(message, 0, message.length);
- oStream.flush();
- IOUtils.closeQuietly(oStream);
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
+ String path = System.getProperty("user.dir") + "/tmp";
+ File tmpDir = new File(path);
+
+ if (!tmpDir.exists())
+ {
+ if (!tmpDir.mkdir())
+ return;
+ }
+
+ System.currentTimeMillis();
+
+ File outFile = new File(path + "/preDecrypt_" + System.currentTimeMillis() + ".eml");
+
+
+ try
+ {
+ if (!outFile.exists())
+ {
+ if (!outFile.createNewFile())
+ return;
+ }
+ BufferedOutputStream oStream = new BufferedOutputStream(new FileOutputStream(outFile));
+
+ oStream.write(message, 0, message.length);
+ oStream.flush();
+ IOUtils.closeQuietly(oStream);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
}
-
+
@SuppressWarnings("deprecation")
- private void writePostDecrypt(byte message[])
+ private void writePostDecrypt(byte message[])
{
- String path = System.getProperty("user.dir") + "/tmp";
- File tmpDir = new File(path);
-
- if (!tmpDir.exists())
- {
- if (!tmpDir.mkdir())
- return;
- }
-
- System.currentTimeMillis();
-
- File outFile = new File(path + "/postDecrypt_" + System.currentTimeMillis() + ".eml");
-
-
- try
- {
- if (!outFile.exists())
- {
- if (!outFile.createNewFile())
- return;
-
- }
- BufferedOutputStream oStream = new BufferedOutputStream(new FileOutputStream(outFile));
-
- oStream.write(message, 0, message.length);
- oStream.flush();
- IOUtils.closeQuietly(oStream);
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
+ String path = System.getProperty("user.dir") + "/tmp";
+ File tmpDir = new File(path);
+
+ if (!tmpDir.exists())
+ {
+ if (!tmpDir.mkdir())
+ return;
+ }
+
+ System.currentTimeMillis();
+
+ File outFile = new File(path + "/postDecrypt_" + System.currentTimeMillis() + ".eml");
+
+
+ try
+ {
+ if (!outFile.exists())
+ {
+ if (!outFile.createNewFile())
+ return;
+
+ }
+ BufferedOutputStream oStream = new BufferedOutputStream(new FileOutputStream(outFile));
+
+ oStream.write(message, 0, message.length);
+ oStream.flush();
+ IOUtils.closeQuietly(oStream);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ public static String getMaskFunctionGeneratorFromOID(String mfgOID){
+ if( mfgOID.equals(PKCSObjectIdentifiers.id_mgf1.getId()))
+ return "MGF1";
+
+ return "Unknown MFG: " + mfgOID;
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/org/nhindirect/stagent/cryptography/bc/DirectJceAsymmetricKeyUnwrapper.java b/src/main/java/org/nhindirect/stagent/cryptography/bc/DirectJceAsymmetricKeyUnwrapper.java
index 9a27fa7..bb1923a 100644
--- a/src/main/java/org/nhindirect/stagent/cryptography/bc/DirectJceAsymmetricKeyUnwrapper.java
+++ b/src/main/java/org/nhindirect/stagent/cryptography/bc/DirectJceAsymmetricKeyUnwrapper.java
@@ -2,6 +2,7 @@
import java.lang.reflect.Field;
import java.lang.reflect.Method;
+import java.security.AlgorithmParameters;
import java.security.Key;
import java.security.PrivateKey;
import java.util.HashMap;
@@ -11,7 +12,9 @@
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.operator.DefaultAlgorithmNameFinder;
import org.bouncycastle.operator.GenericKey;
import org.bouncycastle.operator.OperatorException;
import org.bouncycastle.operator.jcajce.JceAsymmetricKeyUnwrapper;
@@ -20,60 +23,69 @@
public class DirectJceAsymmetricKeyUnwrapper extends JceAsymmetricKeyUnwrapper
{
protected Map extraMappings = new HashMap<>();
- protected PrivateKey privateKey;
-
-
+ protected PrivateKey privateKey;
+
+
public DirectJceAsymmetricKeyUnwrapper(AlgorithmIdentifier algorithmIdentifier, PrivateKey privKey)
{
super(algorithmIdentifier, privKey);
this.privateKey = privKey;
}
-
+
@Override
public JceAsymmetricKeyUnwrapper setAlgorithmMapping(ASN1ObjectIdentifier algorithm, String algorithmName)
{
- super.setAlgorithmMapping(algorithm, algorithmName);
-
+ super.setAlgorithmMapping(algorithm, algorithmName);
+
extraMappings.put(algorithm, algorithmName);
return this;
}
-
+
@Override
public GenericKey generateUnwrappedKey(AlgorithmIdentifier encryptedKeyAlgorithm, byte[] encryptedKey)
throws OperatorException
+ {
+ try
{
- try
- {
- Key sKey = null;
+ Key sKey = null;
- Class> parentClass = Class.forName("org.bouncycastle.operator.jcajce.JceAsymmetricKeyUnwrapper");
- Field helpField = parentClass.getDeclaredField("helper");
- helpField.setAccessible(true);
-
- Class> helperClazz = Class.forName("org.bouncycastle.operator.jcajce.OperatorHelper");
+ Class> parentClass = Class.forName("org.bouncycastle.operator.jcajce.JceAsymmetricKeyUnwrapper");
+ Field helpField = parentClass.getDeclaredField("helper");
+ helpField.setAccessible(true);
- Method cipherMeth = helperClazz.getDeclaredMethod("createAsymmetricWrapper", ASN1ObjectIdentifier.class, Map.class);
- cipherMeth.setAccessible(true);
-
- Cipher keyCipher = (Cipher)cipherMeth.invoke(helpField.get(this), this.getAlgorithmIdentifier().getAlgorithm(), extraMappings);
+ Class> helperClazz = Class.forName("org.bouncycastle.operator.jcajce.OperatorHelper");
+ Method cipherMeth = helperClazz.getDeclaredMethod("createAsymmetricWrapper", ASN1ObjectIdentifier.class, Map.class);
+ cipherMeth.setAccessible(true);
- // some providers do not support UNWRAP (this appears to be only for asymmetric algorithms)
- if (sKey == null)
- {
- keyCipher.init(Cipher.DECRYPT_MODE, privateKey);
- sKey = new SecretKeySpec(keyCipher.doFinal(encryptedKey), encryptedKeyAlgorithm.getAlgorithm().getId());
- }
+ Cipher keyCipher = (Cipher)cipherMeth.invoke(helpField.get(this), this.getAlgorithmIdentifier().getAlgorithm(), extraMappings);
- return new JceGenericKey(encryptedKeyAlgorithm, sKey);
- }
- catch (Exception e)
+
+ // some providers do not support UNWRAP (this appears to be only for asymmetric algorithms)
+ if (sKey == null)
{
- throw new OperatorException("Decrypt failed: " + e.getMessage(), e);
+
+ if( this.getAlgorithmIdentifier().getAlgorithm().getId().equals(PKCSObjectIdentifiers.id_RSAES_OAEP.toString())) {
+ // Get the SHA Digest from the algorithm identifier
+ AlgorithmParameters algorithmParameters = AlgorithmParameters.getInstance(this.getAlgorithmIdentifier().getAlgorithm().toString());
+ algorithmParameters.init(this.getAlgorithmIdentifier().getParameters().toASN1Primitive().getEncoded());
+ keyCipher.init(Cipher.DECRYPT_MODE, privateKey, algorithmParameters);
+ } else {
+ keyCipher.init(Cipher.DECRYPT_MODE, privateKey);
+ }
+ byte[] var1 = keyCipher.doFinal(encryptedKey); // emm
+ sKey = new SecretKeySpec(keyCipher.doFinal(encryptedKey), encryptedKeyAlgorithm.getAlgorithm().getId());
}
- }
-
+ return new JceGenericKey(encryptedKeyAlgorithm, sKey);
+ }
+ catch (Exception e)
+ {
+ throw new OperatorException("Decrypt failed: " + e.getMessage(), e);
+ }
+
+ }
+
-}
+}
\ No newline at end of file
diff --git a/src/test/java/org/nhindirect/stagent/cryptography/CryptographerTest.java b/src/test/java/org/nhindirect/stagent/cryptography/CryptographerTest.java
index 899db5a..0b1ba50 100644
--- a/src/test/java/org/nhindirect/stagent/cryptography/CryptographerTest.java
+++ b/src/test/java/org/nhindirect/stagent/cryptography/CryptographerTest.java
@@ -1,3 +1,4 @@
+
package org.nhindirect.stagent.cryptography;
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -6,6 +7,7 @@
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.io.ByteArrayOutputStream;
@@ -46,65 +48,65 @@
import org.nhindirect.stagent.utils.TestUtils;
public class CryptographerTest
-{
+{
@BeforeEach
public void setUp()
{
- CryptoExtensions.registerJCEProviders();
+ CryptoExtensions.registerJCEProviders();
}
-
+
@Test
public void testEncryptAndDecryptMimeEntityAES128() throws Exception
{
testEncryptAndDecryptMimeEntity(EncryptionAlgorithm.AES128, true, false);
}
-
+
@Test
public void testEncryptAndDecryptMimeEntityAES256() throws Exception
{
testEncryptAndDecryptMimeEntity(EncryptionAlgorithm.AES256, true, false);
- }
-
+ }
+
@Test
public void testEncryptAndDecryptMimeEntityRSA_3DES() throws Exception
{
testEncryptAndDecryptMimeEntity(EncryptionAlgorithm.RSA_3DES, false, false);
- }
-
+ }
+
@Test
public void testEncryptAndDecryptMimeEntityAES192() throws Exception
{
testEncryptAndDecryptMimeEntity(EncryptionAlgorithm.AES192, true, false);
- }
+ }
@Test
public void testEncryptAndDecryptMimeEntityRSA_3DES_enforceStrongEncr_assertException() throws Exception
{
testEncryptAndDecryptMimeEntity(EncryptionAlgorithm.RSA_3DES, true, true);
- }
-
+ }
+
@Test
public void testEncryptAndDecryptMimeEntityDefaultAlg() throws Exception
{
testEncryptAndDecryptMimeEntity(null, true, false);
- }
-
+ }
+
private void testEncryptAndDecryptMimeEntity(EncryptionAlgorithm encAlg, boolean enforceStrongEncryption, boolean expectDecException) throws Exception
{
X509Certificate cert = TestUtils.getExternalCert("user1");
-
+
SMIMECryptographerImpl cryptographer = new SMIMECryptographerImpl();
if (encAlg != null)
cryptographer.setEncryptionAlgorithm(encAlg);
cryptographer.setStrongEncryptionEnforced(enforceStrongEncryption);
-
-
+
+
MimeEntity entity = new MimeEntity();
entity.setText("Hello world.");
entity.setHeader(MimeStandard.ContentTypeHeader, "text/plain");
entity.setHeader(MimeStandard.ContentTransferEncodingHeader, "7bit");
-
-
+
+
MimeEntity encEntity = cryptographer.encrypt(entity, cert);
assertNotNull(encEntity);
/*
@@ -114,9 +116,9 @@ private void testEncryptAndDecryptMimeEntity(EncryptionAlgorithm encAlg, boolean
final ContentType type = new ContentType(encEntity.getContentType());
assertTrue(type.match(SMIMEStandard.CmsEnvelopeMediaType));
assertFalse(type.match(SMIMEStandard.CmsEnvelopeMediaTypeAlt));
-
+
X509CertificateEx certex = TestUtils.getInternalCert("user1");
-
+
if (expectDecException)
{
boolean exceptionOccured = false;
@@ -133,71 +135,71 @@ private void testEncryptAndDecryptMimeEntity(EncryptionAlgorithm encAlg, boolean
else
{
MimeEntity decryEntity = cryptographer.decrypt(encEntity, certex);
-
+
assertNotNull(decryEntity);
-
+
byte[] decryEntityBytes = EntitySerializer.Default.serializeToBytes(decryEntity);
byte[] entityBytes = EntitySerializer.Default.serializeToBytes(entity);
-
+
assertTrue(Arrays.equals(decryEntityBytes, entityBytes));
}
}
-
+
protected String pkcs11ProviderName;
-
+
@Test
public void testEncryptAndDecryptMimeEntity_hsmDecryption() throws Exception
{
pkcs11ProviderName = TestUtils.setupSafeNetToken();
if (!StringUtils.isEmpty(pkcs11ProviderName))
testEncryptAndDecryptMimeEntity_hsmDecryption(EncryptionAlgorithm.AES128);
- }
-
+ }
+
private void testEncryptAndDecryptMimeEntity_hsmDecryption(EncryptionAlgorithm encAlg) throws Exception
{
-
+
OptionsManager.destroyInstance();
-
+
CryptoExtensions.registerJCEProviders();
-
+
try
{
final PKCS11Credential cred = new BootstrappedPKCS11Credential("1Kingpuff");
final MutableKeyStoreProtectionManager mgr = new StaticPKCS11TokenKeyStoreProtectionManager(cred, "", "");
final CacheableKeyStoreManagerCertificateStore store = new CacheableKeyStoreManagerCertificateStore(mgr);
store.add(TestUtils.getInternalCert("user1"));
-
+
X509Certificate cert = TestUtils.getExternalCert("user1");
-
+
SMIMECryptographerImpl cryptographer = new SMIMECryptographerImpl();
-
+
cryptographer.setEncryptionAlgorithm(encAlg);
-
+
MimeEntity entity = new MimeEntity();
entity.setText("Hello world.");
entity.setHeader(MimeStandard.ContentTypeHeader, "text/plain");
entity.setHeader(MimeStandard.ContentTransferEncodingHeader, "7bit");
-
+
MimeEntity encEntity = cryptographer.encrypt(entity, cert);
-
+
assertNotNull(encEntity);
-
+
// open up the pkcs11 store and find the private key
KeyStore ks = KeyStore.getInstance("PKCS11");
- ks.load(null, "1Kingpuff".toCharArray());
-
+ ks.load(null, "1Kingpuff".toCharArray());
+
X509CertificateEx decryptCert = null;
-
+
final Enumeration aliases = ks.aliases();
while (aliases.hasMoreElements())
{
String alias = aliases.nextElement();
-
+
Certificate pkcs11Cert = ks.getCertificate(alias);
if (pkcs11Cert != null &&pkcs11Cert instanceof X509Certificate)
{
-
+
// check if there is private key
Key key = ks.getKey(alias, null);
if (key != null && key instanceof PrivateKey && CryptoExtensions.certSubjectContainsName((X509Certificate)pkcs11Cert, "user1@cerner.com"))
@@ -206,221 +208,221 @@ private void testEncryptAndDecryptMimeEntity_hsmDecryption(EncryptionAlgorithm e
break;
}
}
- }
-
+ }
+
MimeEntity decryEntity = cryptographer.decrypt(encEntity, decryptCert);
-
+
assertNotNull(decryEntity);
-
+
byte[] decryEntityBytes = EntitySerializer.Default.serializeToBytes(decryEntity);
byte[] entityBytes = EntitySerializer.Default.serializeToBytes(entity);
-
+
assertTrue(Arrays.equals(decryEntityBytes, entityBytes));
- }
+ }
finally
{
System.setProperty("org.nhindirect.stagent.cryptography.JCESensitiveProviderName", "");
System.setProperty("org.nhindirect.stagent.cryptography.JCESensitiveProviderClassNames", "");
-
+
OptionsManager.destroyInstance();
}
}
-
+
@Test
public void testEncryptAndDecryptMultipartEntityAES128() throws Exception
{
testEncryptAndDecryptMultipartEntity(EncryptionAlgorithm.AES128, true);
}
-
+
@Test
public void testEncryptAndDecryptMultipartEntityAES192() throws Exception
{
testEncryptAndDecryptMultipartEntity(EncryptionAlgorithm.AES192, true);
}
-
+
@Test
public void testEncryptAndDecryptMultipartEntityAES256() throws Exception
{
testEncryptAndDecryptMultipartEntity(EncryptionAlgorithm.AES256, true);
- }
-
+ }
+
@Test
public void testEncryptAndDecryptMultipartEntityRSA_3DES() throws Exception
{
testEncryptAndDecryptMultipartEntity(EncryptionAlgorithm.RSA_3DES, false);
}
-
+
private void testEncryptAndDecryptMultipartEntity(EncryptionAlgorithm encAlgo, boolean enforceStrongEncryption) throws Exception
- {
+ {
X509Certificate cert = TestUtils.getExternalCert("user1");
-
+
SMIMECryptographerImpl cryptographer = new SMIMECryptographerImpl();
cryptographer.setEncryptionAlgorithm(encAlgo);
cryptographer.setStrongEncryptionEnforced(enforceStrongEncryption);
-
+
MimeEntity entityText = new MimeEntity();
entityText.setText("Hello world.");
entityText.setHeader(MimeStandard.ContentTypeHeader, "text/plain");
entityText.setHeader(MimeStandard.ContentTransferEncodingHeader, "7bit");
-
+
MimeEntity entityXML = new MimeEntity();
entityXML.setText("");
- entityXML.setHeader(MimeStandard.ContentTypeHeader, "text/xml");
-
+ entityXML.setHeader(MimeStandard.ContentTypeHeader, "text/xml");
+
MimeMultipart mpEntity = new MimeMultipart();
-
+
mpEntity.addBodyPart(entityText);
mpEntity.addBodyPart(entityXML);
-
+
MimeEntity encEntity = cryptographer.encrypt(mpEntity, cert);
-
+
assertNotNull(encEntity);
-
+
X509CertificateEx certex = TestUtils.getInternalCert("user1");
-
+
MimeEntity decryEntity = cryptographer.decrypt(encEntity, certex);
-
+
assertNotNull(decryEntity);
-
+
ByteArrayOutputStream oStream = new ByteArrayOutputStream();
mpEntity.writeTo(oStream);
InternetHeaders hdrs = new InternetHeaders();
hdrs.addHeader(MimeStandard.ContentTypeHeader, mpEntity.getContentType());
MimeEntity orgEntity = new MimeEntity(hdrs, oStream.toByteArray());
-
+
byte[] decryEntityBytes = EntitySerializer.Default.serializeToBytes(decryEntity);
byte[] entityBytes = EntitySerializer.Default.serializeToBytes(orgEntity);
System.out.println("Original:\r\n" + new String(entityBytes));
- System.out.println("\r\n\r\n\r\nNew:\r\n" + new String(decryEntityBytes));
-
-
- assertTrue(Arrays.equals(decryEntityBytes, entityBytes));
-
-
- }
-
+ System.out.println("\r\n\r\n\r\nNew:\r\n" + new String(decryEntityBytes));
+
+
+ assertTrue(Arrays.equals(decryEntityBytes, entityBytes));
+
+
+ }
+
@Test
public void testSignMimeEntitySHA256() throws Exception
{
testSignMimeEntity(DigestAlgorithm.SHA256WITHRSA);
- }
-
+ }
+
@Test
public void testSignMimeEntitySHA384() throws Exception
{
testSignMimeEntity(DigestAlgorithm.SHA384WITHRSA);
- }
-
+ }
+
@Test
public void testSignMimeEntitySHA512() throws Exception
{
testSignMimeEntity(DigestAlgorithm.SHA512WITHRSA);
- }
-
+ }
+
private void testSignMimeEntity(DigestAlgorithm digAlg) throws Exception
- {
+ {
X509CertificateEx certex = TestUtils.getInternalCert("user1");
-
+
SMIMECryptographerImpl cryptographer = new SMIMECryptographerImpl();
cryptographer.setDigestAlgorithm(digAlg);
-
+
MimeEntity entity = new MimeEntity();
entity.setText("Hello world.");
entity.setHeader(MimeStandard.ContentTypeHeader, "text/plain");
entity.setHeader(MimeStandard.ContentTransferEncodingHeader, "7bit");
-
+
SignedEntity signedEnt = cryptographer.sign(entity, certex);
-
+
assertNotNull(signedEnt);
-
+
byte[] signedEntityBytes = EntitySerializer.Default.serializeToBytes(signedEnt.getContent());
- byte[] entityBytes = EntitySerializer.Default.serializeToBytes(entity);
-
+ byte[] entityBytes = EntitySerializer.Default.serializeToBytes(entity);
+
assertTrue(Arrays.equals(signedEntityBytes, entityBytes));
assertNotNull(signedEnt.getSignature());
-
+
X509Certificate cert = TestUtils.getExternalCert("user1");
-
-
+
+
cryptographer.checkSignature(signedEnt, cert, new ArrayList());
}
@Test
public void testSignMimeEntity_SHA1Digest_assertNotAllowedAlgorithm() throws Exception
- {
-
+ {
+
SMIMECryptographerImpl cryptographer = new SMIMECryptographerImpl();
Assertions.assertThrows(IllegalArgumentException.class, () ->{
cryptographer.setDigestAlgorithm(DigestAlgorithm.SHA1WITHRSA);
});
-
+
}
-
+
@Test
public void testSignMimeEntity_SHA256Digest_forceStrongDigest_assertValidation() throws Exception
- {
+ {
X509CertificateEx certex = TestUtils.getInternalCert("user1");
-
+
SMIMECryptographerImpl cryptographer = new SMIMECryptographerImpl();
cryptographer.setDigestAlgorithm(DigestAlgorithm.SHA256WITHRSA);
-
+
MimeEntity entity = new MimeEntity();
entity.setText("Hello world.");
entity.setHeader(MimeStandard.ContentTypeHeader, "text/plain");
entity.setHeader(MimeStandard.ContentTransferEncodingHeader, "7bit");
-
+
SignedEntity signedEnt = cryptographer.sign(entity, certex);
-
+
assertNotNull(signedEnt);
-
+
byte[] signedEntityBytes = EntitySerializer.Default.serializeToBytes(signedEnt.getContent());
- byte[] entityBytes = EntitySerializer.Default.serializeToBytes(entity);
-
+ byte[] entityBytes = EntitySerializer.Default.serializeToBytes(entity);
+
assertTrue(Arrays.equals(signedEntityBytes, entityBytes));
assertNotNull(signedEnt.getSignature());
-
+
X509Certificate cert = TestUtils.getExternalCert("user1");
-
+
cryptographer.checkSignature(signedEnt, cert, new ArrayList());
-
+
}
-
+
@Test
public void testSignMimeEntity_SHA1Digest_assertNotAllowedDigestAlgorithm() throws Exception
- {
+ {
SMIMECryptographerImpl cryptographer = new SMIMECryptographerImpl();
-
+
Assertions.assertThrows(IllegalArgumentException.class, () ->{
cryptographer.setDigestAlgorithm(DigestAlgorithm.SHA1WITHRSA);
});
-
-
+
+
}
-
+
@Test
public void testEncryptAndSignMimeEntity() throws Exception
- {
+ {
X509Certificate cert = TestUtils.getInternalCACert("user1");
-
+
SMIMECryptographerImpl cryptographer = new SMIMECryptographerImpl();
-
+
MimeEntity entity = new MimeEntity();
entity.setText("Hello world.");
entity.setHeader(MimeStandard.ContentTypeHeader, "text/plain");
entity.setHeader(MimeStandard.ContentTransferEncodingHeader, "7bit");
MimeEntity encEntity = cryptographer.encrypt(entity, cert);
-
+
assertNotNull(encEntity);
-
+
X509CertificateEx certex = TestUtils.getInternalCert("user1");
SignedEntity signedEnt = cryptographer.sign(entity, certex);
-
+
assertNotNull(signedEnt);
cryptographer.checkSignature(signedEnt, cert, new ArrayList());
@@ -431,21 +433,21 @@ public void testEncryptAndSignMimeEntity() throws Exception
public void testEncryptWithSingleCert_wrongDecryptCert_assertFailDecrypt() throws Exception
{
X509Certificate cert = TestUtils.getExternalCert("user1");
-
+
SMIMECryptographerImpl cryptographer = new SMIMECryptographerImpl();
-
+
MimeEntity entity = new MimeEntity();
entity.setText("Hello world.");
entity.setHeader(MimeStandard.ContentTypeHeader, "text/plain");
entity.setHeader(MimeStandard.ContentTransferEncodingHeader, "7bit");
-
-
+
+
MimeEntity encEntity = cryptographer.encrypt(entity, cert);
-
+
assertNotNull(encEntity);
-
+
X509CertificateEx certex = TestUtils.getInternalCert("altnameonly");
-
+
boolean exceptionOccured = false;
try
{
@@ -454,57 +456,200 @@ public void testEncryptWithSingleCert_wrongDecryptCert_assertFailDecrypt() throw
catch (NHINDException e)
{
if (e.getError().equals(MimeError.Unexpected));
- exceptionOccured = true;
+ exceptionOccured = true;
}
assertTrue(exceptionOccured);
}
-
+
@Test
public void testEncryptWithSingleCert_decryptWithMutlipeCerts_onlyOneCertCorrect_assertDecrypted() throws Exception
{
X509Certificate cert = TestUtils.getExternalCert("user1");
-
+
SMIMECryptographerImpl cryptographer = new SMIMECryptographerImpl();
-
+
MimeEntity entity = new MimeEntity();
entity.setText("Hello world.");
entity.setHeader(MimeStandard.ContentTypeHeader, "text/plain");
entity.setHeader(MimeStandard.ContentTransferEncodingHeader, "7bit");
-
-
+
+
MimeEntity encEntity = cryptographer.encrypt(entity, cert);
-
+
assertNotNull(encEntity);
-
+
X509CertificateEx certex1 = TestUtils.getInternalCert("altnameonly");
X509CertificateEx certex2 = TestUtils.getInternalCert("user1");
MimeEntity decryEntity = cryptographer.decrypt(encEntity, Arrays.asList(certex1, certex2));
assertNotNull(decryEntity);
-
+
byte[] decryEntityBytes = EntitySerializer.Default.serializeToBytes(decryEntity);
byte[] entityBytes = EntitySerializer.Default.serializeToBytes(entity);
-
+
assertTrue(Arrays.equals(decryEntityBytes, entityBytes));
- }
-
+ }
+
@SuppressWarnings("deprecation")
public void testvalidateSignature() throws Exception
{
final String str = FileUtils.readFileToString(new File("./src/test/resources/org/nhindirect/stagent/msgSig.txt"));
-
+
byte[] byteData = Base64.decode(str);
+
+
+ CMSSignedData signed = new CMSSignedData(byteData);
+
+ Store certs = signed.getCertificates();
+
+
+ for (X509CertificateHolder cert : certs.getMatches(null))
+ {
+ FileUtils.writeByteArrayToFile(new File("./testCert.der"), cert.getEncoded());
+ }
+ }
+
+ @Test
+ public void testEncryptAndDecryptKeyEncryptionMimeEntityDefaultAlg() throws Exception
+ {
+ testEncryptAndDecryptKeyEncryptionMimeEntity(null, null, null, true, false, false);
+ }
+
+ @Test
+ public void testEncryptAndDecryptKeyEncryptionMimeEntityStrongEncryptionAlg() throws Exception
+ {
+ testEncryptAndDecryptKeyEncryptionMimeEntity(null, EncryptionAlgorithm.RSA_OAEP, null, true, false, false);
+ }
+
+ @Test
+ public void testEncryptAndDecryptKeyEncryptionMimeEntityStrongEncryptionAlgKeyEncryptDigestSHA256() throws Exception
+ {
+ testEncryptAndDecryptKeyEncryptionMimeEntity(null, EncryptionAlgorithm.RSA_OAEP, DigestAlgorithm.SHA256, true, false, false);
+ }
+ @Test
+ public void testEncryptAndDecryptKeyEncryptionMimeEntityStrongEncryptionAlgKeyEncryptDigestSHA384() throws Exception
+ {
+ testEncryptAndDecryptKeyEncryptionMimeEntity(null, EncryptionAlgorithm.RSA_OAEP, DigestAlgorithm.SHA384, true, false, false);
+ }
+ @Test
+ public void testEncryptAndDecryptKeyEncryptionMimeEntityStrongEncryptionAlgKeyEncryptDigestSHA512() throws Exception
+ {
+ testEncryptAndDecryptKeyEncryptionMimeEntity(null, EncryptionAlgorithm.RSA_OAEP, DigestAlgorithm.SHA512, true, false, false);
+ }
+
+ @Disabled // SHA1 is allowed for now
+ @Test
+ public void testEncryptAndDecryptKeyEncryptionMimeEntityStrongEncryptionAlgWeakKeyEncryptionDigestAlg() throws Exception
+ {
+ // This should throw an encryption exception, enforceStrongEncryption is set, SHA-1 is requested for key encryption digest
+ testEncryptAndDecryptKeyEncryptionMimeEntity(null, EncryptionAlgorithm.RSA_OAEP, DigestAlgorithm.SHA1, true, true, false);
+ }
+ public void testEncryptAndDecryptKeyEncryptionMimeEntityWeakEncryptionAlgStrongKeyEncryptionDigestAlg() throws Exception
+ {
+ // This should throw an encryption exception, enforceStrongEncryption is set, SHA-1 is requested for key encryption digest
+ testEncryptAndDecryptKeyEncryptionMimeEntity(null, EncryptionAlgorithm.RSA_PKCS1_V15, DigestAlgorithm.SHA256, true, true, false);
+ }
-
- CMSSignedData signed = new CMSSignedData(byteData);
-
- Store certs = signed.getCertificates();
-
-
- for (X509CertificateHolder cert : certs.getMatches(null))
- {
- FileUtils.writeByteArrayToFile(new File("./testCert.der"), cert.getEncoded());
- }
- }
+ @Disabled // PKCS1.5 is allowed for now
+ @Test
+ public void testEncryptAndDecryptKeyEncryptionMimeEntityWeakKeyEncryptionAlg() throws Exception
+ {
+ // This should throw an encryption exception, enforceStrongEncryption is set, PKCS#1 V1.5 is requested for key encryption
+ testEncryptAndDecryptKeyEncryptionMimeEntity(null, EncryptionAlgorithm.RSA_PKCS1_V15, null, true, true, false);
+ }
+
+ @Disabled // SHA1 is allowed for now
+ @Test
+ public void testEncryptAndDecryptKeyEncryptionMimeEntityWeakKeyEncryptionDigestAlg() throws Exception
+ {
+ // This should throw an encryption exception, enforceStrongEncryption is set, SHA-1 is requested for key encryption digest
+ testEncryptAndDecryptKeyEncryptionMimeEntity(null, null, DigestAlgorithm.SHA1, true, true, false);
+ }
+ @Test
+ public void testEncryptAndDecryptKeyEncryptionMimeEntityWeakKeyEncryptionDigestAlgNoEnforce() throws Exception
+ {
+ // This should NOT throw an encryption exception, enforceStrongEncryption is NOT set, SHA-1 is requested for key encryption digest
+ testEncryptAndDecryptKeyEncryptionMimeEntity(null, null, DigestAlgorithm.SHA1, false, false, false);
+ }
+ @Test
+ public void testEncryptAndDecryptKeyEncryptionMimeEntityWeakKeyEncryptionAlgNoEnforce() throws Exception
+ {
+ // This should NOT throw an encryption exception, enforceStrongEncryption is NOT set, PKCS#1V1.5 is requested for key encryption
+ testEncryptAndDecryptKeyEncryptionMimeEntity(null, EncryptionAlgorithm.RSA_PKCS1_V15, null, false, false, false);
+ }
+ private void testEncryptAndDecryptKeyEncryptionMimeEntity(EncryptionAlgorithm encAlg, EncryptionAlgorithm keyEncAlg, DigestAlgorithm keyEncDigAlg, boolean enforceStrongEncryption, boolean expectEncException, boolean expectDecException) throws Exception
+ {
+ X509Certificate cert = TestUtils.getExternalCert("user1");
+
+ SMIMECryptographerImpl cryptographer = new SMIMECryptographerImpl();
+ if (encAlg != null)
+ cryptographer.setEncryptionAlgorithm(encAlg);
+ if (keyEncAlg != null)
+ cryptographer.setKeyEncryptionAlgorithm(keyEncAlg);
+ if (keyEncDigAlg != null)
+ cryptographer.setKeyEncryptionDigestAlgorithm(keyEncDigAlg);
+ cryptographer.setStrongEncryptionEnforced(enforceStrongEncryption);
+
+ MimeEntity entity = new MimeEntity();
+ entity.setText("Hello world.");
+ entity.setHeader(MimeStandard.ContentTypeHeader, "text/plain");
+ entity.setHeader(MimeStandard.ContentTransferEncodingHeader, "7bit");
+
+ MimeEntity encEntity = null;
+ if (expectEncException)
+ {
+ boolean exceptionOccured = false;
+ try
+ {
+ encEntity = cryptographer.encrypt(entity, cert);
+ assertNotNull(encEntity);
+ }
+ catch (Exception e)
+ {
+ exceptionOccured = true;
+ }
+ assertTrue(exceptionOccured);
+ return;
+ } else {
+ encEntity = cryptographer.encrypt(entity, cert);
+ assertNotNull(encEntity);
+ }
+
+
+ /*
+ * explicit header checking for compliance with Applicability
+ * Statement v 1.2
+ */
+ final ContentType type = new ContentType(encEntity.getContentType());
+ assertTrue(type.match(SMIMEStandard.CmsEnvelopeMediaType));
+ assertFalse(type.match(SMIMEStandard.CmsEnvelopeMediaTypeAlt));
+
+ X509CertificateEx certex = TestUtils.getInternalCert("user1");
+
+ if (expectDecException)
+ {
+ boolean exceptionOccured = false;
+ try
+ {
+ cryptographer.decrypt(encEntity, certex);
+ }
+ catch (Exception e)
+ {
+ exceptionOccured = true;
+ }
+ assertTrue(exceptionOccured);
+ }
+ else
+ {
+ MimeEntity decryEntity = cryptographer.decrypt(encEntity, certex);
+
+ assertNotNull(decryEntity);
+
+ byte[] decryEntityBytes = EntitySerializer.Default.serializeToBytes(decryEntity);
+ byte[] entityBytes = EntitySerializer.Default.serializeToBytes(entity);
+
+ assertTrue(Arrays.equals(decryEntityBytes, entityBytes));
+ }
+ }
}