opencodez

Send Encrypted Email Using Java Spring Boot – Simple Step By Step Guide With Source Code

Emails are used as communication modes most of the time. Not always people use encrypted email when sending business-sensitive information. Outlook and other email clients have inbuilt support for this and you can do this with a simple click.

Send Encrypted Email Using Java Spring Boot:

But what if you need to send encrypted email via your custom application. In this article, we will see how we can send an encrypted email using Java. We will use the Spring Boot project for this.

Software used

In this tutorial, we will use PKI to encrypt and sign our emails. For testing purposes, we will prepare a couple of self-signed certificates using Java Keytool and use them in our example.

Encrypted Email Prerequisite

Create Certificate for Signer : We will use our domain name certificate as a signer when we only sign and send an email. The below command gives us a JKS file with a private key and public certificate for our site. We will use this to sign our email.

keytool -genkey -alias opencodez -keyalg RSA -validity 1825 
-keystore "opencodez.jks" -storetype JKS 
-dname "CN=www.opencodez.com,OU=Opencodez,O=Opencodez,L=Pune,ST=Maharashtra,C=IN" 
-ext san=dns:opencodez.com,dns:OPENCODEZ.COM 
-keypass op3n.cod3z -storepass op3n.cod3z

Create Certificate for Mail Receipient : When an encrypted email is sent to any email id or recipient we need to have his public key. So the same can be used to encrypt an email for that user. In our tutorial we will use email id xsolapure@opencodez.comx and we will use a self-signed certificate for this email id. The command to prepare the JKS for this is

keytool -genkey -alias solapure -keyalg RSA -validity 1825 -keystore "solapure.jks" 
-storetype JKS -dname "CN=Pavan Solapure,O=Opencodez" 
-ext san=email:solapure@opencodez.com 
-keypass 123456 -storepass 123456

As this is a self-signed certificate we need to trust this in our machine. We will install this certificate along with its private key. So when an encrypted email is sent the mail client will be able to access the correct certificate and key. To do that we will convert our JKS to PKCS #12 using below command.

keytool -importkeystore -srckeystore solapure.jks -destkeystore solapure.p12 
-srcstoretype JKS -deststoretype PKCS12 -srcstorepass 123456 
-deststorepass 123456 -srcalias solapure -destalias solapure 
-srckeypass 123456 -destkeypass 123456 -noprompt

Once done, just double click the xsolapure.p12x file, you will be prompted to install this certificate. Follow the instructions and install this certificate as a Trusted Authority.

The Project

Now we will go through an actual encrypted email project. We will be extending our existing project from github repository. The most important is that we add bouncy castle dependencies to our pom.xml along with other default spring boot items.

xdependencyx
	xgroupIdxorg.bouncycastlex/groupIdx
	xartifactIdxbcprov-jdk15onx/artifactIdx
	xversionx1.58x/versionx
x/dependencyx

xdependencyx
	xgroupIdxorg.bouncycastlex/groupIdx
	xartifactIdxbcmail-jdk15onx/artifactIdx
	xversionx1.58x/versionx
x/dependencyx

xdependencyx
	xgroupIdxorg.bouncycastlex/groupIdx
	xartifactIdxbcpkix-jdk15onx/artifactIdx
	xversionx1.58x/versionx
x/dependencyx

Now letxs look into our MailEncryptionUtil.java

Email Signing

