PGP/MIME in Android


As of version 1.3.2 DidiSoft OpenPGP Library for Android provides a separate JAR file located under [product ZIP]\Library\Mail\pgplib-mail-android-<version>.jar and offering PGP/MIME email functionality.

In this tutorial we will illustrate how to utilize the classes located in the above JAR file in order to exchange PGP/MIME email messages.

Prerequisites: Your Android application will require Internet access permissions in AndroidManifest.xml:

 

Table of contents
1. Setup
2. Sending encrypted email (PGP/MIME)
3. Sending encrypted email (PGP/inline)
4. Receiving encrypted email
5. Sending signed email

Setup

You have to include the JAR files listed below in the class path of your Java application:

[product ZIP archive]\Library\Mail\pgplib-mail-android-x.x.x.jar
[product ZIP archive]\Library\Mail\pgplib-android-x.x.x.jar
[product ZIP archive]\Library\Mail\mail.jar
[product ZIP archive]\Library\Mail\activation.jar
[product ZIP archive]\Library\Mail\additional.jar

2. Sending encrypted email

The main class offering PGP/MIME functionality is com.didisoft.pgp.mail.PGPMailUtils. It provides encrypting methods similar to the ones provided by PGPLib class and works with keys located in files, provided as inline strings or located in a KeyStore.

The example below shows how to produce a javax.mail.internet.MimeMessage in encrypted PGP/MIME format using a public (encryption) key located in a file in the Assets folder of the application:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import java.util.Properties;
import javax.mail.*;
import javax.mail.internet.*;
import com.didisoft.pgp.mail.PGPMailUtils;
 
public class MailSendActivity extends Activity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
 
     StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();        
     StrictMode.setThreadPolicy(policy);
 
     setContentView(R.layout.activity_mail_send); 
 
      // Recipient's email
      String to = "recipient@company.com";
      // Sender email
      String from = "sender@didisoft.com";
 
      Properties properties = System.getProperties();
      properties.setProperty("mail.smtp.host", "mail.didisoft.com");
      properties.setProperty("mail.smtp.port", "25");
 
      properties.setProperty("mail.user", "sender@didisoft.com");
      properties.setProperty("mail.password", "mail password");	      
 
      // Get the default Session object.
      Session session = Session.getDefaultInstance(properties);
 
      try{
         // Create a default MimeMessage object.
         MimeMessage message = new MimeMessage(session);
         message.setFrom(new InternetAddress(from));
         message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
 
         // Set Subject: header field
         message.setSubject("This is the Subject Line!");
 
         // Now set the actual message
         message.setText("This is actual message");
 
         // PGP encrypt here the message
         PGPMailUtils mailUtil = new PGPMailUtils();
         MimeMessage pgpMessage = null;
         InputStream keyStream = null;
         try {
           keyStream = getApplicationContext().getAssets().open("recipient_key.asc"); 
           pgpMessage = mailUtil.encryptMessage(session, message, keyStream);         } finally {
           if (keyStream != null) {
             keyStream.close();
           }
         }
         // Send message
         Transport.send(pgpMessage);
 
         android.util.Log.e("PGP_DEMO", "Email sent", "Message successfully sent");
      }catch (Exception ex) {
         android.util.Log.e("PGP_DEMO", "Error sending email", ex);	         
      }
 }
}

3. Sending encrypted email (PGP/inline)

The PGP/inline email message format is from the early days of PGP version 2.x. Technically it is an email with content type “text/plain” and message body containing the ASCII armored encrypted OpenPGP message. In order to create OpenPGP encrypted message in ASCII armored format we are going to use the com.didisoft.pgp.PGPLib class.

The example below shows how to produce a javax.mail.internet.MimeMessage in PGP/inline format encrypted with a public key located in a file in the Assets folder of the application:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import java.util.Properties;
import javax.mail.*;
import javax.mail.internet.*;
import com.didisoft.pgp.PGPLib;
 
