OpenPGP API library


Source link: https://github.com/open-keychain/openpgp-api

OpenPGP API library

The OpenPGP API provides methods to execute OpenPGP operations, such as sign, encrypt, decrypt, verify, and more without user interaction from background threads. This is done by connecting your client application to a remote service provided by OpenKeychain or other OpenPGP providers.

News

Version 12

  • OpenPgpDecryptionResult and OpenPgpSignatureResult are now immutable
  • Added PROGRESS_MESSENGER and DATA_LENGTH extras for ACTION_DECRYPT_VERIFY. This allows to the client app to get periodic updates for displaying a progress bar on decryption.
  • Added ACTION_BACKUP
  • Added special API calls for better K-9 Mail integration:
    Check for sender address matching with EXTRA_SENDER_ADDRESS and result in OpenPgpSignatureResult
    Opportunistic encryption mode with EXTRA_OPPORTUNISTIC_ENCRYPTION
    There is an external ContentProvider at org.sufficientlysecure.keychain.provider.exported for querying available keys (CAUTION: This API is not final!)

Full changelog here…

License

While OpenKeychain itself is GPLv3+, the API library is licensed under Apache License v2. Thus, you are allowed to also use it in closed source applications as long as you respect the Apache License v2.

Add the API library to your project

Add this to your build.gradle:

repositories {

  jcenter() 
}
  dependencies {

  compile 'org.sufficientlysecure:openpgp-api:12.0' 
}

Full example

A full working example is available in the example project. The OpenPgpApiActivity.java contains most relevant sourcecode.

API

OpenPgpApi contains all possible Intents and available extras.

Short tutorial

This tutorial only covers the basics, please consult the full example for a complete overview over all methods

The API is not designed around Intents which are started via startActivityForResult. These Intent actions typically start an activity for user interaction, so they are not suitable for background tasks. Most API design decisions are explained at the bottom of this wiki page.

We will go through the basic steps to understand how this API works, following this (greatly simplified) sequence diagram:

In this diagram the client app is depicted on the left side, the OpenPGP provider (in this case OpenKeychain) is depicted on the right. The remote service is defined via the AIDL file IOpenPgpService. It contains only one exposed method which can be invoked remotely:

interface IOpenPgpService {

  Intent execute(in Intent data, in ParcelFileDescriptor input, in ParcelFileDescriptor output);
 
}

The interaction between the apps is done by binding from your client app to the remote service of OpenKeychain. OpenPgpServiceConnection is a helper class from the library to ease this step:

OpenPgpServiceConnection mServiceConnection;  public void onCreate(Bundle savedInstance) {

  [...]
  mServiceConnection = new OpenPgpServiceConnection(this, "org.sufficientlysecure.keychain");

  mServiceConnection.bindToService();
 
}
  public void onDestroy() {

  [...]
  if (mServiceConnection != null) {

mServiceConnection.unbindFromService();

  
}
 
}

Following the sequence diagram, these steps are executed:

  1. Define an Intent containing the actual PGP instructions which should be done, e.g.

    Intent data = new Intent();
     data.setAction(OpenPgpApi.ACTION_ENCRYPT);
     data.putExtra(OpenPgpApi.EXTRA_USER_IDS, new String[]{
    "[email protected]"
    }
    );
     data.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
    

    Define an InputStream currently holding the plaintext, and an OutputStream where you want the ciphertext to be written by OpenKeychain's remote service:

    InputStream is = new ByteArrayInputStream("Hello world!".getBytes("UTF-8"));
     ByteArrayOutputStream os = new ByteArrayOutputStream();
    

    Using a helper class from the library, is and os are passed via ParcelFileDescriptors as input and output together with Intent data, as depicted in the sequence diagram, from the client to the remote service. Programmatically, this can be done with:

    OpenPgpApi api = new OpenPgpApi(this, mServiceConnection.getService());
     Intent result = api.executeApi(data, is, os);
    
  2. The PGP operation is executed by OpenKeychain and the produced ciphertext is written into os which can then be accessed by the client app.

  3. A result Intent is returned containing one of these result codes:

    • OpenPgpApi.RESULT_CODE_ERROR
    • OpenPgpApi.RESULT_CODE_SUCCESS
    • OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED

    If RESULT_CODE_USER_INTERACTION_REQUIRED is returned, an additional PendingIntent is returned to the client, which must be used to get user input required to process the request. A PendingIntent is executed with startIntentSenderForResult, which starts an activity, originally belonging to OpenKeychain, on the task stack of the client. Only if RESULT_CODE_SUCCESS is returned, os actually contains data. A nearly complete example looks like this:

    switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) {
    
      case OpenPgpApi.RESULT_CODE_SUCCESS: {
    
    try {
    
     Log.d(OpenPgpApi.TAG, "output: " + os.toString("UTF-8"));
    
    }
     catch (UnsupportedEncodingException e) {
    
     Log.e(Constants.TAG, "UnsupportedEncodingException", e);
    
    }
    
     if (result.hasExtra(OpenPgpApi.RESULT_SIGNATURE)) {
    
     OpenPgpSignatureResult sigResult
    
    = result.getParcelableExtra(OpenPgpApi.RESULT_SIGNATURE);
    
     [...]
    
    }
    
    break;
      
    }
    
      case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED: {
    
    PendingIntent pi = result.getParcelableExtra(OpenPgpApi.RESULT_INTENT);
    
    try {
    
     startIntentSenderForResult(pi.getIntentSender(), 42, null, 0, 0, 0);
    
    }
     catch (IntentSender.SendIntentException e) {
    
     Log.e(Constants.TAG, "SendIntentException", e);
    
    }
    
    break;
      
    }
    
      case OpenPgpApi.RESULT_CODE_ERROR: {
    
    OpenPgpError error = result.getParcelableExtra(OpenPgpApi.RESULT_ERROR);
    
    [...]
    
    break;
      
    }
     
    }
    
  4. Results from a PendingIntent are returned in onActivityResult of the activity, which executed startIntentSenderForResult. The returned Intent data in onActivityResult contains the original PGP operation definition and new values acquired from the user interaction. Thus, you can now execute the Intent again, like done in step 1. This time it should return with RESULT_CODE_SUCCESS because all required information has been obtained by the previous user interaction stored in this Intent.

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    
      [...]
      // try again after user interaction
      if (resultCode == RESULT_OK) {
    
    switch (requestCode) {
    
     case 42: {
    
      encrypt(data);
     // defined like in step 1
    
      break;
    
     
    }
    
    }
    
      
    }
     
    }
    