public static MimeMessage signMessage(MimeMessage message) throws Exception {
	
	Security.addProvider(new BouncyCastleProvider());

	CertificateDetails certDetails = CertificateUtil.getCertificateDetails(SIGNING_JKS,SECRET_KEY);
	
	// Create the SMIMESignedGenerator
	SMIMECapabilityVector capabilities = new SMIMECapabilityVector();
	capabilities.addCapability(SMIMECapability.dES_EDE3_CBC);
	capabilities.addCapability(SMIMECapability.rC2_CBC, 128);
	capabilities.addCapability(SMIMECapability.dES_CBC);
	capabilities.addCapability(SMIMECapability.aES256_CBC);
	
	ASN1EncodableVector attributes = new ASN1EncodableVector();
	attributes.add(new SMIMECapabilitiesAttribute(capabilities));
	
	IssuerAndSerialNumber issAndSer = new IssuerAndSerialNumber(new X500Name(certDetails.getX509Certificate().getIssuerDN().getName()),
			certDetails.getX509Certificate().getSerialNumber());
	attributes.add(new SMIMEEncryptionKeyPreferenceAttribute(issAndSer));
	
	SMIMESignedGenerator signer = new SMIMESignedGenerator();
	
	signer.addSignerInfoGenerator(new JcaSimpleSignerInfoGeneratorBuilder()
			.setProvider("BC")
			.setSignedAttributeGenerator(new AttributeTable(attributes))
			.build("SHA1withRSA", certDetails.getPrivateKey(), 
					certDetails.getX509Certificate()));
	
	// Add the list of certs to the generator
	ListxX509Certificatex certList = new ArrayListxX509Certificatex();
	certList.add(certDetails.getX509Certificate());
	
	JcaCertStore bcerts = new JcaCertStore(certList);
	signer.addCertificates(bcerts);
	
	// Sign the message
	MimeMultipart mm = signer.generate(message);

	// Set the content of the signed message
	message.setContent(mm, mm.getContentType());
	message.saveChanges();
	
	return message;
}

The first thing this utility method does is to add Bouncy Castle as one of the Security Provider. Then we read the certificates from JKS we prepared earlier. You can refer more on this utility in our previous article

Then we add some default SMIME  capabilities and create a signer object. The signer also needs details about the certificate we read earlier. The signer then can generate the MimeMultipart object which we can send.

To send mail in our example we will do like

public void signAndSend(Email eParams) throws Exception {
	
	MimeMessage message = mailSender.createMimeMessage();
	MimeMessageHelper helper = new MimeMessageHelper(message);
	helper.setTo(eParams.getTo().toArray(new String[eParams.getTo().size()]));
	helper.setReplyTo(eParams.getFrom());
	helper.setFrom(eParams.getFrom());
	helper.setSubject(eParams.getSubject());
	helper.setText(eParams.getMessage(), true);
	
	mailSender.send(MailEncryptionUtil.signMessage(message));
	
}

Post this, once you receive mail in your mailbox you can verify the signature as below.

x

Encrypted Email

For encryption of email, the utility class has separate method as below

public static MimeMessage encryptMessage(MimeMessage message) throws Exception  {
	
	Security.addProvider(new BouncyCastleProvider());
	
	// create the generator for creating an smime/encrypted message
	SMIMEEnvelopedGenerator  gen = new SMIMEEnvelopedGenerator();
	
	X509Certificate recipientCert = getRecipientPublicCertificate(message);
	
	gen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(recipientCert).setProvider("BC"));
	
	MimeBodyPart msg = new MimeBodyPart();
	msg.setContent(message.getContent(), message.getContentType());
	
	MimeBodyPart mp = gen.generate(msg, new JceCMSContentEncryptorBuilder(CMSAlgorithm.RC2_CBC).setProvider("BC").build());
	message.setContent(mp.getContent(), mp.getContentType());
	message.saveChanges();
	
	return message;
}

The first step is similar to signing and we need to let JVM know about our security provider. The method getRecipientPublicCertificate is externalized. In this example, we are reading a fixed certificate for an email but in reality, this has to be dynamic. We need to figure out a way to fetch public certificates based on emails from the public certificate directory.

private static X509Certificate getRecipientPublicCertificate(MimeMessage message) throws Exception {

	//for future - add routine to fetch public certificate for email
	//for now - just print the email and use fixed certificate 
	for(Address addrs: message.getAllRecipients()) {
		System.out.println(addrs.toString());
	}
	
	CertificateFactory fact = CertificateFactory.getInstance("X.509");
	ClassLoader classLoader = MailEncryptionUtil.class.getClassLoader();
	File file = new File(classLoader.getResource("solapure@opencodez.com.cer").getFile());
	FileInputStream is = new FileInputStream (file);
	X509Certificate recipientCert = (X509Certificate) fact.generateCertificate(is);
	return recipientCert;
}

Once encrypted mail is sent, based upon your recipientxs email client he will be asked to allow access to a private key. You will see the screen as below

If you allow it then only you will be able to open your encrypted mail. The opened email will look like 

So now we are sure that our email is encrypted and only the actual recipient will be able to open and read it.  You can download the code from our Github

Download Code

Summary

The tutorial gives you a working example of email encryption and signing. I hope you like it and find it useful. Please do not hesitate to comment or ask a question.