Tuesday, October 14, 2008

How to secure email using S/MIME standard

S/MIME
S/MIME (Secure / Multipurpose Internet Mail Extensions) is a standard for public key encryption and signing of e-mail encapsulated in MIME.

Java Libraries
There are several Java libraries for S/MIME encryption: ISNetworks S/MIME (link did not work last time I was trying to locate it), CMS-S/MIME, JSMIME, JavaMail-Crypto etc. But JavaMail-Crypto library is the easiest in use with Java Mail. It uses Bouncy Castle libraries (the bcprov-jdk14-139.jar (BouncyCastle JCE provider) and the bcmail-jdk14-139.jar (BouncyCastle S/MIME implementation) files).

Code Examples for Encryption and Signing
How to encrypt email message using JavaMail-Crypto example:
public MimeMessage encrypt(Session session, MimeMessage mimeMessage) throws Exception {
// Getting of the S/MIME EncryptionUtilities.
EncryptionUtils encUtils = EncryptionManager.getEncryptionUtils(EncryptionManager.SMIME);

// Loading of the S/MIME keystore from the file (stored as resource).
char[] keystorePass = "keystore pass".toCharArray();
EncryptionKeyManager encKeyManager = encUtils.createKeyManager();
encKeyManager.loadPublicKeystore(
getClass().getResourceAsStream("/keystore.p12"),
keystorePass);

// Getting of the S/MIME public key for encryption.
Key publicKey = encKeyManager.getPublicKey("Key Alias");

// Encrypting the message.
return encUtils.encryptMessage(session, mimeMessage, publicKey);
}

How to sign email message using JavaMail-Crypto example:
public MimeMessage sign(Session session, MimeMessage mimeMessage) throws Exception {
// Getting of the S/MIME EncryptionUtilities.
EncryptionUtils encUtils = EncryptionManager.getEncryptionUtils(EncryptionManager.SMIME);

// Loading of the S/MIME keystore from the file (stored as resource).
char[] keystorePass = "keystore pass".toCharArray();
EncryptionKeyManager encKeyManager = encUtils.createKeyManager();
encKeyManager.loadPrivateKeystore(
getClass().getResourceAsStream("/keystore.p12"), keystorePass);

// Getting of the S/MIME private key for signing.
Key privateKey = encKeyManager.getPrivateKey("Key Alias", keystorePass);

// Signing the message.
return encUtils.signMessage(session, mimeMessage, privateKey);
}

Source Code
You can download source code from here.

Troubleshooting
To run this code you will need to install Unlimited Strength Jurisdiction Policy Files for your JDK: http://java.sun.com/j2se/1.4.2/download.html. If it is not installed you will have one of the following exceptions:
"java.lang.SecurityException: Unsupported keysize or algorithm parameters"
or
"java.security.InvalidKeyException: Illegal key size"


Email Client Setup
To read email messages encrypted with S/MIME encryption standard you will need to import your PKCS12 certificate into the email client you use. If you use Mozilla Thunderbird email client you should do following:
Tools -> Options -> Advanced -> Certificates -> View Certificates -> Your Certificates -> Import
and select your keystore.p12 PKCS12 certificate file. Use your keystore password to import PKCS12 certificate.
After performing this steps you will be able to read messages encrypted by your certificate.

Certificate Generation
PKCS12, Personal Information Exchange Syntax Standard, certificates can be used for things such as email signing and file signing. They are different from other certificates in that rather than being only the public or private certificate, they are a combination of both plus the root certificate. This means the person they are made for only has to worry with one file.

Certificate generation using OpenSSL
To generate PKCS12 certificate using OpenSSL follow the steps from the "Creating PKCS12 Certificates" article.

Certificate generation using Thawte
There is ability to generate certificate using Thawte service:
https://www.thawte.com/secure-email/personal-email-certificates/index.html?click=main-nav-products-email

17 comments:

klklkj said...

nice job with this article :) thank you :)

Frank Thilo said...

You saved me hours, good starting point !

Yuri said...

Thank you!

Mahesh said...

Good starter, thanks!

ahmed said...

thanks alot for this topic
i want to ask a question
if i downloaded an email certificate from thawte how i could use it to encrypt/sign a message using your simplified example..
hope u understand wut i mean
thanks

sysmat said...

Thx for article, but a lot of people have error:

java.security.NoSuchProviderException: No provider configured for S/MIME

Even installing unlimeted JCE didn't help, what this error actually mean