public class MailSendActivity extends Activity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
 
     StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();        
     StrictMode.setThreadPolicy(policy);
 
     setContentView(R.layout.activity_mail_send); 
 
      // Recipient's email
      String to = "recipient@company.com";
      // Sender email
      String from = "sender@didisoft.com";
 
      Properties properties = System.getProperties();
      properties.setProperty("mail.smtp.host", "mail.didisoft.com");
      properties.setProperty("mail.smtp.port", "25");
 
      properties.setProperty("mail.user", "sender@didisoft.com");
      properties.setProperty("mail.password", "mail password");	      
 
      // Get the default Session object.
      Session session = Session.getDefaultInstance(properties);
 
      try{
         // Create a default MimeMessage object.
         MimeMessage message = new MimeMessage(session);
         message.setFrom(new InternetAddress(from));
         message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
 
         // Set Subject: header field
         message.setSubject("This is the Subject Line!");
 
         PGPLib pgp = new PGPLib();
	 String messageText = "This is my email message text \n\r Best Regards";
	 message.setText(pgp.encryptString(messageText, publicKeyFileName)); 
         // Send message
         Transport.send(message);
 
         android.util.Log.e("PGP_DEMO", "Email sent", "Message successfully sent");
      }catch (Exception ex) {
         android.util.Log.e("PGP_DEMO", "Error sending email", ex);	         
      }
 }
}

4. Receiving encrypted mail

The receiving of PGP/MIME encrypted message consists of actually decrypting it and handling the extracted message like an ordinary received mail:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import java.io.IOException;  
import java.util.Properties;  
import javax.activation.DataHandler;
import javax.mail.*;
import javax.mail.internet.*;
import com.sun.mail.pop3.POP3Store;  
 
import com.didisoft.pgp.mail.*;
 
public class ReceiveEncryptedMail {
 
 private boolean textIsHtml = false;
 
 /** Handling MIME parts */	
 private String getText(Part p) throws MessagingException, IOException {
	if (p.isMimeType("text/*")) {
		String s = (String) p.getContent();
		textIsHtml = p.isMimeType("text/html");
		return s;
	}
 
	if (p.isMimeType("multipart/alternative")) {
		// prefer html text over plain text
		Multipart mp = (Multipart) p.getContent();
		String text = null;
		for (int i = 0; i < mp.getCount(); i++) {
			Part bp = mp.getBodyPart(i);
			if (bp.isMimeType("text/plain")) {
				if (text == null)
					text = getText(bp);
				continue;
			} else if (bp.isMimeType("text/html")) {
				String s = getText(bp);
				if (s != null)
					return s;
			} else {
				return getText(bp);
			}
		}
		return text;
	} else if (p.isMimeType("multipart/*")) {
		Multipart mp = (Multipart) p.getContent();
		for (int i = 0; i < mp.getCount(); i++) {
			String s = getText(mp.getBodyPart(i));
			if (s != null)
				return s;
		}
	}
 
	return null;
 }	
 
