2011-08-16 46 views
2

我試圖使用BouncyCastle的SMIME包使用ECDSA X509證書創建加密郵件。根據BouncyCastle的發行說明,自1.32開始支持(我使用1.46),但我一直收到一個異常,指出ECDSA OID中找不到密碼。使用EC X509證書加密電子郵件

org.bouncycastle.cms.CMSException:除了包裝內容密鑰: 不能創建密碼:找不到任何配套商 1.2.840.10045.2.1

下面是測試的一個片段我使用

Version: V3 
    Subject: [email protected] 
    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)); 

我確定我做的事顯然是錯的,但我現在沒有看到它。有任何想法嗎?

回答

2

正如Thomas Pornin建議(上圖),ECDH需要用來完成這項工作。因此,不必使用JceKeyTransRecipientInfoGenerator,而必須使用JceKeyAgreeRecipientInfoGenerator。

SMIMEEnvelopedGenerator gen = new SMIMEEnvelopedGenerator(); 
JceKeyAgreeRecipientInfoGenerator rig = new JceKeyAgreeRecipientInfoGenerator(CMSAlgorithm.ECDH_SHA1KDF, senderPrivateKey, senderPublicKey, CMSAlgorithm.AES128_WRAP); 
rig.setProvider("BC"); 
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 = "[email protected]"; 

Address fromUser = new InternetAddress("[email protected]"); 
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")); 
1

ECDSA是一種簽名算法,不是加密或密鑰交換算法。爲了加密消息,您需要收件人的RSA或Diffie-Hellman密鑰(可能是ECDH)。

+0

不允許EC公鑰用於ECDSA和ECDH?我認爲使用SHA256withECDSA作爲簽名算法不會將密鑰的使用侷限於簽名。那是錯的嗎? – senecaso

+1

ECDSA密鑰和ECDH密鑰共享相同的結構;但是,他們通常需要不同的生命週期和存儲策略(例如,您通常希望保留加密密鑰的備份和/或託管,以避免災難性的數據丟失情況,但您當然不希望爲簽名密鑰執行此操作;也,根據密鑰類型,私鑰泄露的後果是截然不同的)。許多X.509證書明確聲明瞭預期用法(密鑰用法擴展),它禁止使用簽名密鑰進行加密。 –

+0

是的,我遇到了你以前對[ECDSA和ECDH]的解釋之一(http://stackoverflow.com/questions/4969570/is-there-a-difference-between-ecdh-and-ecdsa-keys),但我認爲只要我把證書的關鍵用途標記爲一切(這是一個單獨的問題),它就可以被使用。在這種情況下,我相信其他事情正在發生,因爲在BC中失敗的代碼段只是簡單地提取公鑰的OID並將其傳遞到Cipher.getInstance()中。由於OID是用於EC「密鑰類型」的,我不希望找到有效的密碼 – senecaso