diff options
Diffstat (limited to 'OpenPGP-Keychain')
12 files changed, 501 insertions, 96 deletions
diff --git a/OpenPGP-Keychain/res/layout/import_keys_clipboard_fragment.xml b/OpenPGP-Keychain/res/layout/import_keys_clipboard_fragment.xml new file mode 100644 index 000000000..bb3b8a1cb --- /dev/null +++ b/OpenPGP-Keychain/res/layout/import_keys_clipboard_fragment.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" +    android:layout_width="fill_parent" +    android:layout_height="wrap_content" +    android:orientation="horizontal" > + +    <Button +        android:id="@+id/import_clipboard_button" +        android:layout_width="match_parent" +        android:layout_height="wrap_content" +        android:text="@string/import_from_clipboard" /> + +</LinearLayout>
\ No newline at end of file diff --git a/OpenPGP-Keychain/res/values/arrays.xml b/OpenPGP-Keychain/res/values/arrays.xml index dc9de0f38..aca70c488 100644 --- a/OpenPGP-Keychain/res/values/arrays.xml +++ b/OpenPGP-Keychain/res/values/arrays.xml @@ -53,6 +53,7 @@          <item>@string/menu_importFromFile</item>          <item>@string/menu_keyServer</item>          <item>@string/menu_importFromQrCode</item> +        <item>@string/import_from_clipboard</item>          <item>@string/menu_importFromNfc</item>      </string-array> diff --git a/OpenPGP-Keychain/res/values/strings.xml b/OpenPGP-Keychain/res/values/strings.xml index f8d1f6216..fb799cd14 100644 --- a/OpenPGP-Keychain/res/values/strings.xml +++ b/OpenPGP-Keychain/res/values/strings.xml @@ -351,6 +351,7 @@      <string name="import_import">Import selected keys</string>      <string name="import_sign_and_upload">Import, Sign, and upload selected keys</string>      <string name="import_finish">Finish</string> +    <string name="import_from_clipboard">Import from Clipboard</string>      <!-- Intent labels -->      <string name="intent_decrypt_file">OpenPGP: Decrypt File</string> diff --git a/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpCallback.aidl b/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpCallback.aidl index ca00c8ce1..ba41de1ba 100644 --- a/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpCallback.aidl +++ b/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpCallback.aidl @@ -16,6 +16,7 @@  package org.openintents.openpgp; +import org.openintents.openpgp.OpenPgpData;  import org.openintents.openpgp.OpenPgpSignatureResult;  import org.openintents.openpgp.OpenPgpError; @@ -24,14 +25,14 @@ interface IOpenPgpCallback {      /**       * onSuccess returns on successful OpenPGP operations.       *  -     * @param outputBytes -     *            contains resulting output bytes (decrypted content (when input was encrypted) +     * @param output +     *            contains resulting output (decrypted content (when input was encrypted)       *            or content without signature (when input was signed-only))       * @param signatureResult       *            signatureResult is only non-null if decryptAndVerify() was called and the content       *            was encrypted or signed-and-encrypted.       */ -    oneway void onSuccess(in byte[] outputBytes, in OpenPgpSignatureResult signatureResult); +    oneway void onSuccess(in OpenPgpData output, in OpenPgpSignatureResult signatureResult);      /**       * onError returns on errors or when allowUserInteraction was set to false, but user interaction diff --git a/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpKeyIdsCallback.aidl b/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpKeyIdsCallback.aidl new file mode 100644 index 000000000..4ca356fad --- /dev/null +++ b/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpKeyIdsCallback.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openintents.openpgp; + +import org.openintents.openpgp.OpenPgpError; + +interface IOpenPgpKeyIdsCallback { +     +    /** +     * onSuccess returns on successful getKeyIds operations. +     *  +     * @param keyIds +     *            returned key ids +     */ +    oneway void onSuccess(in long[] keyIds); + +    /** +     * onError returns on errors or when allowUserInteraction was set to false, but user interaction +     * was required execute an OpenPGP operation. +     *  +     * @param error +     *            See OpenPgpError class for more information. +     */ +    oneway void onError(in OpenPgpError error); +}
\ No newline at end of file diff --git a/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpService.aidl b/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpService.aidl index ab7ec8b1a..69a608dc6 100644 --- a/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpService.aidl +++ b/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpService.aidl @@ -16,7 +16,9 @@  package org.openintents.openpgp; +import org.openintents.openpgp.OpenPgpData;  import org.openintents.openpgp.IOpenPgpCallback; +import org.openintents.openpgp.IOpenPgpKeyIdsCallback;  /**   * All methods are oneway, which means they are asynchronous and non-blocking. @@ -29,54 +31,76 @@ interface IOpenPgpService {       *        * After successful encryption, callback's onSuccess will contain the resulting output bytes.       *  -     * @param inputBytes -     *            Byte array you want to encrypt -     * @param encryptionUserIds -     *            User Ids (emails) of recipients -     * @param asciiArmor -     *            Encode result for ASCII (Radix-64, 33 percent overhead compared to binary) -     * @param allowUserInteraction -     *            Allows the OpenPGP Provider to handle missing keys by showing activities +     * @param input +     *            OpenPgpData object containing String, byte[], ParcelFileDescriptor, or Uri +     * @param output +     *            Request output format by defining OpenPgpData object +     *             +     *            new OpenPgpData(OpenPgpData.TYPE_STRING) +     *                Returns as String +     *                (OpenPGP Radix-64, 33 percent overhead compared to binary, see http://tools.ietf.org/html/rfc4880#page-53) +     *            new OpenPgpData(OpenPgpData.TYPE_BYTE_ARRAY) +     *                Returns as byte[] +     *            new OpenPgpData(uri) +     *                Writes output to given Uri +     *            new OpenPgpData(fileDescriptor) +     *                Writes output to given ParcelFileDescriptor +     * @param keyIds +     *            Key Ids of recipients. Can be retrieved with getKeyIds()       * @param callback       *            Callback where to return results       */ -    oneway void encrypt(in byte[] inputBytes, in String[] encryptionUserIds, in boolean asciiArmor, -            in IOpenPgpCallback callback); +    oneway void encrypt(in OpenPgpData input, in OpenPgpData output, in long[] keyIds, in IOpenPgpCallback callback);      /**       * Sign       *        * After successful signing, callback's onSuccess will contain the resulting output bytes.       * -     * @param inputBytes -     *            Byte array you want to sign -     * @param asciiArmor -     *            Encode result for ASCII (Radix-64, 33 percent overhead compared to binary) -     * @param allowUserInteraction -     *            Allows the OpenPGP Provider to handle missing keys by showing activities +     * @param input +     *            OpenPgpData object containing String, byte[], ParcelFileDescriptor, or Uri +     * @param output +     *            Request output format by defining OpenPgpData object +     *             +     *            new OpenPgpData(OpenPgpData.TYPE_STRING) +     *                Returns as String +     *                (OpenPGP Radix-64, 33 percent overhead compared to binary, see http://tools.ietf.org/html/rfc4880#page-53) +     *            new OpenPgpData(OpenPgpData.TYPE_BYTE_ARRAY) +     *                Returns as byte[] +     *            new OpenPgpData(uri) +     *                Writes output to given Uri +     *            new OpenPgpData(fileDescriptor) +     *                Writes output to given ParcelFileDescriptor       * @param callback       *            Callback where to return results       */ -    oneway void sign(in byte[] inputBytes, in boolean asciiArmor, in IOpenPgpCallback callback); +    oneway void sign(in OpenPgpData input, in OpenPgpData output, in IOpenPgpCallback callback);      /**       * Sign then encrypt       *        * After successful signing and encryption, callback's onSuccess will contain the resulting output bytes.       * -     * @param inputBytes -     *            Byte array you want to sign and encrypt -     * @param encryptionUserIds -     *            User Ids (emails) of recipients -     * @param asciiArmor -     *            Encode result for ASCII (Radix-64, 33 percent overhead compared to binary) -     * @param allowUserInteraction -     *            Allows the OpenPGP Provider to handle missing keys by showing activities +     * @param input +     *            OpenPgpData object containing String, byte[], ParcelFileDescriptor, or Uri +     * @param output +     *            Request output format by defining OpenPgpData object +     *             +     *            new OpenPgpData(OpenPgpData.TYPE_STRING) +     *                Returns as String +     *                (OpenPGP Radix-64, 33 percent overhead compared to binary, see http://tools.ietf.org/html/rfc4880#page-53) +     *            new OpenPgpData(OpenPgpData.TYPE_BYTE_ARRAY) +     *                Returns as byte[] +     *            new OpenPgpData(uri) +     *                Writes output to given Uri +     *            new OpenPgpData(fileDescriptor) +     *                Writes output to given ParcelFileDescriptor +     * @param keyIds +     *            Key Ids of recipients. Can be retrieved with getKeyIds()       * @param callback       *            Callback where to return results       */ -    oneway void signAndEncrypt(in byte[] inputBytes, in String[] encryptionUserIds, in boolean asciiArmor, -            in IOpenPgpCallback callback); +    oneway void signAndEncrypt(in OpenPgpData input, in OpenPgpData output, in long[] keyIds, in IOpenPgpCallback callback);      /**       * Decrypts and verifies given input bytes. This methods handles encrypted-only, signed-and-encrypted, @@ -85,15 +109,35 @@ interface IOpenPgpService {       * After successful decryption/verification, callback's onSuccess will contain the resulting output bytes.       * The signatureResult in onSuccess is only non-null if signed-and-encrypted or signed-only inputBytes were given.       *  -     * @param inputBytes -     *            Byte array you want to decrypt and verify -     * @param allowUserInteraction -     *            Allows the OpenPGP Provider to handle missing keys by showing activities +     * @param input +     *            OpenPgpData object containing String, byte[], ParcelFileDescriptor, or Uri +     * @param output +     *            Request output format by defining OpenPgpData object +     *             +     *            new OpenPgpData(OpenPgpData.TYPE_STRING) +     *                Returns as String +     *                (OpenPGP Radix-64, 33 percent overhead compared to binary, see http://tools.ietf.org/html/rfc4880#page-53) +     *            new OpenPgpData(OpenPgpData.TYPE_BYTE_ARRAY) +     *                Returns as byte[] +     *            new OpenPgpData(uri) +     *                Writes output to given Uri +     *            new OpenPgpData(fileDescriptor) +     *                Writes output to given ParcelFileDescriptor       * @param callback       *            Callback where to return results       */ -    oneway void decryptAndVerify(in byte[] inputBytes, in IOpenPgpCallback callback); +    oneway void decryptAndVerify(in OpenPgpData input, in OpenPgpData output, in IOpenPgpCallback callback); -    boolean isKeyAvailable(in String[] userIds); +    /** +     * Get available key ids based on given user ids +     * +     * @param ids +     *            User Ids (emails) of recipients OR key ids +     * @param allowUserInteraction +     *            Enable user interaction to lookup and import unknown keys +     * @param callback +     *            Callback where to return results (different type than callback in other functions!) +     */ +    oneway void getKeyIds(in String[] ids, in boolean allowUserInteraction, in IOpenPgpKeyIdsCallback callback);  }
\ No newline at end of file diff --git a/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpData.aidl b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpData.aidl new file mode 100644 index 000000000..3711e4fb4 --- /dev/null +++ b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpData.aidl @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +  +package org.openintents.openpgp; + +// Declare OpenPgpData so AIDL can find it and knows that it implements the parcelable protocol. +parcelable OpenPgpData;
\ No newline at end of file diff --git a/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpData.java b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpData.java new file mode 100644 index 000000000..064df0f1e --- /dev/null +++ b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpData.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openintents.openpgp; + +import android.net.Uri; +import android.os.Parcel; +import android.os.ParcelFileDescriptor; +import android.os.Parcelable; + +public class OpenPgpData implements Parcelable { +    public static final int TYPE_STRING = 0; +    public static final int TYPE_BYTE_ARRAY = 1; +    public static final int TYPE_FILE_DESCRIPTOR = 2; +    public static final int TYPE_URI = 3; + +    int type; + +    String string; +    byte[] bytes = new byte[0]; +    ParcelFileDescriptor fileDescriptor; +    Uri uri; + +    public int getType() { +        return type; +    } + +    public String getString() { +        return string; +    } + +    public byte[] getBytes() { +        return bytes; +    } + +    public ParcelFileDescriptor getFileDescriptor() { +        return fileDescriptor; +    } + +    public Uri getUri() { +        return uri; +    } + +    public OpenPgpData() { + +    } + +    /** +     * Not a real constructor. This can be used to define requested output type. +     *  +     * @param type +     */ +    public OpenPgpData(int type) { +        this.type = type; +    } + +    public OpenPgpData(String string) { +        this.string = string; +        this.type = TYPE_STRING; +    } + +    public OpenPgpData(byte[] bytes) { +        this.bytes = bytes; +        this.type = TYPE_BYTE_ARRAY; +    } + +    public OpenPgpData(ParcelFileDescriptor fileDescriptor) { +        this.fileDescriptor = fileDescriptor; +        this.type = TYPE_FILE_DESCRIPTOR; +    } + +    public OpenPgpData(Uri uri) { +        this.uri = uri; +        this.type = TYPE_URI; +    } + +    public OpenPgpData(OpenPgpData b) { +        this.string = b.string; +        this.bytes = b.bytes; +        this.fileDescriptor = b.fileDescriptor; +        this.uri = b.uri; +    } + +    public int describeContents() { +        return 0; +    } + +    public void writeToParcel(Parcel dest, int flags) { +        dest.writeString(string); +        dest.writeInt(bytes.length); +        dest.writeByteArray(bytes); +        dest.writeParcelable(fileDescriptor, 0); +        dest.writeParcelable(uri, 0); +    } + +    public static final Creator<OpenPgpData> CREATOR = new Creator<OpenPgpData>() { +        public OpenPgpData createFromParcel(final Parcel source) { +            OpenPgpData vr = new OpenPgpData(); +            vr.string = source.readString(); +            vr.bytes = new byte[source.readInt()]; +            source.readByteArray(vr.bytes); +            vr.fileDescriptor = source.readParcelable(ParcelFileDescriptor.class.getClassLoader()); +            vr.fileDescriptor = source.readParcelable(Uri.class.getClassLoader()); +            return vr; +        } + +        public OpenPgpData[] newArray(final int size) { +            return new OpenPgpData[size]; +        } +    }; + +} diff --git a/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpSignatureResult.java b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpSignatureResult.java index 4446614dd..829f8f8cf 100644 --- a/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpSignatureResult.java +++ b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpSignatureResult.java @@ -25,40 +25,50 @@ public class OpenPgpSignatureResult implements Parcelable {      // successfully verified signature, with trusted public key      public static final int SIGNATURE_SUCCESS_TRUSTED = 1;      // no public key was found for this signature verification +    // you can retrieve the key with +    // getKeys(new String[] {String.valueOf(signatureResult.getKeyId)}, true, callback)      public static final int SIGNATURE_UNKNOWN_PUB_KEY = 2;      // successfully verified signature, but with untrusted public key      public static final int SIGNATURE_SUCCESS_UNTRUSTED = 3; -    int signatureStatus; -    String signatureUserId; +    int status;      boolean signatureOnly; +    String userId; +    long keyId; -    public int getSignatureStatus() { -        return signatureStatus; -    } - -    public String getSignatureUserId() { -        return signatureUserId; +    public int getStatus() { +        return status;      }      public boolean isSignatureOnly() {          return signatureOnly;      } +    public String getUserId() { +        return userId; +    } + +    public long getKeyId() { +        return keyId; +    } +      public OpenPgpSignatureResult() {      } -    public OpenPgpSignatureResult(int signatureStatus, String signatureUserId, boolean signatureOnly) { -        this.signatureStatus = signatureStatus; -        this.signatureUserId = signatureUserId; +    public OpenPgpSignatureResult(int signatureStatus, String signatureUserId, +            boolean signatureOnly, long keyId) { +        this.status = signatureStatus;          this.signatureOnly = signatureOnly; +        this.userId = signatureUserId; +        this.keyId = keyId;      }      public OpenPgpSignatureResult(OpenPgpSignatureResult b) { -        this.signatureStatus = b.signatureStatus; -        this.signatureUserId = b.signatureUserId; +        this.status = b.status; +        this.userId = b.userId;          this.signatureOnly = b.signatureOnly; +        this.keyId = b.keyId;      }      public int describeContents() { @@ -66,17 +76,19 @@ public class OpenPgpSignatureResult implements Parcelable {      }      public void writeToParcel(Parcel dest, int flags) { -        dest.writeInt(signatureStatus); -        dest.writeString(signatureUserId); +        dest.writeInt(status);          dest.writeByte((byte) (signatureOnly ? 1 : 0)); +        dest.writeString(userId); +        dest.writeLong(keyId);      }      public static final Creator<OpenPgpSignatureResult> CREATOR = new Creator<OpenPgpSignatureResult>() {          public OpenPgpSignatureResult createFromParcel(final Parcel source) {              OpenPgpSignatureResult vr = new OpenPgpSignatureResult(); -            vr.signatureStatus = source.readInt(); -            vr.signatureUserId = source.readString(); +            vr.status = source.readInt();              vr.signatureOnly = source.readByte() == 1; +            vr.userId = source.readString(); +            vr.keyId = source.readLong();              return vr;          } @@ -88,9 +100,10 @@ public class OpenPgpSignatureResult implements Parcelable {      @Override      public String toString() {          String out = new String(); -        out += "\nsignatureStatus: " + signatureStatus; -        out += "\nsignatureUserId: " + signatureUserId; +        out += "\nstatus: " + status; +        out += "\nuserId: " + userId;          out += "\nsignatureOnly: " + signatureOnly; +        out += "\nkeyId: " + keyId;          return out;      } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java index 50e49a2ab..9f302459c 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java @@ -25,9 +25,12 @@ import java.util.ArrayList;  import java.util.regex.Matcher;  import org.openintents.openpgp.IOpenPgpCallback; +import org.openintents.openpgp.IOpenPgpKeyIdsCallback;  import org.openintents.openpgp.IOpenPgpService; +import org.openintents.openpgp.OpenPgpData;  import org.openintents.openpgp.OpenPgpError;  import org.openintents.openpgp.OpenPgpSignatureResult; +import org.spongycastle.util.Arrays;  import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.Id;  import org.sufficientlysecure.keychain.R; @@ -114,8 +117,8 @@ public class OpenPgpService extends RemoteService {       * @param encryptionUserIds       * @return       */ -    private long[] getKeyIdsFromEmails(String[] encryptionUserIds, long ownKeyId, -            boolean allowUserInteraction) throws UserInteractionRequiredException { +    private long[] getKeyIdsFromEmails(String[] encryptionUserIds, boolean allowUserInteraction) +            throws UserInteractionRequiredException {          // find key ids to given emails in database          ArrayList<Long> keyIds = new ArrayList<Long>(); @@ -142,9 +145,6 @@ public class OpenPgpService extends RemoteService {              }          } -        // also encrypt to our self (so that we can decrypt it later!) -        keyIds.add(ownKeyId); -          // convert to long[]          long[] keyIdsArray = new long[keyIds.size()];          for (int i = 0; i < keyIdsArray.length; i++) { @@ -215,24 +215,47 @@ public class OpenPgpService extends RemoteService {          }      }; -    private synchronized void encryptAndSignSafe(byte[] inputBytes, String[] encryptionUserIds, -            boolean asciiArmor, boolean allowUserInteraction, IOpenPgpCallback callback, -            AppSettings appSettings, boolean sign) { +    private synchronized void getKeyIdsSafe(String[] userIds, boolean allowUserInteraction, +            IOpenPgpKeyIdsCallback callback, AppSettings appSettings) {          try { +            long[] keyIds = getKeyIdsFromEmails(userIds, allowUserInteraction); +            if (keyIds == null) { +                throw new NoUserIdsException("No user ids!"); +            } + +            callback.onSuccess(keyIds); +        } catch (UserInteractionRequiredException e) { +            callbackOpenPgpError(callback, OpenPgpError.USER_INTERACTION_REQUIRED, e.getMessage()); +        } catch (NoUserIdsException e) { +            callbackOpenPgpError(callback, OpenPgpError.NO_USER_IDS, e.getMessage()); +        } catch (Exception e) { +            callbackOpenPgpError(callback, OpenPgpError.GENERIC_ERROR, e.getMessage()); +        } +    } + +    private synchronized void encryptAndSignSafe(OpenPgpData inputData, +            final OpenPgpData outputData, long[] keyIds, boolean allowUserInteraction, +            IOpenPgpCallback callback, AppSettings appSettings, boolean sign) { +        try { +            // TODO: other options of OpenPgpData! +            byte[] inputBytes = getInput(inputData); +            boolean asciiArmor = false; +            if (outputData.getType() == OpenPgpData.TYPE_STRING) { +                asciiArmor = true; +            } + +            // add own key for encryption +            keyIds = Arrays.copyOf(keyIds, keyIds.length + 1); +            keyIds[keyIds.length - 1] = appSettings.getKeyId(); +              // build InputData and write into OutputStream              InputStream inputStream = new ByteArrayInputStream(inputBytes);              long inputLength = inputBytes.length; -            InputData inputData = new InputData(inputStream, inputLength); +            InputData inputDt = new InputData(inputStream, inputLength);              OutputStream outputStream = new ByteArrayOutputStream(); -            long[] keyIds = getKeyIdsFromEmails(encryptionUserIds, appSettings.getKeyId(), -                    allowUserInteraction); -            if (keyIds == null) { -                throw new NoUserIdsException("No user ids!"); -            } - -            PgpOperation operation = new PgpOperation(getContext(), null, inputData, outputStream); +            PgpOperation operation = new PgpOperation(getContext(), null, inputDt, outputStream);              if (sign) {                  String passphrase = getCachedPassphrase(appSettings.getKeyId(),                          allowUserInteraction); @@ -253,12 +276,17 @@ public class OpenPgpService extends RemoteService {              byte[] outputBytes = ((ByteArrayOutputStream) outputStream).toByteArray(); +            OpenPgpData output = null; +            if (asciiArmor) { +                output = new OpenPgpData(new String(outputBytes)); +            } else { +                output = new OpenPgpData(outputBytes); +            } +              // return over handler on client side -            callback.onSuccess(outputBytes, null); +            callback.onSuccess(output, null);          } catch (UserInteractionRequiredException e) {              callbackOpenPgpError(callback, OpenPgpError.USER_INTERACTION_REQUIRED, e.getMessage()); -        } catch (NoUserIdsException e) { -            callbackOpenPgpError(callback, OpenPgpError.NO_USER_IDS, e.getMessage());          } catch (WrongPassphraseException e) {              callbackOpenPgpError(callback, OpenPgpError.NO_OR_WRONG_PASSPHRASE, e.getMessage());          } catch (Exception e) { @@ -289,9 +317,10 @@ public class OpenPgpService extends RemoteService {              outputStream.close();              byte[] outputBytes = ((ByteArrayOutputStream) outputStream).toByteArray(); +            OpenPgpData output = new OpenPgpData(new String(outputBytes));              // return over handler on client side -            callback.onSuccess(outputBytes, null); +            callback.onSuccess(output, null);          } catch (UserInteractionRequiredException e) {              callbackOpenPgpError(callback, OpenPgpError.USER_INTERACTION_REQUIRED, e.getMessage());          } catch (WrongPassphraseException e) { @@ -406,8 +435,8 @@ public class OpenPgpService extends RemoteService {              OpenPgpSignatureResult sigResult = null;              if (signature) { -                // long signatureKeyId = outputBundle -                // .getLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID); +                long signatureKeyId = outputBundle +                        .getLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID);                  String signatureUserId = outputBundle                          .getString(KeychainIntentService.RESULT_SIGNATURE_USER_ID);                  boolean signatureSuccess = outputBundle @@ -422,11 +451,13 @@ public class OpenPgpService extends RemoteService {                      signatureStatus = OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY;                  } -                sigResult = new OpenPgpSignatureResult(signatureStatus, signatureUserId, signedOnly); +                sigResult = new OpenPgpSignatureResult(signatureStatus, signatureUserId, +                        signedOnly, signatureKeyId);              } +            OpenPgpData output = new OpenPgpData(new String(outputBytes));              // return over handler on client side -            callback.onSuccess(outputBytes, sigResult); +            callback.onSuccess(output, sigResult);          } catch (UserInteractionRequiredException e) {              callbackOpenPgpError(callback, OpenPgpError.USER_INTERACTION_REQUIRED, e.getMessage());          } catch (WrongPassphraseException e) { @@ -452,18 +483,26 @@ public class OpenPgpService extends RemoteService {          }      } +    private void callbackOpenPgpError(IOpenPgpKeyIdsCallback callback, int errorId, String message) { +        try { +            callback.onError(new OpenPgpError(0, message)); +        } catch (Exception t) { +            Log.e(Constants.TAG, +                    "Exception while returning OpenPgpError to client via callback.onError()", t); +        } +    } +      private final IOpenPgpService.Stub mBinder = new IOpenPgpService.Stub() {          @Override -        public void encrypt(final byte[] inputBytes, final String[] encryptionUserIds, -                final boolean asciiArmor, final IOpenPgpCallback callback) throws RemoteException { +        public void encrypt(final OpenPgpData input, final OpenPgpData output, final long[] keyIds, +                final IOpenPgpCallback callback) throws RemoteException {              final AppSettings settings = getAppSettings();              Runnable r = new Runnable() {                  @Override                  public void run() { -                    encryptAndSignSafe(inputBytes, encryptionUserIds, asciiArmor, true, callback, -                            settings, false); +                    encryptAndSignSafe(input, output, keyIds, true, callback, settings, false);                  }              }; @@ -471,15 +510,14 @@ public class OpenPgpService extends RemoteService {          }          @Override -        public void signAndEncrypt(final byte[] inputBytes, final String[] encryptionUserIds, -                final boolean asciiArmor, final IOpenPgpCallback callback) throws RemoteException { +        public void signAndEncrypt(final OpenPgpData input, final OpenPgpData output, +                final long[] keyIds, final IOpenPgpCallback callback) throws RemoteException {              final AppSettings settings = getAppSettings();              Runnable r = new Runnable() {                  @Override                  public void run() { -                    encryptAndSignSafe(inputBytes, encryptionUserIds, asciiArmor, true, callback, -                            settings, true); +                    encryptAndSignSafe(input, output, keyIds, true, callback, settings, true);                  }              }; @@ -487,14 +525,14 @@ public class OpenPgpService extends RemoteService {          }          @Override -        public void sign(final byte[] inputBytes, boolean asciiArmor, +        public void sign(final OpenPgpData input, final OpenPgpData output,                  final IOpenPgpCallback callback) throws RemoteException {              final AppSettings settings = getAppSettings();              Runnable r = new Runnable() {                  @Override                  public void run() { -                    signSafe(inputBytes, true, callback, settings); +                    signSafe(getInput(input), true, callback, settings);                  }              }; @@ -502,15 +540,15 @@ public class OpenPgpService extends RemoteService {          }          @Override -        public void decryptAndVerify(final byte[] inputBytes, final IOpenPgpCallback callback) -                throws RemoteException { +        public void decryptAndVerify(final OpenPgpData input, final OpenPgpData output, +                final IOpenPgpCallback callback) throws RemoteException {              final AppSettings settings = getAppSettings();              Runnable r = new Runnable() {                  @Override                  public void run() { -                    decryptAndVerifySafe(inputBytes, true, callback, settings); +                    decryptAndVerifySafe(getInput(input), true, callback, settings);                  }              }; @@ -518,13 +556,44 @@ public class OpenPgpService extends RemoteService {          }          @Override -        public boolean isKeyAvailable(String[] userIds) throws RemoteException { -            // TODO -            return false; +        public void getKeyIds(final String[] userIds, final boolean allowUserInteraction, +                final IOpenPgpKeyIdsCallback callback) throws RemoteException { + +            final AppSettings settings = getAppSettings(); + +            Runnable r = new Runnable() { +                @Override +                public void run() { +                    getKeyIdsSafe(userIds, allowUserInteraction, callback, settings); +                } +            }; + +            checkAndEnqueue(r);          }      }; +    private static byte[] getInput(OpenPgpData data) { +        // TODO: support Uri and ParcelFileDescriptor + +        byte[] inBytes = null; +        switch (data.getType()) { +        case OpenPgpData.TYPE_STRING: +            inBytes = data.getString().getBytes(); +            break; + +        case OpenPgpData.TYPE_BYTE_ARRAY: +            inBytes = data.getBytes(); +            break; + +        default: +            Log.e(Constants.TAG, "Uri and ParcelFileDescriptor not supported right now!"); +            break; +        } + +        return inBytes; +    } +      @Override      public IBinder onBind(Intent intent) {          return mBinder; diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java index 132e644bc..b9348cdaf 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -166,7 +166,7 @@ public class ImportKeysActivity extends SherlockFragmentActivity implements OnNa              mListFragment = ImportKeysListFragment.newInstance(bytes, filename);              // Add the fragment to the 'fragment_container' FrameLayout -            // NOTE: We use commitAllowingStateLoss() to prevent wierd crashes! +            // NOTE: We use commitAllowingStateLoss() to prevent weird crashes!              getSupportFragmentManager().beginTransaction()                      .replace(R.id.import_keys_list_container, mListFragment)                      .commitAllowingStateLoss(); @@ -189,6 +189,9 @@ public class ImportKeysActivity extends SherlockFragmentActivity implements OnNa              loadFragment(ImportKeysQrCodeFragment.class, null, mNavigationStrings[itemPosition]);              break;          case 3: +            loadFragment(ImportKeysClipboardFragment.class, null, mNavigationStrings[itemPosition]); +            break; +        case 4:              loadFragment(ImportKeysNFCFragment.class, null, mNavigationStrings[itemPosition]);              break; diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysClipboardFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysClipboardFragment.java new file mode 100644 index 000000000..dcb7dbcc6 --- /dev/null +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysClipboardFragment.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +package org.sufficientlysecure.keychain.ui; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.Button; + +public class ImportKeysClipboardFragment extends Fragment { + +    private ImportKeysActivity mImportActivity; +    private Button mButton; + +    /** +     * Creates new instance of this fragment +     */ +    public static ImportKeysClipboardFragment newInstance() { +        ImportKeysClipboardFragment frag = new ImportKeysClipboardFragment(); + +        Bundle args = new Bundle(); +        frag.setArguments(args); + +        return frag; +    } + +    /** +     * Inflate the layout for this fragment +     */ +    @Override +    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { +        View view = inflater.inflate(R.layout.import_keys_clipboard_fragment, container, false); + +        mButton = (Button) view.findViewById(R.id.import_clipboard_button); +        mButton.setOnClickListener(new OnClickListener() { + +            @Override +            public void onClick(View v) { +                CharSequence clipboardText = ClipboardReflection.getClipboardText(getActivity()); + +                mImportActivity.loadCallback(clipboardText.toString().getBytes(), null); +            } +        }); + +        return view; +    } + +    @Override +    public void onActivityCreated(Bundle savedInstanceState) { +        super.onActivityCreated(savedInstanceState); + +        mImportActivity = (ImportKeysActivity) getActivity(); +    } + +}  | 
