I'm trying to use BouncyCastle's SMIME package to create an encrypted message using ECDSA X509 certificates. According to BouncyCastle's release notes, this has been supported since 1.32 (I'm using 1.46), but I keep getting an exception stating that no cipher can be found for the ECDSA OID.
org.bouncycastle.cms.CMSException: exception wrapping content key: cannot create cipher: Cannot find any provider supporting 1.2.840.10045.2.1
Here is a snippet from one of the test certificates I am using
Version: V3
Subject: EMAILADDRESS=bob@example.com
Signature Algorithm: SHA256withECDSA, OID = 1.2.840.10045.4.3.2
Key: EC Public Key
The code I am using to create the encrypted message looks like this:
// allow the use of the BC JCE
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
SMIMEEnvelopedGenerator gen = new SMIMEEnvelopedGenerator();
JceKeyTransRecipientInfoGenerator rig = new JceKeyTransRecipientInfoGenerator(cert);
gen.addRecipientInfoGenerator(rig);
MimeBodyPart msg = new MimeBodyPart();
msg.setText(message);
MimeBodyPart mp = gen.generate(
msg,
new JceCMSContentEncryptorBuilder(
CMSAlgorithm.AES128_CBC).setProvider("BC").build());
Properties props = System.getProperties();
Session session = Session.getDefaultInstance(props, null);
// TODO: This is incorrect. Perhaps AKA is better?
String to = cert.getSubjectDN().getName();
Address fromUser = new InternetAddress(from);
Address toUser = new InternetAddress(to);
MimeMessage body = new MimeMessage(session);
body.setFrom(fromUser);
body.setRecipient(Message.RecipientType.TO, toUser);
body.setSubject("example encrypted message");
body.setContent(mp.getContent(), mp.getContentType());
body.saveChanges();
body.writeTo(new FileOutputStream(filename));
I'm sure I'm doing something obviously wrong, but I'm not seeing it right now. Any ideas?
As Thomas Pornin suggested (above), ECDH needed to be used to make this work. So instead of using a JceKeyTransRecipientInfoGenerator, it was necessary to use a JceKeyAgreeRecipientInfoGenerator.
SMIMEEnvelopedGenerator gen = new SMIMEEnvelopedGenerator();
JceKeyAgreeRecipientInfoGenerator rig = new JceKeyAgreeRecipientInfoGenerator(CMSAlgorithm.ECDH_SHA1KDF, senderPrivateKey, senderPublicKey, CMSAlgorithm.AES128_WRAP);
rig.setProvider(BouncyCastleProvider.PROVIDER_NAME);
rig.addRecipient(recipientX509Certificate);
gen.addRecipientInfoGenerator(rig);
MimeBodyPart msg = new MimeBodyPart();
msg.setText("This is a secret message");
MimeBodyPart mp = gen.generate(msg, new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider("BC").build());
Properties props = System.getProperties();
Session session = Session.getDefaultInstance(props, null);
String to = "bob@example.com";
Address fromUser = new InternetAddress("alice@example.com");
Address toUser = new InternetAddress(to);
MimeMessage body = new MimeMessage(session);
body.setFrom(fromUser);
body.setRecipient(Message.RecipientType.TO, toUser);
body.setSubject("example encrypted message");
body.setContent(mp.getContent(), mp.getContentType());
body.saveChanges();
body.writeTo(new FileOutputStream("/tmp/encrypted.msg"));