BouncyCastle的加密邮件与SMIME和X.509邮件、BouncyCastle、SMIME

2023-09-06 00:41:40 作者:去你外婆家的香蕉皮i

我试图发送加密邮件与的JavaMail 库和 BouncyCastle的库:

I'm trying to send a encrypted mail with JavaMail Library and BouncyCastle Library:

这是在code我已经写了,或者我也跟着教程:

This is the code I've written, or I followed a tutorial:

public class SendMail extends javax.mail.Authenticator {

private String _user;
private String _pass;

private String[] _to;
private String _from;

private String _port;
private String _sport;

private String _host;

private String _subject;
private String _body;

private boolean _auth;
private boolean _debuggable;

private Multipart _multipart;
SharedPreferences sharedPrefs;

InputStream privateKeyStoreInputStream;
InputStream publicCertificateInputStream;
InputStream publicKeystoreInputStream;

public static final String ksPassword = "mobile";
Certificate[] chain;
PrivateKey privateKey;
Certificate rcptCert;
CertificateFactory cf;

public SendMail() {

    _user = ""; // username
    _pass = ""; // password
    _from = ""; // email sent from
    _subject = ""; // email subject
    _body = ""; // email body

    _debuggable = false; // debug mode on or off - default off
    _auth = true; // smtp authentication - default on

    _multipart = new MimeMultipart();

    // There is something wrong with MailCap, javamail can not find a
    // handler for the multipart/mixed part, so this bit needs to be added.
    MailcapCommandMap mc = (MailcapCommandMap) CommandMap
            .getDefaultCommandMap();
    mc.addMailcap("application/pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_signature");
    mc.addMailcap("application/pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_mime");
    mc.addMailcap("application/x-pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_signature");
    mc.addMailcap("application/x-pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_mime");
    mc.addMailcap("multipart/signed;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.multipart_signed");

    CommandMap.setDefaultCommandMap(mc);

    Security.addProvider(new BouncyCastleProvider());

}

public SendMail(Context c, InputStream privateKeyStoreInputStream,
        InputStream publicCertificateInputStream,
        InputStream publicKeystoreInputStream) {
    this();

    this.privateKeyStoreInputStream = privateKeyStoreInputStream;
    this.publicCertificateInputStream = publicCertificateInputStream;
    this.publicKeystoreInputStream = publicKeystoreInputStream;

    _host = "removed";
    _port = "25";
    _sport = "25";
    _user = "removed";
    _pass = "removed";

    try {
        KeyStore keystore = KeyStore.getInstance("PKCS12", "BC");
        keystore.load(privateKeyStoreInputStream, ksPassword.toCharArray());

        Enumeration e = keystore.aliases();
        String keyAlias = null;

        while (e.hasMoreElements() && (keyAlias == null)) {
            String alias = (String) e.nextElement();
            keyAlias = keystore.isKeyEntry(alias) ? alias : null;
        }

        if (keyAlias == null) {
            Log.e("KEY ALIAS: ", "NULL");
            return;
        }

        chain = keystore.getCertificateChain(keyAlias);

        /* Get the private key to sign the message */

        privateKey = (PrivateKey) keystore.getKey(keyAlias,
                ksPassword.toCharArray());

        if (privateKey == null) {
            Log.e("No Private key for: ", keyAlias);
        }

        /* Get the public key of reciepient */
        BufferedInputStream bis = new BufferedInputStream(
                publicCertificateInputStream);
        cf = CertificateFactory.getInstance("X.509");
        rcptCert = cf.generateCertificate(bis);

    } catch (KeyStoreException e) {
        Log.e("KeyStore Exception: ", e.getMessage());
    } catch (NoSuchProviderException e) {
        Log.e("NoSuchProvider Exception: ", e.getMessage());
    } catch (CertificateException ce) {
        Log.e("Certification Exception: ", ce.getMessage());
    } catch (NoSuchAlgorithmException ns) {
        Log.e("NoSuchAlgorithm Exception: ", ns.getMessage());
    } catch (IOException e) {
        Log.e("IO Exception: ", e.getMessage());
    } catch (UnrecoverableKeyException uke) {
        Log.e("UnrecoverableKeyException: ", uke.getMessage());
    }
}

public boolean send() throws Exception {
    Properties props = _setProperties();

    if (!_user.equals("") && !_pass.equals("") && _to.length > 0
            && !_from.equals("") && !_subject.equals("")
            && !_body.equals("")) {

        Session session = Session.getInstance(props,
                new GMailAuthenticator(_user, _pass));

        MimeMessage msg = new MimeMessage(session);

        msg.setFrom(new InternetAddress(_from));

        InternetAddress[] addressTo = new InternetAddress[_to.length];
        for (int i = 0; i < _to.length; i++) {
            addressTo[i] = new InternetAddress(_to[i]);
        }
        msg.setRecipients(MimeMessage.RecipientType.TO, addressTo);

        msg.setSubject(_subject);
        msg.setSentDate(new Date());

        // setup message body
        BodyPart messageBodyPart = new MimeBodyPart();
        messageBodyPart.setText(_body);
        _multipart.addBodyPart(messageBodyPart);

        // Put parts in message
        msg.setContent(_multipart);

        /* Create SMIMESignedGenerator */
        SMIMECapabilityVector capabilities = new SMIMECapabilityVector();
        capabilities.addCapability(SMIMECapability.dES_EDE3_CBC);
        capabilities.addCapability(SMIMECapability.rC2_CBC, 128);
        capabilities.addCapability(SMIMECapability.dES_CBC);

        ASN1EncodableVector attributes = new ASN1EncodableVector();
        // attributes.add(new SMIMEEncryptionKeyPreferenceAttribute(new
        // org.bouncycastle.asn1.cms.IssuerAndSerialNumber(new
        // X509Name(((X509Certificate)chain[0]).getIssuerDN().getName()),
        // ((X509Certificate)chain[0]).getSerialNumber())));
        attributes.add(new SMIMECapabilitiesAttribute(capabilities));

        SMIMESignedGenerator signer = new SMIMESignedGenerator();

        signer.addSigner(
                privateKey,
                (X509Certificate) chain[0],
                "DSA".equals(privateKey.getAlgorithm()) ? SMIMESignedGenerator.DIGEST_SHA1
                        : SMIMESignedGenerator.DIGEST_MD5,
                new AttributeTable(attributes), null);

        /* Add the list of certs to the generator */
        List certList = new ArrayList();
        certList.add(chain[0]);
        CertStore certs = CertStore.getInstance("Collection",
                new CollectionCertStoreParameters(certList), "BC");
        signer.addCertificatesAndCRLs(certs);

        /* Sign the message and copy all headers from original message */
        MimeMultipart multipart = signer.generate(msg, "BC");
        MimeMessage signedMessage = new MimeMessage(session);
        Enumeration headers = msg.getAllHeaderLines();

        while (headers.hasMoreElements()) {
            signedMessage.addHeaderLine((String) headers.nextElement());
        }

        signedMessage.setContent(_multipart);
        signedMessage.saveChanges();

        /* Create the encrypter and encrypt the message */
        SMIMEEnvelopedGenerator encrypter = new SMIMEEnvelopedGenerator();
        encrypter.addKeyTransRecipient((X509Certificate) chain[0]);
        encrypter.addKeyTransRecipient((X509Certificate) rcptCert);

        MimeBodyPart encryptedPart = encrypter.generate(signedMessage,
                SMIMEEnvelopedGenerator.RC2_CBC, 128, "BC");
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        encryptedPart.writeTo(out);

        Session smtpSession = Session.getInstance(props, null);
        MimeMessage smtpMessage = new MimeMessage(smtpSession,
                new ByteArrayInputStream(out.toByteArray()));
        smtpMessage.saveChanges();

        Transport.send(smtpMessage);

        return true;
    } else {
        return false;
    }
}

public void addAttachment(String filename) throws Exception {
    BodyPart messageBodyPart = new MimeBodyPart();
    DataSource source = new FileDataSource(filename);
    messageBodyPart.setDataHandler(new DataHandler(source));
    messageBodyPart.setFileName(filename);

    _multipart.addBodyPart(messageBodyPart);
}

class GMailAuthenticator extends Authenticator {
    String user;
    String pw;