Tipps

  • api.executeApi(data, is, os); is a blocking call. If you want a convenient asynchronous call, use api.executeApiAsync(data, is, os, new MyCallback([... ])); , where MyCallback is an private class implementing OpenPgpApi.IOpenPgpCallback. See OpenPgpApiActivity.java for an example.

  • Using

    mServiceConnection = new OpenPgpServiceConnection(this, "org.sufficientlysecure.keychain");
    

    connects to OpenKeychain directly. If you want to let the user choose between OpenPGP providers, you can implement the OpenPgpAppPreference.java like done in the example app.

  • To enable installing a debug and release version at the same time, the debug build of OpenKeychain uses org.sufficientlysecure.keychain.debug as a package name. Make sure you connect to the right one during development!

Resources

SimpleWebWrapper is an Android library which helps you creating Wrappers for Webpages more easier. You just have to configure the main things instead of coding them yourself.

A easy way of using Android SharedPreferences.

RxJava binding APIs for the Palette Android library.

A menu consisting of icons (ImageViews) and metaball bouncing selection to give a blob effect.

This HintSpinnerAdapter allows user to add hint to spinner with very less effor and very effectively. Only thing user need to do is, he has to pass his own spinner adapter to this sample adapter and thats it.

An Android demo of a foldable layout implementation.

Topics


2D Engines   3D Engines   9-Patch   Action Bars   Activities   ADB   Advertisements   Analytics   Animations   ANR   AOP   API   APK   APT   Architecture   Audio   Autocomplete   Background Processing   Backward Compatibility   Badges   Bar Codes   Benchmarking   Bitmaps   Bluetooth   Blur Effects   Bread Crumbs   BRMS   Browser Extensions   Build Systems   Bundles   Buttons   Caching   Camera   Canvas   Cards   Carousels   Changelog   Checkboxes   Cloud Storages   Color Analysis   Color Pickers   Colors   Comet/Push   Compass Sensors   Conferences   Content Providers   Continuous Integration   Crash Reports   Credit Cards   Credits   CSV   Curl/Flip   Data Binding   Data Generators   Data Structures   Database   Database Browsers   Date &   Debugging   Decompilers   Deep Links   Dependency Injections   Design   Design Patterns   Dex   Dialogs   Distributed Computing   Distribution Platforms   Download Managers   Drawables   Emoji   Emulators   EPUB   Equalizers &   Event Buses   Exception Handling   Face Recognition   Feedback &   File System   File/Directory   Fingerprint   Floating Action   Fonts   Forms   Fragments   FRP   FSM   Functional Programming   Gamepads   Games   Geocaching   Gestures   GIF   Glow Pad   Gradle Plugins   Graphics   Grid Views   Highlighting   HTML   HTTP Mocking   Icons   IDE   IDE Plugins   Image Croppers   Image Loaders   Image Pickers   Image Processing   Image Views   Instrumentation   Intents   Job Schedulers   JSON   Keyboard   Kotlin   Layouts   Library Demos   List View   List Views   Localization   Location   Lock Patterns   Logcat   Logging   Mails   Maps   Markdown   Mathematics   Maven Plugins   MBaaS   Media   Menus   Messaging   MIME   Mobile Web   Native Image   Navigation   NDK   Networking   NFC   NoSQL   Number Pickers   OAuth   Object Mocking   OCR Engines   OpenGL   ORM   Other Pickers   Parallax List   Parcelables   Particle Systems   Password Inputs   PDF   Permissions   Physics Engines   Platforms   Plugin Frameworks   Preferences   Progress Indicators   ProGuard   Properties   Protocol Buffer   Pull To   Purchases   Push/Pull   QR Codes   Quick Return   Radio Buttons   Range Bars   Ratings   Recycler Views   Resources   REST   Ripple Effects   RSS   Screenshots   Scripting   Scroll Views   SDK   Search Inputs   Security   Sensors   Services   Showcase Views   Signatures   Sliding Panels   Snackbars   SOAP   Social Networks   Spannable   Spinners   Splash Screens   SSH   Static Analysis   Status Bars   Styling   SVG   System   Tags   Task Managers   TDD &   Template Engines   Testing   Testing Tools   Text Formatting   Text Views   Text Watchers   Text-to   Toasts   Toolkits For   Tools   Tooltips   Trainings   TV   Twitter   Updaters   USB   User Stories   Utils   Validation   Video   View Adapters   View Pagers   Views   Watch Face   Wearable Data   Wearables   Weather   Web Tools   Web Views   WebRTC   WebSockets   Wheel Widgets   Wi-Fi   Widgets   Windows   Wizards   XML   XMPP   YAML   ZIP Codes