Question

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?

Was it helpful?

Solution

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"));

OTHER TIPS

ECDSA is a signature algorithm, not an encryption or key exchange algorithm. In order to encrypt a message, you need the recipient's RSA or Diffie-Hellman key (possibly ECDH).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top