我正在尝试从 Java Mail(充气城堡 1.51)向我的 Outlook 发送 S/MIME 签名和加密的邮件。
我可以很好地发送邮件,但接收是一个问题,因为 Outlook 不想打开邮件。以下是我尝试打开时遇到的错误:
无法打开此项目。底层安全系统无法找到您的数字 ID 名称。
使用 p7m Viewer 可以正常查看相同的邮件(以 eml 格式保存到本地文件),这表明 P12 证书已正确安装在我的笔记本电脑上。我已经在我的 Java 邮件代码中安装了与密钥库相同的 P12 文件。
我做错什么了吗?Outlook的问题结束了吗?我正在使用 Office 365 并想添加 p7m 查看器也无法打开我从 Outlook WebMail 下载的 smime.p7m。我收到的错误是:
文件已损坏;可能缺少签名信息。
下面是我用来加密/发送邮件的 Java 代码。
public class BCTest {
public static final String pkcs12Keystore = "C:/Development/Workspace/BouncyCastle_SecureMail/resources/cert/StartCom.p12";
public static final String ksPassword = "ksPassword";
public static final String sendFile = "C:/Development/Workspace/BouncyCastle_SecureMail/resources/hello.txt";
public static final String outputFile = "C:/Development/Workspace/BouncyCastle_SecureMail/output/Encrypted.eml";
public static final String message = "Hi There!!";
public static final String frAddress = "email@domain.com";
public static final String toAddress = "email@domain.com";
public static final String host = "outlook.office365.com";
public static final int port = 587;
public static final String userName = "email@domain.com";
public static final String password = "password";
public static void main(String[] args) {
send();
}
public static void send() {
try {
System.out.println("Setting Mailcap");
MailcapCommandMap mailcap = (MailcapCommandMap) CommandMap.getDefaultCommandMap();
mailcap.addMailcap("application/pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_signature");
mailcap.addMailcap("application/pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_mime");
mailcap.addMailcap("application/x-pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_signature");
mailcap.addMailcap("application/x-pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_mime");
mailcap.addMailcap("multipart/signed;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.multipart_signed");
CommandMap.setDefaultCommandMap(mailcap);
/* Add BC */
System.out.println("Setting Bouncy Castle as provider");
Security.addProvider(new BouncyCastleProvider());
/* Open the keystore */
System.out.println("Opening the keystore: " + pkcs12Keystore + " using password " + ksPassword);
KeyStore keystore = KeyStore.getInstance("PKCS12", "BC");
keystore.load(new FileInputStream(pkcs12Keystore), ksPassword.toCharArray());
// Find the first legit alias in the keystore and use it
System.out.println("Getting the keystore alias");
Enumeration<String> e = keystore.aliases();
String keyAlias = null;
while (e.hasMoreElements() && (keyAlias == null)) {
String alias = e.nextElement();
keyAlias = keystore.isKeyEntry(alias) ? alias : null;
}
if (keyAlias == null) {
throw new Exception("Can't find a private key!");
}
Certificate[] chain = keystore.getCertificateChain(keyAlias);
/* Get the private key to sign the message with */
System.out.println("Getting the private key");
PrivateKey privateKey = (PrivateKey) keystore.getKey(keyAlias, ksPassword.toCharArray());
if (privateKey == null) {
throw new Exception("No private key for alias: " + keyAlias);
}
/* Create Email body */
System.out.println("Creating the Email body");
MimeBodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setContent(message, "text/html");
/* Attach the file to encrypt */
System.out.println("Creating the attachment");
FileDataSource fds = new FileDataSource(sendFile);
MimeBodyPart attachPart = new MimeBodyPart();
attachPart.setDataHandler(new DataHandler(fds));
attachPart.setFileName(fds.getName());
System.out.println("Adding body & attachment to mail");
MimeMultipart bodyMulti = new MimeMultipart();
bodyMulti.addBodyPart(messageBodyPart);
bodyMulti.addBodyPart(attachPart);
System.out.println("Setting mail properties");
Session session = Session.getDefaultInstance(System.getProperties());
MimeMessage body = new MimeMessage(session);
body.setFrom(new InternetAddress(frAddress));
body.setRecipient(Message.RecipientType.TO, new InternetAddress(toAddress));
body.setSentDate(new Date());
body.setSubject("Encrypted Mail");
body.setContent(bodyMulti, bodyMulti.getContentType());
body.saveChanges();
/* Create the SMIMESignedGenerator */
System.out.println("Creating the SMIMESignedGenerator");
SMIMECapabilityVector capabilities = new SMIMECapabilityVector();
capabilities.addCapability(SMIMECapability.dES_EDE3_CBC);
capabilities.addCapability(SMIMECapability.rC2_CBC, 128);
capabilities.addCapability(SMIMECapability.dES_CBC);
capabilities.addCapability(SMIMECapability.aES256_CBC);
System.out.println("Creating the ASN1EncodableVector");
ASN1EncodableVector attributes = new ASN1EncodableVector();
attributes.add(new SMIMEEncryptionKeyPreferenceAttribute(new IssuerAndSerialNumber(new X500Name(((X509Certificate) chain[0])
.getIssuerDN().getName()), ((X509Certificate) chain[0]).getSerialNumber())));
attributes.add(new SMIMECapabilitiesAttribute(capabilities));
System.out.println("Adding certificate");
List<X509Certificate> certList = new ArrayList<X509Certificate>();
certList.add((X509Certificate) chain[0]);
SMIMESignedGenerator gen = new SMIMESignedGenerator("binary");
gen.addSignerInfoGenerator(new JcaSimpleSignerInfoGeneratorBuilder().setProvider("BC").build("SHA1withRSA", privateKey,
(X509Certificate) chain[0]));
gen.addCertificates(new JcaCertStore(certList));
MimeMultipart multiPart = gen.generate(body);
MimeMessage signedMessage = new MimeMessage(session);
System.out.println("Creating Mime Message");
@SuppressWarnings("unchecked")
Enumeration<String> headers = body.getAllHeaderLines();
while (headers.hasMoreElements()) {
signedMessage.addHeaderLine(headers.nextElement());
}
signedMessage.setContent(multiPart);
signedMessage.saveChanges();
/* Create the encrypter and encrypt the message */
System.out.println("Encrypting Mime Message");
SMIMEEnvelopedGenerator fact = new SMIMEEnvelopedGenerator();
fact.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator((X509Certificate) chain[0]).setProvider("BC"));
MimeBodyPart encryptedPart = fact.generate(signedMessage, new JceCMSContentEncryptorBuilder(CMSAlgorithm.RC2_CBC, 40)
.setProvider("BC").build());
encryptedPart.setHeader("Content-Transfer-Encoding", "binary");
ByteArrayOutputStream out = new ByteArrayOutputStream();
encryptedPart.writeTo(out);
/* Create a new MimeMessage for the encrypted and signed content */
System.out.println("Setting mail server properties");
Properties props = new Properties();
props.put("mail.smtp.host", host);
props.put("mail.smtp.port", port);
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.starttls.enable", "true");
Session smtpSession = Session.getInstance(props, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(userName, password);
}
});
MimeMessage smtpMessage = new MimeMessage(smtpSession, new ByteArrayInputStream(out.toByteArray()));
smtpMessage.saveChanges();
/* Set all original MIME headers in the encrypted message */
@SuppressWarnings("unchecked")
Enumeration<String> orgHeaders = body.getAllHeaderLines();
while (orgHeaders.hasMoreElements()) {
String headerLine = (String) orgHeaders.nextElement();
/* Do not override content-* headers from the original message */
if (!Strings.toLowerCase(headerLine).startsWith("content-")) {
smtpMessage.addHeaderLine(headerLine);
}
}
System.out.println("Creating eml file as location: " + outputFile);
smtpMessage.writeTo(new FileOutputStream(outputFile));
System.out.println("Sending Mail");
Transport.send(smtpMessage);
System.out.println("Mail Sent");
} catch (SMIMEException ex) {
ex.getUnderlyingException().printStackTrace(System.err);
ex.printStackTrace(System.err);
} catch (Exception ex) {
ex.printStackTrace(System.err);
}
}
}
请帮忙!!!
问候