2

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?

Mike Samuel
  • 109,453
  • 27
  • 204
  • 234
senecaso
  • 273
  • 2
  • 10

2 Answers2

2

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"));
Pawel Os.
  • 531
  • 5
  • 20
senecaso
  • 273
  • 2
  • 10
1

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).

Thomas Pornin
  • 68,772
  • 14
  • 141
  • 184
  • Cant an EC Public Key be used for both ECDSA and ECDH? I assumed that using SHA256withECDSA for the signature algorithm wouldnt restrict the usage of the key to just signatures. Is that wrong? – senecaso Aug 17 '11 at 13:08
  • 1
    An ECDSA key and an ECDH key share the same structure; however, they usually need distinct life cycles and storage policies (e.g. you usually want to keep a backup and/or escrow of the encryption key, to avoid catastrophic data loss scenarios, but you certainly do not want to do it for signature keys; also, consequences of a private key compromise are quite distinct depending on the key type). Many X.509 certificates explicitly state the intended usage (Key Usage extension), which forbids using a signature key for encryption. – Thomas Pornin Aug 17 '11 at 14:18
  • Yes, I came across one of your previous explanations of [ECDSA and ECDH](http://stackoverflow.com/questions/4969570/is-there-a-difference-between-ecdh-and-ecdsa-keys), but I thought as long as I marked the certificate's Key Usage for everything (thats a separate issue) that it would be allowed to be used. In this case, I believe something else is going on though, because the section of code that is failing in BC is simply extracting the OID of the public key and passing that into a Cipher.getInstance(). Since the OID is for the EC "key type", I wouldnt expect a valid Cipher to ever be found – senecaso Aug 17 '11 at 23:20