Secure Email from Java

I've been working recently with a client to do some rather useful things with notifications, and one of them involved sending a secure email from within a Java program. We encountered some interesting (translation: weird!) challenges, and in overcoming them, I worked out a reasonably straightforward path through the minefield. If you've been thinking about secure-email-enabling your Java app but aren't sure where to start, hopefully this will serve as a fairly quick and mostly painless primer.  :-)

The Problem

Let me first say that if you only want to send a plain-text email from Java, there are ways to do that without much fuss and without any external players. If you want to sign or encrypt your emails, though, you'll need a couple of extra components:
1. a digital certificate (private/public key pair issued by a recognized Certificate Authority, or "CA") and
2. a means of using the certificate to sign and/or encrypt the email

The goal is to digitally sign an email to assure recipients that the sender of the mail is indeed me (or you, if you're following along at work/home). Let's get started!

Getting Your Tools in Order

Getting a Certificate

First, we have to have a digital certificate. If you already have one, you can skip this step...but if not, StartSSL offers free user/email certificates for personal use. Just point your browser to the StartSSL site and click the large button labeled "Sign-up". You'll need to provide them some information, enter the verification code they email to the address you provide, and they do the rest...including installing your new cert and the certificate chain into your web browser.

Freeing the Certificate from your Browser

Perhaps the easiest way to use a certificate is to store it (keys, certificate chain) in a Java Keystore (jks). Extracting your shiny new certificate from your browser is a relatively easy (albeit drawn-out) process. From your browser, export your certificate, including private key. This will produce a .pfx file, which is a PKCS12 keystore. From Chrome, you simply:
  1. Click on the Wrench (or Lines) icon in the upper-right corner
  2. Select "Settings" from the menu
  3. "Show advanced settings..." at the bottom of the page
  4. Scroll down to the section labeled "HTTPS/SSL"
  5. Click the "Manage certificates..." button to display your certificates.
Then, from the certificates window:
  1. Select the target certificate and click the "Export..." button
  2. Click "Next" from the Export Wizard window
  3. Choose "Yes, export the private key" and click "Next"
  4. Under the "Personal Information Exchange - PKCS #12 (.PFX)" entry, select the options to "Include all certificates in the certification path if possible" and "Export all extended properties" (NOTE: Do NOT choose to "Delete the private key if the export is successful". No no no!) and click "Next"
  5. Enter a password (twice) and click "Next"
  6. Provide a path/filename for the export and click "Next", and finally...
  7. Confirm the export options and click "Finish".
Now that we've liberated your cert from the browser, let's make it usable by our (non-browser) Java program.

Creating a Java Keystore

The fastest, easiest way I've found to convert a .pfx file to a .jks (Java Keystore) file is with the Oracle 11g database client. The database client can be downloaded by following this link, selecting the "See All" link to the right of your listed operating system, and choosing the 11g client from the OS-specific download page. Once it's downloaded and installed, you're ready to proceed.

Like the .pfx file, the Oracle wallet is a PKCS12 keystore, and the orapki utility (and other tools) included with the database client can be used to manipulate it...as long as it thinks it's dealing with an Oracle wallet. To make that happen, simply rename the .pfx file to ewallet.p12. Since we aren't dealing with the Oracle Wallet Manager, we don't have to worry about meeting OWM's password criteria or other niceties. Yes, that really is all there is to it!

Now, to make a Java Keystore. To do that, you'll need to open a command prompt and do the following tasks:
  1. Create an ORACLE_HOME environment variable that points to the install location of the Oracle client
  2. Run the following command, pointing to the orapki utility under %ORACLE_HOME%\bin (in Windows) or $ORACLE_HOME/bin (Mac/Linux/UNIX):
orapki wallet pkcs12_to_jks -wallet <wallet_directory> -pwd <wallet_password> -jksKeyStoreLoc <java_key_store_path_and_filename> -jksKeyStorepwd <jks_password>

You should now have a brand new Java KeyStore! You can verify its contents with the OpenSSL keytool utility:
keytool -list -keystore <java_key_store>

Now that we have our credentials in order, on to the Java side of things!

Building the Solution

There are several Java libraries available that aid in signing and/or encrypting email. Of the non-commercial options I found, all use the Bouncy Castle Crypto API and libraries as their underpinnings. Bouncy Castle (BC) may have a funny name, but it's all business with regard to encryption.

At a very high level, you need to do the following things to create/send a signed email:
  1. Provide the email "essentials": SMTP server host & port, email addresses (sender & receiver), a subject, content, and the sending user's password
  2. Add BC as a new crypto provider
  3. Retrieve the cert from your Java Keystore
  4. Create and sign the email using the BC API/libraries
  5. Send the email
There is much more you can do of course, but these are the "must-haves".

In preparation for developing our secure email module, I created a proof of concept (BCCrypTool) by marrying a Java email program I'd written previously and some BC sample code...code reuse at its lowest level, but still good for the environment. :-) What you see here in my GitHub repo is a bit of streamlined Java code that should be pretty easy to repurpose. Please feel free to take a copy and do just that, and if you make significant changes/improvements and are able and inclined to share them, please feel free to do that as well. Sharing is caring.  :-)

A quick note on libraries. You'll need the following to make this work:
And from Bouncy Castle, the following:
  • The BC provider library (bcprov-jdk15on-147.jar)
  • The BC S/MIME library (bcmail-jdk15on-147.jar)
  • The BC security library (bcpkix-jdk15on-147.jar)
There are other BC libraries available here if you'd like to take things even further.

All the best to you in your Java secure email adventures!

Mark

Comments:

could a java program make my yahoo free web-page-based email able to send encrypted mail to others whom also had the same java code?

Posted by govani on February 28, 2013 at 11:12 PM PST #

You're actually asking a few questions in there, so let me break them out and try to address each one.

You can send/receive encrypted emails via Yahoo Mail - using the server/account information in your code - if you know the server name, port, etc.

Using the web interface to Yahoo Mail (or any web-based email) is a different matter. You could encrypt the text and copy/paste it into the mail message, then the recipient could do the same on the other end. That is similar to how PGP/OpenGPG does it, and while it involves more steps, it's been done reliably for years.

Underneath most of those options is the concept of PKI, or Public Key Infrastructure. At a really basic level, each person has two keys, one public & one private. As an example, if I encrypt an email to you using your public key, you can decrypt it using your private key (for example). As long as each party has access to the other's public key, it's possible to exchange secure emails.

I'd recommend reading some books/publications about PKI to get those concepts down, then seeing what is practical within your environment. If both parties are using a webmail interface, OpenGPG (or your own Java-based, stand-alone encryption/decryption program) may be your best bet.

Hope this helps, and good luck!

All the best,
Mark

Posted by Mark Heckler on March 01, 2013 at 07:49 AM PST #

Hi,

I would like to ask something regarding java mail. I am reading a mail using java mail api with whih I need to download an attachment from email. Whenever I am looking the mail manually I am able to find the attachment but whenever my code tries to open the mail then it is finding 'winmail.dat' as an attachment rather than Original one. Why it could be happening and what is the reason behind that?

Posted by guest on April 18, 2013 at 10:08 PM PDT #

Hi,

I haven't run into that particular issue, but I'd encourage you to keep chipping away at it. Updates to JavaMail are mentioned here - http://www.oracle.com/technetwork/java/javamail/index.html - and there is a wealth of information out there on the various combinations of OS, email servers/clients, formats, etc. that can make life "interesting" as a developer. :-)

I'd also encourage you to share your findings once you isolate and resolve that particular issue. The more we all share, the more we all know.

All the best,
Mark

Posted by Mark Heckler on April 19, 2013 at 07:02 AM PDT #

Hi, Sorry for the delay actually I have posted one problem regarding email as a guest as follows.

I would like to ask something regarding java mail. I am reading a mail using java mail api with whih I need to download an attachment from email. Whenever I am looking the mail manually I am able to find the attachment but whenever my code tries to open the mail then it is finding 'winmail.dat' as an attachment rather than Original one. Why it could be happening and what is the reason behind that?

I got some R&D on that and came to know something that when a mail is auto forwarded from email clients like Microsoft Outlook or some other things then the attachments are masked as winmail.dat whenever we try to access them technically like using java to download them.

the file winmail.dat is the file which contains the information about that attachment like attachment link, some style information. Finally I have used a third party jar name 'tnef.jar' to read that file and successfully downloaded the original attachments. :) That jar is works only when the winmail.dat file's content type is 'application/ms-tnef' which generally indicates a file which contains the mail's styles information and attachment information if it has.

