1

我正在尝试从 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);
        }
    }
}

请帮忙!!!

问候

4

1 回答 1

0

听起来您需要将您的私钥(.p12 格式)导入 Outlook 的个人信任库。以下是如何做到这一点:

导入您的个人证书:

从工具菜单中,选择 Internet 选项。打开内容选项卡,然后单击证书。在“证书”窗口中,选择您的证书并单击“导入”。通过证书导入向导导入您的证书文件。浏览正确的文件时,将“文件类型”字段从 *.cer、*.crt 更改为 *.pfx、*.p12。最初导出证书时,系统将提示您输入用于加密私钥的密码。输入它。您将需要选择启用强私钥保护并将此密钥标记为可导出单选按钮。您可以选择所需的任何存储空间。将所有证书放在个人存储中是最简单的。单击完成退出向导。执行导入需要一点时间。弹出一个窗口,说明应用程序正在创建一个受保护的项目,供您选择安全级别。将其保持在中等(默认值)就可以了。单击确定。弹出一个窗口说导入成功。单击确定。

来源:https ://fermi.service-now.com/kb_view.do?sysparm_article=KB0010813

于 2014-11-13T18:08:22.477 回答