Regards

sysmat said...

For me the easy way was a oyster project(also using bouncy castle).

Regards

Industrialist said...

ENV:
bcprov-jdk14-143.jar
jdk14-143.jar
javamail-crypto_060622.jar
unlimited JCE
JAVAMAIL 1.4.2

when I run this program

http://javamail-crypto.sourceforge.net/examples/EncryptMessage.java

java.security.NoSuchProviderException: No provider configured for S/MIME
--> is caught

Any idea is appreciated.

I have "google" it and cannot find a fine solution. Is there anything that can encrypt the message and its attachment with public/private key infrastructure?

Thanks at all.

sysmat said...

Industrialist:

Are you running as stand alone application?

It could be yours jars, I suggest you use this jars in java 1.6:

bcmail-jdk16-143.jar
bcprov-jdk16-143.jar
javamail-crypto_060622.jar
javamail-crypto-bouncycastle-smime_060622.jar

Industrialist said...

To sysmat,
Env:
Java_jdk_1_6_0
jre6


I have installed following
(javamai_1_4_2)
.%lib%\dsn.jar
%lib%\imap.jar
%lib%\mailapi.jar
%lib%\pop3.jar
%lib%\smtp.jar
%lib%\bcmail-jdk16-143.jar
%lib%\bcpg-jdk16-143.jar
%lib%\bcprov-jdk16-143.jar
%lib%\javamail-crypto_060622.jar
%lib%\javamail-crypto-bouncycastle-smime.jar
%lib%\security\local_policy.jar
%lib%\security\US_export_policy.jar

and unlimited JCE from java.sun.com

I also configured
C:\Program Files\Java\jre6\lib\security\java.security

and add a line security.provider.10=org.bouncycastle.jce.provider.BouncyCastleProvider
after the last security provider.


but a java.security_NoSuchProviderException: No Provider configured for S/MINE --> is caught

following is the full stack trace of that exception:

DEBUG: setDebug: JavaMail version 1.4.2
DEBUG: getProvider() returning javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.
smtp.SMTPSSLTransport,Sun Microsystems, Inc]
java.security.NoSuchProviderException: No provider configured for S/MIME
at net.suberic.crypto.EncryptionManager.getEncryptionUtils(EncryptionMan
ager.java:106)
at EncryptMessage.main(EncryptMessage.java:71)

-----------------------------
Any help / hint / discussion is appreciated.

Thanks at all

Industrialist said...

I think first I need a S/MIME Provider

Second, I need know how to configure that 'provider' may be in jar or other format in my JDK.

Let me try it.

Still, any help is welcome

Thanks

ahmed said...

industrialist:
send me your email address so that we could discuss your problem and solve it, i have developed a desktop mail client application that sends and recives messages secured with S/MIME, i need more information about why you need to use S/MIME because there may be better solutions.

Industrialist said...

ahmed,


Thanks for your help.

Sorry for forgetting the installation of JCE onto jre.

It works now.

blaf said...

Hello,
I have a problem with mail signing. If I try the code from this article to sign mail with attachement (multipart) mail is sent but Thunderbird says "Message includes digital signature but it is invalid. The signature doesn't match the message content correctly. ..." Mail without atachement is correct. Where can be the problem?

Bill said...

Can someone explain something to me. Suppose you have multiple recipients in your email. Don't you need to pass in a set of keys to encrypt the message for each recipient? However, the Javamail-Crypto API only allows you to pass in a single key from encryption. Is there something I'm not getting, because I would think you'd need to be able to pass in a list.

I looked at the underlying code. For instance, for the BouncyCastle S/MIME stuff it does the following:

public MimeMessage encryptMessage(Session s, MimeMessage msg, java.security.Key key)
...
gen.addKeyTransRecipient(bKey.getCertificate());
...

Code just adds a single key when generating S/MIME, but what if you had a list of certs?

Panamint Joe said...

Thawte, Inc. discontinued Personal Email Certificates and the Web of Trust (WOT) certification system in late 2009. There was a linked FAQ article, but that has been removed, too.

Vojkan said...

Hi, I'am trying to illustrate complete process of sending message encrypted by S/MIME with triple-encapsulation.

Here is the illustration that I have done.

http://img31.imageshack.us/img31/6876/aqfx.jpg

Please comment. I think I am missing something out.
Any help will be greatly appreciated!

You can also reply on:
http://stackoverflow.com/questions/18753280/comments-on-s-mime