title: Encrypt mail with SMIME and X.509 using BouncyCastle
body: <p>I'm trying to send a encrypted mail with <code>JavaMail</code> Library and <code>BouncyCastle</code> Library:</p>
  
  <p>This is the code I've written, or I followed a tutorial:</p>
  
  <pre><code>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() &amp;&amp; (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("") &amp;&amp; !_pass.equals("") &amp;&amp; _to.length &gt; 0
              &amp;&amp; !_from.equals("") &amp;&amp; !_subject.equals("")
              &amp;&amp; !_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 &lt; _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;
  }
  }
  </code></pre>
  
  <p>When I debug the application, the only app crashes at this following line:</p>
  
  <pre><code>SMIMESignedGenerator signer = new SMIMESignedGenerator();
  </code></pre>
  
  <p>This is the only error message I get from dalvik: </p>
  
  <pre><code>DexOpt: unable to optimize static field ref 0x0991 at 0x18 in Lorg/bouncycastle/mail/smime/SMIMESignedGenerator;.&lt;clinit&gt;
  </code></pre>
  
  <p>All of my external <code>.jar</code> files is located under the folder <code>libs</code>.</p>
  
  <p>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? </p>