I am very happy to share my knowledge on this thing and also thanking you people for your immediate responses.

Thanks.

Posted by guest on April 26, 2013 at 06:25 AM PDT #

Hi,

That's great to hear! Congratulations on solving that, and thank you very much for closing the loop and sharing what you found out.

The Java community is strong and only gets better the more we all share!

All the best,
Mark

Posted by Mark Heckler on April 26, 2013 at 11:34 AM PDT #

Thanks Mark for this example. Unfortunately I can't seem to get past this error, thought I've followed your instructions here. I'm using NetBeans, getting this error:

java.io.IOException: Keystore was tampered with, or password was incorrect

Any hints appreciated! Thanks again.

Posted by Roj on September 08, 2013 at 08:46 AM PDT #

Hi Roj,

Sounds like you may have a misbehaving/corrupt keystore. As a starting point, you might try running

keytool -list -keystore <java_key_store>

on the target machine to see if you still have access. If everything checks out and you still get an error, you may want to rename that keystore and create another one, again (best) on that machine.

Keystores can be a bit temperamental, as you're seeing. Good luck!

Mark

Posted by Mark Heckler on September 09, 2013 at 12:10 PM PDT #

Thanks Mark. Yes, I was trying this from a windows7 laptop. I'm going to need to port it to an AIX server anyhow. So I've got the comm. working there, using manual openssl and sendmail. I'm going to try adapting this example there. I'll keep you posted, and thanks!

