API Sketch¶
AIDL API¶
Update 2015-04-22
- the API library is here: https://github.com/open-keychain/openpgp-api-lib
Update 2014-04-07
Dominik has updated the API to reflect the proposed changes and is getting them merged into K9:
- New API docs: https://github.com/open-keychain/open-keychain/wiki/OpenPGP-API
- New API explanation: https://github.com/siacs/Conversations/issues/43
Updated 2013-12-04
After several iterations with feedback from K9 developers (summary of issues) we propose the following changes.
1. All input/output will be performed with ParcelFileDescriptor
(this makes the current OpenPgpData
class obsolete)
2. All user interaction will be initiated via the consumer/client program via use of PendingIntent
For all operations, the consumer should check to see if a PendingIntent
was returned, indicating user interaction is required. If so, then the consumer must explicitly start the intent to launch the UI and perform the original operation. In the case where user interaction is not required, the operation will be performed and returned asynchronously via the callback.
Example operation: 'sign'¶
Take a sign()
operation for example, the public method signature would be:
oneway void sign(in ParcelFileDescriptor input, in ParcelFileDescriptor output, in IOpenPgpCallback callback);
Case 1: passphrase cached
When called, if the passphrase is cached, and therefore user interaction is not required, the sign operation occurs asynchronously and the result is returned via the provided callback with the data being written to the output
ParcelFileDescriptor
.
Case 2: passphrase not cached
When called, if the passphrase is not cached, and therefore user interaction is required, then the openpgp provider service will return a PendingIntent
via the provided callback. With this PendingIntent
the consumer application can call startActivity()
when appropriate. This will launch the necessary Activity to prompt the passphrase from the user, then the original sign()
operation will be performed. Again, the result is returned via the provided callback with the data being written to the output
ParcelFileDescriptor
.
Open Questions¶
- Should the consumer/client pass the
ParcelFileDescriptor
or should the provider return one in the callback? - Is a
ParcelFileDescriptor
really the correct choice, always? What if the client just wants to pass abyte[]
or simpleInputStream
? - According to the answer to this SO question, we can't pass ParcelFileDescriptors in a service method..?
Discussions¶
- 2013-05-12 |k-9-dev| Rejected new OpenPGP/Crypto Providers
- 2013-09-10 |k-9-dev| OpenPGP Keychain 2.1 with new API
- 2013-09-15 |k-9-dev| OpenPGP Provider API
- 2013-10-04 chat between Dominik and Hans
- 2013-10-04 |k-9-dev| thoughts related to Dominik/Hans chat
- 2013-12-04 Abel and Dominik discussing OpenPGP API
- 2013-12-04 Summary of current API and K9 blockers
- 2013-12-04 more OpenPGP API discussion on IRC
- |guardian-dev| InputStreams across Services
- |guardian-dev| Blockers w/ OpenPGP API and K9
- 2014-01-23 ParcelFileDescriptor comments in IRC
Intent API¶
- @function@, arguments, return value
------------------------------------ SELECT_KEYS
, send name/email/keyid/etc., search then receive all matching private/public keyids or null (maybeSELECT_KEYS
should use the standardACTION_GET_CONTENT
, should understandEXTRA_EMAIL
)FIND_KEYS_OR_PROMPT
, send name/email/keyid/etc., search then receive matching keys (unless there is a single match, this will prompt with an Activity to choose the key, or try another search, then return whichever key was chosen by the user, should understandEXTRA_EMAIL
. maybe it should use the standardACTION_SEARCH
orACTION_PICK
)SIGN
, send data/text/fileUri, receive signature blobVEFIFY
, send data/text/fileUri, receive verified statusENCRYPT
, send data/text/fileUri and optional signing key, receive encrypted, signed data/text/fileUriDECRYPT
, send encrypted data/text/fileUri, receive unencrypted data and verified statusQUERY_TRUST
, send keyid, receive trust info (or maybe trust should only be sent back as part of verify, encrypt, etc, or maybeSELECT_KEYS
orFIND_KEYS_OR_PROMPT
)
Return Values¶
userID
- a 3 element string array of Name, Email, CommentkeyID
- along
of the last 64-bits of the key fingerprint (aka the last 16 hex chars)
General Ideas¶
- ASCII or binary return is specified by an EXTRA flag
- should use standard
EXTRA_STREAM
,EXTRA_TEXT
,EXTRA_UID
, etc. - respect
EXTRA_LOCAL_ONLY
to prevent searches on keyservers, etc.
AIDL vs Intents¶
In this comparison, we are assuming the same user experience. So for example, we expect the OpenPGP app to handle the passphrase prompting entirely, and the app using the crypto API is entirely ignore of it. The OpenPGP app should also provide the key selection and management.
AIDL¶
+ Java-ish method calls and event handling
+ private data transfer
- AIDL talks to Service
so natural Activity
flow must be manually coded
Intents¶
+ preserves natural Activity
flow when GPGapp handles pinentry, etc.
- world readable data transfer
references¶
Permissions Considerations¶
There might need to be a permission for controlling access to the keyring, along the lines of android.permission.READ_CONTACTS
, otherwise we'll be leaking the contacts info, in effect. Apps would not need to use that permission for encrypting and signing if the exact key id is provided, but that would probably be of limited use.
READ_KEYS
- read/search the public key information from the entire keyring
Key Data ContentProvider¶
Inspired by the APG ContentProvider
, there is a ContentProvider included in gpgcli. You can either select a specific key using its 16 hex char KeyID (e.g. DEADBEEFDECAFBAD or 978234D82FFF34AD). This will return a single key or null:
content://info.guardianproject.gpg/keys/secret/key_id/
content://info.guardianproject.gpg/keys/public/key_id/
Or you can search by email address, which will return an array of all matches, or null if there are none:
content://info.guardianproject.gpg/keys/secret/email/
content://info.guardianproject.gpg/keys/public/email/
The data available for selecting with the projection map are:
key_id
name
email
fingerprint
comment
MIME Types¶
These are the MIME Types of the data returned from the Cursor
:
- PUBLIC_KEY_CONTENT_DIR_TYPE = "vnd.android.cursor.dir/vnd.info.guardianproject.gpg.public_key";
- PUBLIC_KEY_CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.info.guardianproject.gpg.public_key";
- SECRET_KEY_CONTENT_DIR_TYPE = "vnd.android.cursor.dir/vnd.info.guardianproject.gpg.secret_key";
- SECRET_KEY_CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.info.guardianproject.gpg.secret_key";
Other methods for doing things:¶
- import keys via file associations (
.asc
,.gpg
, etc.) - import keys via GPG UI via QR, NFC, file import, etc.
AIDL Remote Service¶
- expose
gpg-agent
key agent functionality for X.509, HTTPS client certs, etc.
Others¶
APG Intent API [1]¶
org.thialfihar.android.apg.intent.SELECT_PUBLIC_KEYS
EXTRA_SELECTION
, along[]
of keyIds to be pre-selected- returns
Apg.EXTRA_SELECTION
, along[]
of keyIds of the selected public keys - returns
Apg.EXTRA_USER_IDS
, aString[]
of userIds, including name, email, and comment
org.thialfihar.android.apg.intent.SELECT_SECRET_KEY
- returns
Apg.EXTRA_KEY_ID
, along
keyId of the selected secret key - returns
Apg.EXTRA_USER_ID
, aString
userId, including name, email, and comment
- returns
org.thialfihar.android.apg.intent.ENCRYPT
org.thialfihar.android.apg.intent.ENCRYPT_FILE
org.thialfihar.android.apg.intent.ENCRYPT_AND_RETURN
org.thialfihar.android.apg.intent.GENERATE_SIGNATURE
- Intent data contains the
Uri
to the file to be encrypted or signed (only used forENCRYPT_FILE
) Apg.EXTRA_SEND_TO
, aString
containing the intended recipient(s)Apg.EXTRA_SUBJECT
, aString
containing the subject of the included messageApg.EXTRA_SIGNATURE_KEY_ID
, thelong keyId
of the key used for signingApg.EXTRA_ENCRYPTION_KEY_IDS
, the array oflong keyIds
of the keys to encrypt toApg.EXTRA_ASCII_ARMOUR
, aboolean
whether the data should be ASCII-armored or notApg.EXTRA_DATA
, thebyte[]
data to be encrypted and/or signedApg.EXTRA_TEXT
ifApg.EXTRA_DATA
is null, thenApg.EXTRA_TEXT
is theString
data to be encrypted and/or signed- returns
Apg.EXTRA_SIGNATURE_TEXT
, ASCII data for the PGP signature - returns
Apg.EXTRA_SIGNATURE_DATA
, binary data for the PGP signature - returns
Apg.EXTRA_ENCRYPTED_MESSAGE
, ASCII data for the encrypted contents - returns
Apg.EXTRA_ENCRYPTED_DATA
, binary data for the encrypted contents - returns
Apg.EXTRA_RESULT_URI
, aUri
to the encrypted file - returns
Apg.EXTRA_ERROR
, the text of any errors that happened during the process
- Intent data contains the
org.thialfihar.android.apg.intent.DECRYPT
org.thialfihar.android.apg.intent.DECRYPT_FILE
org.thialfihar.android.apg.intent.DECRYPT_AND_RETURN
ContentProviders¶
content://org.thialfihar.android.apg.provider/key_rings/public/key_id/
content://org.thialfihar.android.apg.provider/key_rings/public/emails/
content://org.thialfihar.android.apg.provider/key_rings/secret/key_id/
content://org.thialfihar.android.apg.provider/key_rings/secret/emails/
Access to these ContentProviders
is controlled by this permission:
org.thialfihar.android.apg.permission.READ_KEY_DETAILS
OpenPGP-Keychain Intent API [2] [3]¶
org.sufficientlysecure.keychain.action.CREATE_KEYRING
org.sufficientlysecure.keychain.action.DECRYPT
org.sufficientlysecure.keychain.action.DECRYPT_AND_RETURN
org.sufficientlysecure.keychain.action.DECRYPT_FILE
org.sufficientlysecure.keychain.action.DECRYPT_STREAM_AND_RETURN
org.sufficientlysecure.keychain.action.EDIT_KEYRING
org.sufficientlysecure.keychain.action.ENCRYPT
org.sufficientlysecure.keychain.action.ENCRYPT_AND_RETURN
org.sufficientlysecure.keychain.action.ENCRYPT_FILE
org.sufficientlysecure.keychain.action.ENCRYPT_STREAM_AND_RETURN
org.sufficientlysecure.keychain.action.GENERATE_SIGNATURE_AND_RETURN
org.sufficientlysecure.keychain.action.IMPORT
org.sufficientlysecure.keychain.action.IMPORT_FROM_NFC
org.sufficientlysecure.keychain.action.IMPORT_FROM_QR_CODE
org.sufficientlysecure.keychain.action.SELECT_PUBLIC_KEYRINGS
org.sufficientlysecure.keychain.action.SELECT_SECRET_KEYRING
org.sufficientlysecure.keychain.action.SHARE_KEYRING
org.sufficientlysecure.keychain.action.SHARE_KEYRING_WITH_NFC
org.sufficientlysecure.keychain.action.SHARE_KEYRING_WITH_QR_CODE