 public void receiveEmail(String pop3Host, 
				String user, 
				String password) {
 
	 try {
	   Properties properties = new Properties();  
	   properties.put("mail.pop3.host", pop3Host);  
	   Session emailSession = Session.getDefaultInstance(properties);  
 
	   //2) create the POP3 store object and connect with the pop server  
	   POP3Store emailStore = (POP3Store) emailSession.getStore("pop3");  
	   emailStore.connect(user, password);  
 
	   //3) create the folder object and open it  
	   Folder emailFolder = emailStore.getFolder("INBOX");  
	   emailFolder.open(Folder.READ_ONLY);  
 
	   //4) retrieve the messages from the folder in an array and print it  
	   Message[] messages = emailFolder.getMessages();  
	   for (int i = 0; i < messages.length; i++) {  
	    Message message = messages[i];  
 
	    System.out.println("Email Number " + (i + 1));  
	    System.out.println("Subject: " + message.getSubject());  
	    System.out.println("From: " + message.getFrom()[0]);  
 
	    PGPMailUtils mailUtil = new PGPMailUtils();
	    if (mailUtil.isOpenPGPEncrypted(message)) {
 
	    	try {
	    		MimeMessage decrypted = 
                           mailUtil.decryptMessage(emailSession,                                                    (MimeMessage)message, 
                                                   "c:\\PGPKeys\\private_key.asc", 
                                                   "changeit");
 
	    		Object decryptedRawContent = decrypted.getContent(); 
                        if (decryptedRawContent instanceof Multipart) {
                           Multipart multipart = (Multipart) decryptedRawContent;
 
                           BodyPart bodyPart = multipart.getBodyPart(0);
                           String messageText = getText(bodyPart);
 
                           System.out.print("Decrypted message: ");
                           System.out.println(messageText);
 
                           if (mailUtil.hasAttachments(decrypted)) {
                            for (int j = 1; j < multipart.getCount(); j++) {
                             BodyPart attachment = multipart.getBodyPart(j);
 
                             DataHandler handler = attachment.getDataHandler();
                             System.out.println("Attachment file name is : " + handler.getName()); 
                             // save here the file ... ((MimeBodyPart)attachment).saveFile(...)
                           }
                          } 
                      } else {
                      // pgp inline mail with no attachments, just print the decrypted text then
                      String content = decryptedRawContent.toString();
                      System.out.println(content);
                     } 
	    	} catch (Exception e) {
	    		System.out.println(e.getMessage());
	    	}
	    } else if (mailUtil.isOpenPGPSigned(message)) {
	    	// pgp signed only message
	    	MimeBodyPart decrypted = mailUtil.getSignedContent(message);
	        String content = getText(decrypted);
	        System.out.println(content);
	    } else {
	    	System.out.println(message.getContentType());
	    }
	   }  
 
	   //5) close the store and folder objects  
	   emailFolder.close(false);  
	   emailStore.close();  
 
	  } catch (NoSuchProviderException e) {e.printStackTrace();}   
	  catch (MessagingException e) {e.printStackTrace();}  
	  catch (IOException e) {e.printStackTrace();}  
	 }
 
	public static void main(String[] a) {
		ReceiveEncryptedMail receiveDemo = new ReceiveEncryptedMail();
		receiveDemo.receiveEmail("mail.mysite.com", "myname@mysite.com", "my mail password");
	}	
}

5. Sending PGP/MIME signed emails with Java

Here again the whole process consists of constructing the initial email message as it should look like to the recipient and afterwards transforming it to PGP/MIME signed format transparently by invoking PGPMailUtils.signMessage:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import java.util.Properties;
import javax.mail.*;
import javax.mail.internet.*;
import com.didisoft.pgp.mail.PGPMailUtils;
 
public class SendSignedMail {
 
	public static void main(String[] args) {
		  // Recipient's email
	      String to = "recipient@company.com";
	      // Sender email
	      String from = "me@organization.com";
 
	      // SMTP host
	      String host = "mail.organization.com";
 
	      Properties properties = System.getProperties();
	      properties.setProperty("mail.smtp.host", host);
	      properties.setProperty("mail.smtp.port", "25");
 
	      properties.setProperty("mail.user", from);
	      properties.setProperty("mail.password", "my SMTP password");	      
 
	      // Get the default Session object.
	      Session session = Session.getDefaultInstance(properties);
 
	      try{
	         // Create a default MimeMessage object.
	         MimeMessage message = new MimeMessage(session);
	         message.setFrom(new InternetAddress(from));
	         message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
 
	         // Set Subject: header field
	         message.setSubject("This is the Subject Line!");
 
	         // Now set the actual message
	         message.setText("This is the actual message");
 
	         // PGP encrypt here the message
	         PGPMailUtils mailUtil = new PGPMailUtils();
	         String privateKeyFileName = "examples/DataFiles/private.key";
	         String privateKeyPassword = "changeit";
	         MimeMessage pgpMessage = mailUtil.signMessage(session, message, privateKeyFileName, privateKeyPassword); 
	         // Send message
	         Transport.send(pgpMessage);
	         System.out.println("Sent message successfully....");
	      }catch (com.didisoft.pgp.PGPException ex) {
		     ex.printStackTrace(); // PGP error	         
	      }catch (java.io.IOException ex) {
		     ex.printStackTrace(); // I/O error	         
	      }catch (MessagingException mex) {
	         mex.printStackTrace(); // Mail transport error
	      }
	 }
}

Summary

This article demonstrated the basics of the PGP/MIME functionality provided by OpenPGP Library for Android. These functions are provided by the com.didisoft.pgp.mail.PGPMailUtils class located in additional JAR file.