Posted by guest on September 15, 2013 at 01:37 PM PDT #

Hi Roj,

You're very welcome! Please do keep me posted; the more we all share, the more we all learn!

All the best,
Mark

Posted by Mark Heckler on September 16, 2013 at 08:47 AM PDT #

Hi Mark,

I have a recipient's public key, and I'd like to use it to encrypt the mime message before it is digitally signed and mailed. I can do this pretty easily with opensssl. Can it be done with your exampke here? I see the dig. signature part, but not the encrption with a public key part? Thanks!

Posted by guest on September 22, 2013 at 07:26 PM PDT #

Can we also encrypt with this example? I have the recipient's public key, would encrypt the signed mime with that. Am I missing thast here? Thanks!

Posted by Roj on September 25, 2013 at 07:40 PM PDT #

Hi Roj,

You can do that pretty easily by adding a bit of code to this example to encrypt the message as well. In my code, I only sign it using my key, but for what you need to do you'd want to use the recipient's public key to encrypt it as well.

I had intended to circle back on this and expand it - quite a bit - by now, but I just haven't had the chance. Soon! Good luck with your efforts, and please share your victories as you go. Security was always an important topic, but it is only becoming more so.

All the best to you, Roj!

Mark

Posted by Mark Heckler on October 02, 2013 at 07:25 AM PDT #

Post a Comment:
  • HTML Syntax: NOT allowed
About

The Java Jungle addresses topics from mobile to enterprise Java, tech news to techniques, and anything even remotely related. The goal is to help us all do our work better with Java, however we use it.

Your Java Jungle guide is Mark Heckler, an Oracle Java/Middleware/Core Engineer with development experience in numerous environments. Mark's current work pursuits and passions all revolve around Java and leave little time to blog or tweet - but somehow, he finds time to do both anyway.

Mark lives with his very understanding wife, three kids, and dog in the St. Louis, MO area.



Stay Connected

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today