    public GMailAuthenticator(String username, String password) {
        super();
        this.user = username;
        this.pw = password;
    }

    public PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication(user, pw);
    }
}

private Properties _setProperties() {
    Properties props = new Properties();

    props.put("mail.smtp.host", _host);
    props.put("mail.smtp.starttls.enable", "true");
    props.put("mail.smtp.connectiontimeout", "20000"); // timeout with mail
                                                        // 20 sec.

    if (_debuggable) {
        props.put("mail.debug", "true");
    }

    if (_auth) {
        props.put("mail.smtp.auth", "true");
    }

    props.put("mail.smtp.port", _port);
    props.put("mail.smtp.socketFactory.port", _sport);
    props.put("mail.smtp.socketFactory.fallback", "true");

    return props;
}

public String getBody() {
    return _body;
}

public void setBody(String _body) {
    this._body = _body;
}

public void setTo(String[] toArr) {
    this._to = toArr;
}

public void setFrom(String string) {
    this._from = string;
}

public void setSubject(String string) {
    this._subject = string;
}
}

当我调试应用程序,唯一的应用程序崩溃,在此以下行:

When I debug the application, the only app crashes at this following line:

SMIMESignedGenerator signer = new SMIMESignedGenerator();

这是我Dalvik的得到的唯一错误消息:

This is the only error message I get from dalvik:

DexOpt: unable to optimize static field ref 0x0991 at 0x18 in Lorg/bouncycastle/mail/smime/SMIMESignedGenerator;.<clinit>

我所有的外部的.jar 文件所在的文件夹下

All of my external .jar files is located under the folder libs.

是否有人知道为什么会这样?已经有人成功了加密与SMIME / X.509邮件?或者是有一个更简单的方法来做到这一点?

Does anybody know why this happens? Have anybody succeeded encrypting a mail with SMIME/X.509? Or is there a much simpler way to do this?

推荐答案

如果我明白你想实现的,你不只是加密MIME消息,你是签名和加密(并且必须按照这个顺序做)

If I understand what you try to achieve, you are not just encrypting a MIME message, you are signing and encrypting it (and it must be done in that order)

该BouncyCastle的规定为例,签署电子邮件是here 该BouncyCastle的提供的例子来加密电子邮件是here

The BouncyCastle provided example to signing an email is here The BouncyCastle provided example to encrypting an email is here

最后,签订BodyPart的让你一个多部分,你必须包装在一个MimeBodyPart你加密,它可以让你的加密MimeBodyPart你在的MimeMessage插入(见加密例子)

Finally, signing a BodyPart gets you a Multipart that you must wrap in a MimeBodyPart that you encrypt, which gets you an encrypted MimeBodyPart which you "insert" in a MimeMessage (see encryption example)