2

我正在尝试使用 BouncyCastle 的 SMIME 包创建使用 ECDSA X509 证书的加密消息。根据 BouncyCastle 的发行说明,自 1.32 以来就已支持此功能(我使用的是 1.46),但我不断收到异常消息,指出找不到 ECDSA OID 的密码。

org.bouncycastle.cms.CMSException:异常包装内容密钥:无法创建密码:找不到任何支持 1.2.840.10045.2.1 的提供程序

这是我正在使用的测试证书之一的片段

  Version: V3
  Subject: EMAILADDRESS=bob@example.com
  Signature Algorithm: SHA256withECDSA, OID = 1.2.840.10045.4.3.2

  Key:  EC Public Key

我用来创建加密消息的代码如下所示:

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

我确定我在做一些明显错误的事情,但我现在没有看到它。有任何想法吗?

4

2 回答 2

2

正如 Thomas Pornin 所建议的(上图),需要使用 ECDH 来完成这项工作。因此,有必要使用 JceKeyAgreeRecipientInfoGenerator,而不是使用 JceKeyTransRecipientInfoGenerator。

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"));
于 2011-08-19T06:29:21.540 回答
1

ECDSA 是一种签名算法,而不是加密或密钥交换算法。为了加密消息,您需要收件人的 RSA 或 Diffie-Hellman 密钥(可能是 ECDH)。

于 2011-08-17T11:37:01.277 回答