[guardian-dev] Blockers w/ OpenPGP API and K9
abel at guardianproject.info
Wed Dec 4 09:31:30 EST 2013
This is a short update regarding the status of the OpenPGP Crypto Provider API sent to the
various parties I know are interested :)
The OpenPGP Crypto Provider API is a generic API Android applications can use to perform
OpenPGP operations. It is generic, because it can be implemented a service in a different
application, called the "Provider".
The impetus for this API is to avoid the situation where an application becomes dependent
on a specific version of an OpenPGP provider, like happened with K9 Mail and APG. Since
APG was abandoned K9 effectively lost it's PGP feature set.
There are two providers planned, a pure-Java implementation and a Gnupg port to Android.
The former already exists  developed by Dominik Schürmann  who also did the majority
of the work on the API, with input from our own Hans and K9 devs. The second (planned)
implementation is Guardian Project's Gnupg port.
Consumers of the API, such as K9, simply register with the Provider, and shoot of
operations over an AIDL interface to the remote service running the Provider.
The API exists under the org.openintents.openpgp namespace .
K9 was always the first intended recipient of this API (though it turns out other folks
have already implemented it), so Dominik met with cketti, a primary K9 dev, and identified
a few blockers that must be resolved before K9 will implement the API.
Attached (openpgp-api-notes.txt) is a list of notes from that conversation.
The two primary blockers that involve fundamental changes to the API (as hashed out
between Dominik and cketti)
1. Lack of ParcelFileDescriptor use
K9 devs want to use ParcelFileDescriptor for IPC instead of the OpenPGPData  class.
This is a fundamental change, but in the end will make things simpler. Overall it should
be somewhat simple to implement.
2. OpenPGP service launches activities from its background service
The OpenPGP Crypto Provider is expected to implement various UIs when necessary to
retrieve user input, e.g., choosing a key from a list of keys, entering the passphrase, etc.
In the current iteration, all UIs are launched by the provider's background service.
This breaks the Android activity task and the back button behavior.
Moreover, the K9 devs want to be able to control when to show UIs in a more controlled
manner, such as when the device is locked or the app is doing some other long-running
By returning prepared PendingIntent's to the consumer app we can achieve this feature.
Apparently other Google's account manager and billing API does something similar.
This is also a fundamental change to the API, and unlike #1 will involve quite a bit of
More detailed discussion of these two blockers can be found in the chat log between
Dominik and I (openpgp-api-convo.txt).
-------------- next part --------------
+ prefix fields with "m"
+ wrap Log.d in "if (K9.DEBUG)"
+ Parcelable versioning
+ write tests to make sure regexp patterns to extract encrypted/signed message work
+ only match when header/footer begin the line
+ isAvailable: IOpenPgpService.class.getName()
-> hardcode intent action so the package can be renamed
+ isAvailable: check if matches are services. compare to OpenPgpListPreference
+ uppercase constants
+ remove constructor
+ make constants final
+ extract text extraction code to separate method (isEncrypted + isSigned)
+ BETTER: combine those two methods since they're never called separately
+ prefix OpenPGP-related strings with openpgp_ ?
+ abstract crypto provider interface
- crypto settings: Auto-sign + Auto-encrypt stay disabled when changing 'OpenPGP Provider' from "None" to something else
- OpenPgpListPreference: use only one icon size
- OpenPGP Keychain: 'Allow access?' screen doesn't scroll
- new message, check sign, click send, allow access, access granted, back in compose screen. should be: start sending message
ideas for improvement:
- create library project/jar for API integration?
- OpenPGP Keychain: show package name of app in 'allow access' screen
- OpenPGP Keychain: add help text telling users to disallow access if they don't know why that screen appeared
- don't request com.fsck.k9.permission.READ_ATTACHMENT
- check openpgp api version in k9mail
- check app package signature
Intents instead of new task from service!
- new task from service breaks activity stack (k9mail -> allow activity -> home -> k9mail hat allow acticity nicht im stack)
- return Intent as error, like accountmanager, and other google apis
- use this
- api 14?
lib with permission own implementation and signature check
intent on http/https against browser uploading in background
- registration wie bei vpn abfrage (siehe openvpn):
häkchen setzen bevor button aktiv wird: Ich vertraue dieser app
-------------- next part --------------
(02:03:42 PM) Dominik: however, I guess you want to talk about openpgp?
(02:04:15 PM) Dominik: just to explain, development was frozen due to my master's thesis ;)
(02:04:26 PM) Abel: indeed, i've a few questions
(02:04:45 PM) Abel: no worries, TBH i'm surprised you did as much as you did given you were working on your thesis too!
(02:04:55 PM) Abel: the api is well developed
(02:05:21 PM) Abel: I'm working in implementing it in our gnupg app, but I had a few questions about the api that I don't think are documented anywhere
(02:05:26 PM) Abel: can you spare a few minutes?
(02:05:52 PM) Dominik: sure, I just want to explain some things before
(02:06:02 PM) Dominik: I met cketti from k9 development team in berlin
(02:06:09 PM) Dominik: some weeks ago
(02:06:58 PM) Abel: sure
(02:06:59 PM) Dominik: and we discussed what changes they want for the API, and actually they want some fundamental changes unfortunately
(02:07:06 PM) Abel: uhoh
(02:07:12 PM) Abel: such as?
(02:07:21 PM) Dominik: I have all notes in a txt files
(02:07:24 PM) Dominik: wait a sec
(02:07:30 PM) Abel: hah glad I talked to you know before sinking a bunch of hours into it
(02:07:41 PM) Dominik: yeah, sry
(02:07:54 PM) Dominik: I wanted to answer the mail nathan sent but found no time
(02:08:08 PM) Abel: we wanted to implement the API in gnupg this week
(02:08:52 PM) Dominik: yeah, hopefully we can get it to a state where k9mail devs accept it
(02:09:49 PM) Dominik: k you got mail
(02:10:02 PM) Dominik: the notes are not very polished
(02:10:08 PM) Dominik: but I hope I can explain all details
(02:11:15 PM) Dominik: the biggest changes are: 1) they propose to use parcelfiledescriptor for in/out streams between the apps
(02:11:45 PM) Dominik: 2) they don't like the idea of starting activities from the background service
(02:12:35 PM) Dominik: the 2. thing is interesting, but I understand their points: - starting from the background does not stack the openpgp activity onto the task stack of k9mail
(02:12:43 PM) Abel: they want to handle all the UI themselves?
(02:12:51 PM) Abel: even things like key listing and choosing keys?
(02:13:15 PM) Abel: using proper flags to startActivity i believe you can push it on the correct task stack
(02:13:41 PM) Abel: herm, though since it is a remote service, i'm not sure
(02:13:58 PM) Dominik: they don't want to develop the activites themselves, they want to get back prepared intents to be executed on demand
(02:14:19 PM) Abel: oh
(02:14:32 PM) Abel: interesting
(02:15:08 PM) Dominik: so for example: if a passphrase is needed the openpgp service should not start the input activity itself, but send back an prepared intent to k9mail
(02:15:29 PM) Dominik: this allows them to postpone pgp activities on demand
(02:15:34 PM) Abel: i see
(02:16:01 PM) Dominik: so for example when something runs in the background as uses pgp service but the phone is locked, they can postpone the intent
(02:16:08 PM) Abel: so, how would the original task (e.g. sign/decrypt) be complete?
(02:16:09 PM) Dominik: r/as/and
(02:16:17 PM) Abel: would openpgp need to cache all "pending" operations
(02:16:35 PM) Abel: or would the prepared intent include the original operation embedded in it too
(02:17:21 PM) Dominik: yes the second approach basically
(02:17:31 PM) Dominik: ah and those intents are PendingIntents
(02:17:38 PM) Abel: yes
(02:17:51 PM) Dominik: Android's accountmanager and the billing api does it similar
(02:18:11 PM) Abel: so the PendingIntent returned would, when executed, prompt for the passphrase and then continue the original operation?
(02:18:21 PM) Dominik: right this is the idea
(02:19:00 PM) Abel: hm, yea i see why this would be desireable
(02:19:23 PM) Abel: unfortunately it is more complicated and does change the current API substanially
(02:19:33 PM) Dominik: it is nice for async operations but it introduced complexity into the remote service
(02:19:36 PM) Dominik: yeah :(
(02:19:44 PM) Abel: as for #1, I'm not so familiar with parcelfiledescriptors
(02:19:55 PM) Dominik: this is why I postponed into after my master's thesis ;)
(02:19:56 PM) Abel: I know they're a way of serializing objects
(02:20:24 PM) Abel: but what's the advantage to the current impl of Parcelable objects?
(02:20:28 PM) Dominik: hm, basically you can do real inputstream's from one app process to another
(02:20:34 PM) Abel: oh
(02:20:44 PM) Abel: that is defnitely useful
(02:20:47 PM) Dominik: so my abstraction with byte arrays and strings would go away
(02:20:50 PM) Abel: but can't the api do this already?
(02:21:01 PM) Abel: OpenPgpData has a ParcelFileDescriptor fileDescriptor;
(02:21:02 PM) Abel: field
(02:21:17 PM) Dominik: I included parcelfiledscriptors yes, but haven't understood them fully to be honest
(02:21:24 PM) Abel: ah
(02:21:43 PM) Dominik: now it's more clear how to use them and it makes OpenPgpData mostly useless
(02:22:18 PM) Abel: But what if you just want to perform an operation on some array of bytes?
(02:22:20 PM) Abel: and not a FD?
(02:22:38 PM) Abel: i guess, you'd wrap it in an inputstream
(02:22:55 PM) Dominik: you can stream the byte by an ByteArrayInputStream
(02:22:57 PM) Dominik: right
(02:23:50 PM) Dominik: I already discussed with Hans about those some month ago and he explained it to me
(02:23:55 PM) Abel: so it seems #1 might simplify things a bit, at the cost of throwing out your previous effort :(
(02:24:17 PM) Dominik: I think guardianproject are using them in sqlcipher or iocipher or so
(02:24:19 PM) Abel: but #2 seems like it will increase the complexity..
(02:24:24 PM) Abel: Indeed, we use them in IOCipher
(02:24:25 PM) Dominik: right
(02:24:49 PM) Abel: i didn't implement that bit though heh, though i've some outstanding TODOs regarding them :(
(02:25:14 PM) Abel: it seems though that #2 should be an option
(02:25:21 PM) Abel: and the current behavior should stick around too
(02:25:22 PM) Abel: no?
(02:25:44 PM) Abel: I can imagine that some devs just want openpgp to handle everything
(02:25:47 PM) Dominik: hmmm it sounded like k9mail devs won't accept until they are satisfied...
(02:26:07 PM) Abel: oh sure i believe that
(02:26:29 PM) Abel: i was just wondering if we want to support #2 as well as the current way, where activities are handled/launched automatically
(02:26:45 PM) Abel: but supporting both might be too much work
(02:26:57 PM) Dominik: hmm not sure about that, it could be an option but then we would have two remote service aidls
(02:27:12 PM) Abel: or a boolean flag in the method calls?
(02:27:48 PM) Dominik: actually I think it's much more work to support both
(02:28:02 PM) Abel: hm yea, the more i think about it.. i agree
(02:28:07 PM) Dominik: I would go with one option currently
(02:28:36 PM) Abel: especially since k9 is the target consumer of this API atm haha
(02:28:45 PM) Dominik: right
(02:29:15 PM) Dominik: I had contact to one guy using the api already for a prototype of xmpp encrypted server push
(02:29:25 PM) Abel: neat
(02:29:50 PM) Dominik: yeah, I hope for more if it goes public and usable
(02:29:52 PM) Dominik: :)
(02:30:07 PM) Abel: hm ok
(02:30:14 PM) Abel: i had a question about AppSettings
(02:30:20 PM) Abel: how does it get/set created?
(02:30:35 PM) Abel: for example i see that the sign() method doesnt include a "signing key id" param
(02:30:40 PM) Dominik: just a quick thing: can you forward our discussion to the other guardianproject people, I am busy until monday...
(02:30:55 PM) Abel: and your impl pulls it from AppSettings.getKeyId()
(02:31:22 PM) Abel: so i was wondering (1) how does AppSettings get set and (2) how you expected the "signing key id" of the sign() operation to be chosen
(02:31:27 PM) Dominik: ah, the first time you use keychain's remote service the appsettings actiivty pops up asking if the user want's to allow access for this app
(02:31:39 PM) Abel: yea i will, mind if i forward this chat log to guardian-dev?
(02:31:54 PM) Dominik: there he/she also needs to choose the private key solely used for this app
(02:31:55 PM) Dominik: sure
(02:32:17 PM) Dominik: I thought this could be a nice feature to restrict app's to specific private keys
(02:32:29 PM) Abel: yea
(02:32:40 PM) Abel: can they choose multiple keys?
(02:32:53 PM) Dominik: curently no unfortunatly
(02:33:03 PM) Abel: hm ok, no worries
(02:33:17 PM) Abel: thats a minority use case i suspect, can be implemented later
(02:33:48 PM) Dominik: ok
(02:34:39 PM) Abel: so ParcelFileDescriptors and this PendingIntent handback technique for activities are the two blockers before k9 will accept the api?
(02:35:04 PM) Dominik: this and a better check for APi version
(02:35:57 PM) Abel: alright
(02:36:01 PM) Dominik: but I don't think this is a blocker like the other
(02:36:02 PM) Dominik: s
(02:36:12 PM) Abel: versioning should be somewhat simple
(02:36:39 PM) Abel: just add a getVersion method, so consumers can check against it
(02:39:41 PM) Dominik: yes
(02:41:56 PM) Abel: hm ok
(02:42:01 PM) Abel: i'll forward this to gp-dev
(02:42:09 PM) Dominik: k
(02:42:28 PM) Abel: thanks for the info :) and good luck with finishing your theses
-------------- next part --------------
A non-text attachment was scrubbed...
Size: 630 bytes
Desc: OpenPGP digital signature
More information about the Guardian-dev