Encrypt messages with JavaMail
I want to process an inbox with encrypted messages automatically by using JavaMail. To encrypt the messages there is a certificate.p12 with a passphrase available.
BouncyCastle is used for message encryption in this example.
For the JavaMail connection and certificate I use the following attributes:
String host;
int port;
String protocol;
String username;
String password;
String folder;
String certFilename;
String certPassword;
As the first step I extract the PrivateKey and X509Certificate, which is needed to encrypt messages.
// Extract private key and certificate
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(new FileInputStream(certFilename), certPassword.toCharArray());
String keyAlias = getKeyAlias(ks);
PrivateKey privateKey = (PrivateKey) ks.getKey(keyAlias, certPassword.toCharArray());
X509Certificate cert = (X509Certificate) ks.getCertificate(keyAlias);
...
private String getKeyAlias(KeyStore ks) throws KeyStoreException {
Enumeration aliases = ks.aliases();
while (aliases.hasMoreElements()) {
String alias = (String) aliases.nextElement();
if (ks.isKeyEntry(alias)) {
return alias;
}
}
throw new IllegalStateException("Cannot find private key.");
}
Now I can process all messages and encrypt them:
...
// Process emails from inbox
Store store = getConnectedStore();
Folder inbox = store.getFolder(folder);
inbox.open(Folder.READ_WRITE);
Message[] msgs = inbox.getMessages();
for (Message msg : msgs) {
if (isEncrypted(msg)) {
processMessage(encrypt(privateKey, cert, (MimeMessage) msg));
}
}
private Store getConnectedStore() throws MessagingException
{
Properties props = new Properties();
props.put("mail.smtp.host", host);
props.put("mail.protocol.port", port);
Store store = Session.getInstance(props).getStore(protocol);
store.connect(host, username, password);
if (!store.isConnected())
{
throw new IllegalStateException("Cannot connect to store.");
}
return store;
}
private boolean isEncrypted(Message msg) throws MessagingException {
return msg.getContentType().contains("application/pkcs7-mime")
&& msg.getContentType().contains("smime-type=enveloped-data");
}
private MimeBodyPart encrypt(PrivateKey privateKey, X509Certificate cert, MimeMessage msg)
throws IOException, MessagingException, CMSException, NoSuchProviderException, SMIMEException {
RecipientId recId = new RecipientId();
recId.setSerialNumber(cert.getSerialNumber());
recId.setIssuer(cert.getIssuerX500Principal().getEncoded());
return SMIMEUtil.toMimeBodyPart(
new SMIMEEnveloped(msg).getRecipientInfos().get(recId).getContent(privateKey, "SunJCE")
);
}
private void processMessage(MimeBodyPart encrypted) throws IOException, MessagingException {
if (encrypted.getContent() instanceof Multipart) {
Multipart multi = (Multipart) encrypted.getContent();
// ...
}
}
This is just a simple example to show that encryption can be done quite easily.