Android Privacy Guard (APG) is a OpenPGP implementation for Android.
License: Apache License v2
-
Developer: Thialfihar (Main developer), Senecaso (QRCode, sign key, upload key), Markus Doits (AIDL), Oliver Runge, Dominik Schürmann (Version 2 and up)
+
Developer: Thialfihar (Main developer v1.x), Senecaso (QRCode, sign key, upload key), Markus Doits (AIDL), Oliver Runge, Dominik Schürmann (Developer v2.x)
Libraries
• ActionBarSherlock (Apache License v2)
diff --git a/org_apg/src/org/thialfihar/android/apg/Apg.java b/org_apg/src/org/thialfihar/android/apg/Apg.java
deleted file mode 100644
index 2c939f895..000000000
--- a/org_apg/src/org/thialfihar/android/apg/Apg.java
+++ /dev/null
@@ -1,2333 +0,0 @@
-/*
- * Copyright (C) 2010 Thialfihar
- *
- * 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.thialfihar.android.apg;
-
-import org.spongycastle.bcpg.ArmoredInputStream;
-import org.spongycastle.bcpg.ArmoredOutputStream;
-import org.spongycastle.bcpg.BCPGOutputStream;
-import org.spongycastle.bcpg.CompressionAlgorithmTags;
-import org.spongycastle.bcpg.HashAlgorithmTags;
-import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags;
-import org.spongycastle.bcpg.sig.KeyFlags;
-import org.spongycastle.jce.provider.BouncyCastleProvider;
-import org.spongycastle.jce.spec.ElGamalParameterSpec;
-import org.spongycastle.openpgp.PGPCompressedData;
-import org.spongycastle.openpgp.PGPCompressedDataGenerator;
-import org.spongycastle.openpgp.PGPEncryptedData;
-import org.spongycastle.openpgp.PGPEncryptedDataGenerator;
-import org.spongycastle.openpgp.PGPEncryptedDataList;
-import org.spongycastle.openpgp.PGPException;
-import org.spongycastle.openpgp.PGPKeyPair;
-import org.spongycastle.openpgp.PGPKeyRing;
-import org.spongycastle.openpgp.PGPKeyRingGenerator;
-import org.spongycastle.openpgp.PGPLiteralData;
-import org.spongycastle.openpgp.PGPLiteralDataGenerator;
-import org.spongycastle.openpgp.PGPObjectFactory;
-import org.spongycastle.openpgp.PGPOnePassSignature;
-import org.spongycastle.openpgp.PGPOnePassSignatureList;
-import org.spongycastle.openpgp.PGPPBEEncryptedData;
-import org.spongycastle.openpgp.PGPPrivateKey;
-import org.spongycastle.openpgp.PGPPublicKey;
-import org.spongycastle.openpgp.PGPPublicKeyEncryptedData;
-import org.spongycastle.openpgp.PGPPublicKeyRing;
-import org.spongycastle.openpgp.PGPSecretKey;
-import org.spongycastle.openpgp.PGPSecretKeyRing;
-import org.spongycastle.openpgp.PGPSignature;
-import org.spongycastle.openpgp.PGPSignatureGenerator;
-import org.spongycastle.openpgp.PGPSignatureList;
-import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator;
-import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
-import org.spongycastle.openpgp.PGPUtil;
-import org.spongycastle.openpgp.PGPV3SignatureGenerator;
-import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
-import org.spongycastle.openpgp.operator.PBESecretKeyEncryptor;
-import org.spongycastle.openpgp.operator.PGPContentSignerBuilder;
-import org.spongycastle.openpgp.operator.PGPDigestCalculator;
-import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
-import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
-import org.spongycastle.openpgp.operator.jcajce.JcaPGPKeyPair;
-import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
-import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder;
-import org.thialfihar.android.apg.Id.return_value;
-import org.thialfihar.android.apg.KeyServer.AddKeyException;
-import org.thialfihar.android.apg.passphrase.CachedPassPhrase;
-import org.thialfihar.android.apg.provider.DataProvider;
-import org.thialfihar.android.apg.provider.Database;
-import org.thialfihar.android.apg.provider.KeyRings;
-import org.thialfihar.android.apg.provider.Keys;
-import org.thialfihar.android.apg.provider.UserIds;
-import org.thialfihar.android.apg.ui.BaseActivity;
-import org.thialfihar.android.apg.ui.widget.KeyEditor;
-import org.thialfihar.android.apg.ui.widget.SectionView;
-import org.thialfihar.android.apg.ui.widget.UserIdEditor;
-import org.thialfihar.android.apg.util.IterableIterator;
-import org.thialfihar.android.apg.util.Utils;
-import org.thialfihar.android.apg.R;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Environment;
-import android.os.Message;
-import android.util.Log;
-import android.view.ViewGroup;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedReader;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.EOFException;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.RandomAccessFile;
-import java.math.BigInteger;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-import java.security.SecureRandom;
-import java.security.Security;
-import java.security.SignatureException;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Vector;
-import java.util.regex.Pattern;
-
-public class Apg {
-
- static {
- // register spongy castle provider
- Security.addProvider(new BouncyCastleProvider());
- }
-
- public static final String PACKAGE_NAME = "org.thialfihar.android.apg";
-
- private static final String INTENT_PREFIX = "org.thialfihar.android.apg.intent.";
-
- public static class Intent {
- public static final String DECRYPT = INTENT_PREFIX + "DECRYPT";
- public static final String ENCRYPT = INTENT_PREFIX + "ENCRYPT";
- public static final String DECRYPT_FILE = INTENT_PREFIX + "DECRYPT_FILE";
- public static final String ENCRYPT_FILE = INTENT_PREFIX + "ENCRYPT_FILE";
- public static final String DECRYPT_AND_RETURN = INTENT_PREFIX + "DECRYPT_AND_RETURN";
- public static final String ENCRYPT_AND_RETURN = INTENT_PREFIX + "ENCRYPT_AND_RETURN";
- public static final String SELECT_PUBLIC_KEYS = INTENT_PREFIX + "SELECT_PUBLIC_KEYS";
- public static final String SELECT_SECRET_KEY = INTENT_PREFIX + "SELECT_SECRET_KEY";
- public static final String IMPORT = INTENT_PREFIX + "IMPORT";
- public static final String LOOK_UP_KEY_ID = INTENT_PREFIX + "LOOK_UP_KEY_ID";
- public static final String LOOK_UP_KEY_ID_AND_RETURN = INTENT_PREFIX
- + "LOOK_UP_KEY_ID_AND_RETURN";
- public static final String GENERATE_SIGNATURE = INTENT_PREFIX + "GENERATE_SIGNATURE";
- public static final String EXPORT_KEY_TO_SERVER = INTENT_PREFIX + "EXPORT_KEY_TO_SERVER";
- public static final String IMPORT_FROM_QR_CODE = INTENT_PREFIX + "IMPORT_FROM_QR_CODE";
- public static final String CREATE_KEY = INTENT_PREFIX + "CREATE_KEY";
- public static final String EDIT_KEY = INTENT_PREFIX + "EDIT_KEY";
- }
-
- public static final String EXTRA_TEXT = "text";
- public static final String EXTRA_DATA = "data";
- public static final String EXTRA_ERROR = "error";
- public static final String EXTRA_DECRYPTED_MESSAGE = "decryptedMessage";
- public static final String EXTRA_DECRYPTED_DATA = "decryptedData";
- public static final String EXTRA_ENCRYPTED_MESSAGE = "encryptedMessage";
- public static final String EXTRA_ENCRYPTED_DATA = "encryptedData";
- public static final String EXTRA_RESULT_URI = "resultUri";
- public static final String EXTRA_SIGNATURE = "signature";
- public static final String EXTRA_SIGNATURE_KEY_ID = "signatureKeyId";
- public static final String EXTRA_SIGNATURE_USER_ID = "signatureUserId";
- public static final String EXTRA_SIGNATURE_SUCCESS = "signatureSuccess";
- public static final String EXTRA_SIGNATURE_UNKNOWN = "signatureUnknown";
- public static final String EXTRA_SIGNATURE_DATA = "signatureData";
- public static final String EXTRA_SIGNATURE_TEXT = "signatureText";
- public static final String EXTRA_USER_ID = "userId";
- public static final String EXTRA_USER_IDS = "userIds";
- public static final String EXTRA_KEY_ID = "keyId";
- public static final String EXTRA_REPLY_TO = "replyTo";
- public static final String EXTRA_SEND_TO = "sendTo";
- public static final String EXTRA_SUBJECT = "subject";
- public static final String EXTRA_ENCRYPTION_KEY_IDS = "encryptionKeyIds";
- public static final String EXTRA_SELECTION = "selection";
- public static final String EXTRA_ASCII_ARMOUR = "asciiArmour";
- public static final String EXTRA_BINARY = "binary";
- public static final String EXTRA_KEY_SERVERS = "keyServers";
- public static final String EXTRA_EXPECTED_FINGERPRINT = "expectedFingerprint";
- public static final String EXTRA_NO_PASSPHRASE = "noPassphrase";
- public static final String EXTRA_GENERATE_DEFAULT_KEYS = "generateDefaultKeys";
-
- public static final String AUTHORITY = DataProvider.AUTHORITY;
-
- public static final Uri CONTENT_URI_SECRET_KEY_RINGS = Uri.parse("content://" + AUTHORITY
- + "/key_rings/secret/");
- public static final Uri CONTENT_URI_SECRET_KEY_RING_BY_KEY_ID = Uri.parse("content://"
- + AUTHORITY + "/key_rings/secret/key_id/");
- public static final Uri CONTENT_URI_SECRET_KEY_RING_BY_EMAILS = Uri.parse("content://"
- + AUTHORITY + "/key_rings/secret/emails/");
-
- public static final Uri CONTENT_URI_PUBLIC_KEY_RINGS = Uri.parse("content://" + AUTHORITY
- + "/key_rings/public/");
- public static final Uri CONTENT_URI_PUBLIC_KEY_RING_BY_KEY_ID = Uri.parse("content://"
- + AUTHORITY + "/key_rings/public/key_id/");
- public static final Uri CONTENT_URI_PUBLIC_KEY_RING_BY_EMAILS = Uri.parse("content://"
- + AUTHORITY + "/key_rings/public/emails/");
-
- private static String VERSION = null;
-
- private static final int[] PREFERRED_SYMMETRIC_ALGORITHMS = new int[] {
- SymmetricKeyAlgorithmTags.AES_256, SymmetricKeyAlgorithmTags.AES_192,
- SymmetricKeyAlgorithmTags.AES_128, SymmetricKeyAlgorithmTags.CAST5,
- SymmetricKeyAlgorithmTags.TRIPLE_DES };
- private static final int[] PREFERRED_HASH_ALGORITHMS = new int[] { HashAlgorithmTags.SHA1,
- HashAlgorithmTags.SHA256, HashAlgorithmTags.RIPEMD160 };
- private static final int[] PREFERRED_COMPRESSION_ALGORITHMS = new int[] {
- CompressionAlgorithmTags.ZLIB, CompressionAlgorithmTags.BZIP2,
- CompressionAlgorithmTags.ZIP };
-
- public static Pattern PGP_MESSAGE = Pattern.compile(
- ".*?(-----BEGIN PGP MESSAGE-----.*?-----END PGP MESSAGE-----).*", Pattern.DOTALL);
-
- public static Pattern PGP_SIGNED_MESSAGE = Pattern
- .compile(
- ".*?(-----BEGIN PGP SIGNED MESSAGE-----.*?-----BEGIN PGP SIGNATURE-----.*?-----END PGP SIGNATURE-----).*",
- Pattern.DOTALL);
-
- public static Pattern PGP_PUBLIC_KEY = Pattern.compile(
- ".*?(-----BEGIN PGP PUBLIC KEY BLOCK-----.*?-----END PGP PUBLIC KEY BLOCK-----).*",
- Pattern.DOTALL);
-
- private static HashMap mPassPhraseCache = new HashMap();
- private static String mEditPassPhrase = null;
-
- private static Database mDatabase = null;
-
- public static class GeneralException extends Exception {
- static final long serialVersionUID = 0xf812773342L;
-
- public GeneralException(String message) {
- super(message);
- }
- }
-
- public static class NoAsymmetricEncryptionException extends Exception {
- static final long serialVersionUID = 0xf812773343L;
-
- public NoAsymmetricEncryptionException() {
- super();
- }
- }
-
- public static void initialize(Context context) {
- if (mDatabase == null) {
- mDatabase = new Database(context);
- }
- }
-
- public static Database getDatabase() {
- return mDatabase;
- }
-
- public static void setEditPassPhrase(String passPhrase) {
- mEditPassPhrase = passPhrase;
- }
-
- public static String getEditPassPhrase() {
- return mEditPassPhrase;
- }
-
- public static void setCachedPassPhrase(long keyId, String passPhrase) {
- mPassPhraseCache.put(keyId, new CachedPassPhrase(new Date().getTime(), passPhrase));
- }
-
- public static String getCachedPassPhrase(long keyId) {
- long realId = keyId;
- if (realId != Id.key.symmetric) {
- PGPSecretKeyRing keyRing = getSecretKeyRing(keyId);
- if (keyRing == null) {
- return null;
- }
- PGPSecretKey masterKey = getMasterKey(keyRing);
- if (masterKey == null) {
- return null;
- }
- realId = masterKey.getKeyID();
- }
- CachedPassPhrase cpp = mPassPhraseCache.get(realId);
- if (cpp == null) {
- return null;
- }
- // set it again to reset the cache life cycle
- setCachedPassPhrase(realId, cpp.passPhrase);
- return cpp.passPhrase;
- }
-
- public static int cleanUpCache(int ttl, int initialDelay) {
- int delay = initialDelay;
- long realTtl = ttl * 1000;
- long now = new Date().getTime();
- Vector oldKeys = new Vector();
- for (Map.Entry pair : mPassPhraseCache.entrySet()) {
- long lived = now - pair.getValue().timestamp;
- if (lived >= realTtl) {
- oldKeys.add(pair.getKey());
- } else {
- // see, whether the remaining time for this cache entry improves our
- // check delay
- long nextCheck = realTtl - lived + 1000;
- if (nextCheck < delay) {
- delay = (int) nextCheck;
- }
- }
- }
-
- for (long keyId : oldKeys) {
- mPassPhraseCache.remove(keyId);
- }
-
- return delay;
- }
-
- /**
- * Creates new secret key. The returned PGPSecretKeyRing contains only one newly generated key
- * when this key is the new masterkey. If a masterkey is supplied in the parameters
- * PGPSecretKeyRing contains the masterkey and the new key as a subkey (certified by the
- * masterkey).
- *
- * @param context
- * @param algorithmChoice
- * @param keySize
- * @param passPhrase
- * @param masterSecretKey
- * @return
- * @throws NoSuchAlgorithmException
- * @throws PGPException
- * @throws NoSuchProviderException
- * @throws GeneralException
- * @throws InvalidAlgorithmParameterException
- */
- public static PGPSecretKeyRing createKey(Context context, int algorithmChoice, int keySize,
- String passPhrase, PGPSecretKey masterSecretKey) throws NoSuchAlgorithmException,
- PGPException, NoSuchProviderException, GeneralException,
- InvalidAlgorithmParameterException {
-
- if (keySize < 512) {
- throw new GeneralException(context.getString(R.string.error_keySizeMinimum512bit));
- }
-
- if (passPhrase == null) {
- passPhrase = "";
- }
-
- int algorithm = 0;
- KeyPairGenerator keyGen = null;
-
- switch (algorithmChoice) {
- case Id.choice.algorithm.dsa: {
- keyGen = KeyPairGenerator.getInstance("DSA", "SC");
- keyGen.initialize(keySize, new SecureRandom());
- algorithm = PGPPublicKey.DSA;
- break;
- }
-
- case Id.choice.algorithm.elgamal: {
- if (masterSecretKey == null) {
- throw new GeneralException(
- context.getString(R.string.error_masterKeyMustNotBeElGamal));
- }
- keyGen = KeyPairGenerator.getInstance("ELGAMAL", "SC");
- BigInteger p = Primes.getBestPrime(keySize);
- BigInteger g = new BigInteger("2");
-
- ElGamalParameterSpec elParams = new ElGamalParameterSpec(p, g);
-
- keyGen.initialize(elParams);
- algorithm = PGPPublicKey.ELGAMAL_ENCRYPT;
- break;
- }
-
- case Id.choice.algorithm.rsa: {
- keyGen = KeyPairGenerator.getInstance("RSA", "SC");
- keyGen.initialize(keySize, new SecureRandom());
-
- algorithm = PGPPublicKey.RSA_GENERAL;
- break;
- }
-
- default: {
- throw new GeneralException(context.getString(R.string.error_unknownAlgorithmChoice));
- }
- }
-
- // build new key pair
- PGPKeyPair keyPair = new JcaPGPKeyPair(algorithm, keyGen.generateKeyPair(), new Date());
-
- // define hashing and signing algos
- PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get(
- HashAlgorithmTags.SHA1);
- PGPContentSignerBuilder certificationSignerBuilder = new JcaPGPContentSignerBuilder(keyPair
- .getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA1);
-
- // Build key encrypter and decrypter based on passphrase
- PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
- PGPEncryptedData.CAST5, sha1Calc).setProvider("SC").build(passPhrase.toCharArray());
- PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
- .setProvider("SC").build(passPhrase.toCharArray());
-
- PGPKeyRingGenerator ringGen = null;
- if (masterSecretKey == null) {
-
- // build keyRing with only this one master key in it!
- ringGen = new PGPKeyRingGenerator(PGPSignature.DEFAULT_CERTIFICATION, keyPair, "",
- sha1Calc, null, null, certificationSignerBuilder, keyEncryptor);
- } else {
- PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey();
- PGPPrivateKey masterPrivateKey = masterSecretKey.extractPrivateKey(keyDecryptor);
- PGPKeyPair masterKeyPair = new PGPKeyPair(masterPublicKey, masterPrivateKey);
-
- // build keyRing with master key and new key as subkey (certified by masterkey)
- ringGen = new PGPKeyRingGenerator(PGPSignature.DEFAULT_CERTIFICATION, masterKeyPair,
- "", sha1Calc, null, null, certificationSignerBuilder, keyEncryptor);
-
- ringGen.addSubKey(keyPair);
- }
-
- PGPSecretKeyRing secKeyRing = ringGen.generateSecretKeyRing();
-
- return secKeyRing;
- }
-
- public static void buildSecretKey(Context context, ArrayList userIds,
- ArrayList keys, ArrayList keysUsages, long masterKeyId,
- String oldPassPhrase, String newPassPhrase, ProgressDialogUpdater progress)
- throws Apg.GeneralException, NoSuchProviderException, PGPException,
- NoSuchAlgorithmException, SignatureException, IOException, Database.GeneralException {
-
- if (progress != null)
- progress.setProgress(R.string.progress_buildingKey, 0, 100);
-
- if (oldPassPhrase == null || oldPassPhrase.equals("")) {
- oldPassPhrase = "";
- }
-
- if (newPassPhrase == null || newPassPhrase.equals("")) {
- newPassPhrase = "";
- }
-
- // Vector userIds = new Vector();
- // Vector keys = new Vector();
-
- // ViewGroup userIdEditors = userIdsView.getEditors();
- // ViewGroup keyEditors = keysView.getEditors();
- //
- // boolean gotMainUserId = false;
- // for (int i = 0; i < userIdEditors.getChildCount(); ++i) {
- // UserIdEditor editor = (UserIdEditor) userIdEditors.getChildAt(i);
- // String userId = null;
- // try {
- // userId = editor.getValue();
- // } catch (UserIdEditor.NoNameException e) {
- // throw new Apg.GeneralException(context.getString(R.string.error_userIdNeedsAName));
- // } catch (UserIdEditor.NoEmailException e) {
- // throw new Apg.GeneralException(
- // context.getString(R.string.error_userIdNeedsAnEmailAddress));
- // } catch (UserIdEditor.InvalidEmailException e) {
- // throw new Apg.GeneralException("" + e);
- // }
- //
- // if (userId.equals("")) {
- // continue;
- // }
- //
- // if (editor.isMainUserId()) {
- // userIds.insertElementAt(userId, 0);
- // gotMainUserId = true;
- // } else {
- // userIds.add(userId);
- // }
- // }
-
- // if (userIds.size() == 0) {
- // throw new Apg.GeneralException(context.getString(R.string.error_keyNeedsAUserId));
- // }
- //
- // if (!gotMainUserId) {
- // throw new Apg.GeneralException(
- // context.getString(R.string.error_mainUserIdMustNotBeEmpty));
- // }
-
- // if (keyEditors.getChildCount() == 0) {
- // throw new Apg.GeneralException(context.getString(R.string.error_keyNeedsMasterKey));
- // }
- //
- // for (int i = 0; i < keyEditors.getChildCount(); ++i) {
- // KeyEditor editor = (KeyEditor) keyEditors.getChildAt(i);
- // keys.add(editor.getValue());
- // }
-
- if (progress != null)
- progress.setProgress(R.string.progress_preparingMasterKey, 10, 100);
-
- // KeyEditor keyEditor = (KeyEditor) keyEditors.getChildAt(0);
- // int usageId = keyEditor.getUsage();
-
- int usageId = keysUsages.get(0);
- boolean canSign = (usageId == Id.choice.usage.sign_only || usageId == Id.choice.usage.sign_and_encrypt);
- boolean canEncrypt = (usageId == Id.choice.usage.encrypt_only || usageId == Id.choice.usage.sign_and_encrypt);
-
- String mainUserId = userIds.get(0);
-
- PGPSecretKey masterKey = keys.get(0);
- PGPPublicKey tmpKey = masterKey.getPublicKey();
- PGPPublicKey masterPublicKey = new PGPPublicKey(tmpKey.getAlgorithm(),
- tmpKey.getKey(new BouncyCastleProvider()), tmpKey.getCreationTime());
- PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
- .setProvider("SC").build(oldPassPhrase.toCharArray());
- PGPPrivateKey masterPrivateKey = masterKey.extractPrivateKey(keyDecryptor);
-
- if (progress != null)
- progress.setProgress(R.string.progress_certifyingMasterKey, 20, 100);
- for (int i = 0; i < userIds.size(); ++i) {
- String userId = userIds.get(i);
-
- PGPSignatureGenerator sGen = new PGPSignatureGenerator(masterPublicKey.getAlgorithm(),
- HashAlgorithmTags.SHA1, new BouncyCastleProvider());
-
- sGen.initSign(PGPSignature.POSITIVE_CERTIFICATION, masterPrivateKey);
-
- PGPSignature certification = sGen.generateCertification(userId, masterPublicKey);
-
- masterPublicKey = PGPPublicKey.addCertification(masterPublicKey, userId, certification);
- }
-
- // TODO: cross-certify the master key with every sub key
-
- PGPKeyPair masterKeyPair = new PGPKeyPair(masterPublicKey, masterPrivateKey);
-
- PGPSignatureSubpacketGenerator hashedPacketsGen = new PGPSignatureSubpacketGenerator();
- PGPSignatureSubpacketGenerator unhashedPacketsGen = new PGPSignatureSubpacketGenerator();
-
- int keyFlags = KeyFlags.CERTIFY_OTHER | KeyFlags.SIGN_DATA;
- if (canEncrypt) {
- keyFlags |= KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE;
- }
- hashedPacketsGen.setKeyFlags(true, keyFlags);
-
- hashedPacketsGen.setPreferredSymmetricAlgorithms(true, PREFERRED_SYMMETRIC_ALGORITHMS);
- hashedPacketsGen.setPreferredHashAlgorithms(true, PREFERRED_HASH_ALGORITHMS);
- hashedPacketsGen.setPreferredCompressionAlgorithms(true, PREFERRED_COMPRESSION_ALGORITHMS);
-
- // TODO: this doesn't work quite right yet
- // if (keyEditor.getExpiryDate() != null) {
- // GregorianCalendar creationDate = new GregorianCalendar();
- // creationDate.setTime(getCreationDate(masterKey));
- // GregorianCalendar expiryDate = keyEditor.getExpiryDate();
- // long numDays = Utils.getNumDaysBetween(creationDate, expiryDate);
- // if (numDays <= 0) {
- // throw new GeneralException(
- // context.getString(R.string.error_expiryMustComeAfterCreation));
- // }
- // hashedPacketsGen.setKeyExpirationTime(true, numDays * 86400);
- // }
-
- if (progress != null) {
- progress.setProgress(R.string.progress_buildingMasterKeyRing, 30, 100);
- }
-
- PGPKeyRingGenerator keyGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION,
- masterKeyPair, mainUserId, PGPEncryptedData.CAST5, newPassPhrase.toCharArray(),
- hashedPacketsGen.generate(), unhashedPacketsGen.generate(), new SecureRandom(),
- new BouncyCastleProvider().getName());
-
- if (progress != null)
- progress.setProgress(R.string.progress_addingSubKeys, 40, 100);
- for (int i = 1; i < keys.size(); ++i) {
- if (progress != null)
- progress.setProgress(40 + 50 * (i - 1) / (keys.size() - 1), 100);
- PGPSecretKey subKey = keys.get(i);
- // keyEditor = (KeyEditor) keyEditors.getChildAt(i);
- PGPPublicKey subPublicKey = subKey.getPublicKey();
-
- PBESecretKeyDecryptor keyDecryptor2 = new JcePBESecretKeyDecryptorBuilder()
- .setProvider("SC").build(oldPassPhrase.toCharArray());
- PGPPrivateKey subPrivateKey = subKey.extractPrivateKey(keyDecryptor2);
- PGPKeyPair subKeyPair = new PGPKeyPair(subPublicKey.getAlgorithm(),
- subPublicKey.getKey(new BouncyCastleProvider()), subPrivateKey.getKey(),
- subPublicKey.getCreationTime());
-
- hashedPacketsGen = new PGPSignatureSubpacketGenerator();
- unhashedPacketsGen = new PGPSignatureSubpacketGenerator();
-
- keyFlags = 0;
- // usageId = keyEditor.getUsage();
-
- usageId = keysUsages.get(i);
- canSign = (usageId == Id.choice.usage.sign_only || usageId == Id.choice.usage.sign_and_encrypt);
- canEncrypt = (usageId == Id.choice.usage.encrypt_only || usageId == Id.choice.usage.sign_and_encrypt);
- if (canSign) {
- keyFlags |= KeyFlags.SIGN_DATA;
- }
- if (canEncrypt) {
- keyFlags |= KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE;
- }
- hashedPacketsGen.setKeyFlags(true, keyFlags);
-
- // TODO: this doesn't work quite right yet
- // if (keyEditor.getExpiryDate() != null) {
- // GregorianCalendar creationDate = new GregorianCalendar();
- // creationDate.setTime(getCreationDate(masterKey));
- // GregorianCalendar expiryDate = keyEditor.getExpiryDate();
- // long numDays = Utils.getNumDaysBetween(creationDate, expiryDate);
- // if (numDays <= 0) {
- // throw new GeneralException(
- // context.getString(R.string.error_expiryMustComeAfterCreation));
- // }
- // hashedPacketsGen.setKeyExpirationTime(true, numDays * 86400);
- // }
-
- keyGen.addSubKey(subKeyPair, hashedPacketsGen.generate(), unhashedPacketsGen.generate());
- }
-
- PGPSecretKeyRing secretKeyRing = keyGen.generateSecretKeyRing();
- PGPPublicKeyRing publicKeyRing = keyGen.generatePublicKeyRing();
-
- if (progress != null)
- progress.setProgress(R.string.progress_savingKeyRing, 90, 100);
- mDatabase.saveKeyRing(secretKeyRing);
- mDatabase.saveKeyRing(publicKeyRing);
-
- if (progress != null)
- progress.setProgress(R.string.progress_done, 100, 100);
- }
-
- public static PGPKeyRing decodeKeyRing(InputStream is) throws IOException {
- InputStream in = PGPUtil.getDecoderStream(is);
- PGPObjectFactory objectFactory = new PGPObjectFactory(in);
- Object obj = objectFactory.nextObject();
-
- if (obj instanceof PGPKeyRing) {
- return (PGPKeyRing) obj;
- }
-
- return null;
- }
-
- public static int storeKeyRingInCache(PGPKeyRing keyring) {
- int status = Integer.MIN_VALUE; // out of bounds value (Id.retrun_value.*)
- try {
- if (keyring instanceof PGPSecretKeyRing) {
- PGPSecretKeyRing secretKeyRing = (PGPSecretKeyRing) keyring;
- boolean save = true;
- try {
- PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
- .setProvider("SC").build(new char[] {});
- PGPPrivateKey testKey = secretKeyRing.getSecretKey().extractPrivateKey(
- keyDecryptor);
- if (testKey == null) {
- // this is bad, something is very wrong... likely a --export-secret-subkeys
- // export
- save = false;
- status = Id.return_value.bad;
- }
- } catch (PGPException e) {
- // all good if this fails, we likely didn't use the right password
- }
-
- if (save) {
- status = mDatabase.saveKeyRing(secretKeyRing);
- }
- } else if (keyring instanceof PGPPublicKeyRing) {
- PGPPublicKeyRing publicKeyRing = (PGPPublicKeyRing) keyring;
- status = mDatabase.saveKeyRing(publicKeyRing);
- }
- } catch (IOException e) {
- status = Id.return_value.error;
- } catch (Database.GeneralException e) {
- status = Id.return_value.error;
- }
-
- return status;
- }
-
- public static boolean uploadKeyRingToServer(HkpKeyServer server, PGPPublicKeyRing keyring) {
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- ArmoredOutputStream aos = new ArmoredOutputStream(bos);
- try {
- aos.write(keyring.getEncoded());
- aos.close();
-
- String armouredKey = bos.toString("UTF-8");
- server.add(armouredKey);
-
- return true;
- } catch (IOException e) {
- return false;
- } catch (AddKeyException e) {
- // TODO: tell the user?
- return false;
- } finally {
- try {
- bos.close();
- } catch (IOException e) {
- }
- }
- }
-
- public static Bundle importKeyRings(Activity context, int type, InputData data,
- ProgressDialogUpdater progress) throws GeneralException, FileNotFoundException,
- PGPException, IOException {
- Bundle returnData = new Bundle();
-
- if (type == Id.type.secret_key) {
- if (progress != null)
- progress.setProgress(R.string.progress_importingSecretKeys, 0, 100);
- } else {
- if (progress != null)
- progress.setProgress(R.string.progress_importingPublicKeys, 0, 100);
- }
-
- if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- throw new GeneralException(context.getString(R.string.error_externalStorageNotReady));
- }
-
- PositionAwareInputStream progressIn = new PositionAwareInputStream(data.getInputStream());
- // need to have access to the bufferedInput, so we can reuse it for the possible
- // PGPObject chunks after the first one, e.g. files with several consecutive ASCII
- // armour blocks
- BufferedInputStream bufferedInput = new BufferedInputStream(progressIn);
- int newKeys = 0;
- int oldKeys = 0;
- int badKeys = 0;
- try {
- PGPKeyRing keyring = decodeKeyRing(bufferedInput);
- while (keyring != null) {
- int status = Integer.MIN_VALUE; // out of bounds value
-
- // if this key is what we expect it to be, save it
- if ((type == Id.type.secret_key && keyring instanceof PGPSecretKeyRing)
- || (type == Id.type.public_key && keyring instanceof PGPPublicKeyRing)) {
- status = storeKeyRingInCache(keyring);
- }
-
- if (status == Id.return_value.error) {
- throw new GeneralException(context.getString(R.string.error_savingKeys));
- }
-
- // update the counts to display to the user at the end
- if (status == Id.return_value.updated) {
- ++oldKeys;
- } else if (status == Id.return_value.ok) {
- ++newKeys;
- } else if (status == Id.return_value.bad) {
- ++badKeys;
- }
-
- if (progress != null) {
- progress.setProgress((int) (100 * progressIn.position() / data.getSize()), 100);
- }
- // TODO: needed?
- // obj = objectFactory.nextObject();
-
- keyring = decodeKeyRing(bufferedInput);
- }
- } catch (EOFException e) {
- // nothing to do, we are done
- }
-
- returnData.putInt("added", newKeys);
- returnData.putInt("updated", oldKeys);
- returnData.putInt("bad", badKeys);
-
- if (progress != null)
- progress.setProgress(R.string.progress_done, 100, 100);
-
- return returnData;
- }
-
- public static Bundle exportKeyRings(Activity context, Vector keyRingIds,
- OutputStream outStream, ProgressDialogUpdater progress) throws GeneralException,
- FileNotFoundException, PGPException, IOException {
- Bundle returnData = new Bundle();
-
- if (keyRingIds.size() == 1) {
- if (progress != null)
- progress.setProgress(R.string.progress_exportingKey, 0, 100);
- } else {
- if (progress != null)
- progress.setProgress(R.string.progress_exportingKeys, 0, 100);
- }
-
- if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- throw new GeneralException(context.getString(R.string.error_externalStorageNotReady));
- }
- ArmoredOutputStream out = new ArmoredOutputStream(outStream);
-
- int numKeys = 0;
- for (int i = 0; i < keyRingIds.size(); ++i) {
- if (progress != null)
- progress.setProgress(i * 100 / keyRingIds.size(), 100);
- Object obj = mDatabase.getKeyRing(keyRingIds.get(i));
- PGPPublicKeyRing publicKeyRing;
- PGPSecretKeyRing secretKeyRing;
-
- if (obj instanceof PGPSecretKeyRing) {
- secretKeyRing = (PGPSecretKeyRing) obj;
- secretKeyRing.encode(out);
- } else if (obj instanceof PGPPublicKeyRing) {
- publicKeyRing = (PGPPublicKeyRing) obj;
- publicKeyRing.encode(out);
- } else {
- continue;
- }
- ++numKeys;
- }
- out.close();
- returnData.putInt("exported", numKeys);
-
- if (progress != null)
- progress.setProgress(R.string.progress_done, 100, 100);
-
- return returnData;
- }
-
- public static Date getCreationDate(PGPPublicKey key) {
- return key.getCreationTime();
- }
-
- public static Date getCreationDate(PGPSecretKey key) {
- return key.getPublicKey().getCreationTime();
- }
-
- @SuppressWarnings("unchecked")
- public static PGPPublicKey getMasterKey(PGPPublicKeyRing keyRing) {
- if (keyRing == null) {
- return null;
- }
- for (PGPPublicKey key : new IterableIterator(keyRing.getPublicKeys())) {
- if (key.isMasterKey()) {
- return key;
- }
- }
-
- return null;
- }
-
- @SuppressWarnings("unchecked")
- public static PGPSecretKey getMasterKey(PGPSecretKeyRing keyRing) {
- if (keyRing == null) {
- return null;
- }
- for (PGPSecretKey key : new IterableIterator(keyRing.getSecretKeys())) {
- if (key.isMasterKey()) {
- return key;
- }
- }
-
- return null;
- }
-
- @SuppressWarnings("unchecked")
- public static Vector getEncryptKeys(PGPPublicKeyRing keyRing) {
- Vector encryptKeys = new Vector();
-
- for (PGPPublicKey key : new IterableIterator(keyRing.getPublicKeys())) {
- if (isEncryptionKey(key)) {
- encryptKeys.add(key);
- }
- }
-
- return encryptKeys;
- }
-
- @SuppressWarnings("unchecked")
- public static Vector getSigningKeys(PGPSecretKeyRing keyRing) {
- Vector signingKeys = new Vector();
-
- for (PGPSecretKey key : new IterableIterator(keyRing.getSecretKeys())) {
- if (isSigningKey(key)) {
- signingKeys.add(key);
- }
- }
-
- return signingKeys;
- }
-
- public static Vector getUsableEncryptKeys(PGPPublicKeyRing keyRing) {
- Vector usableKeys = new Vector();
- Vector encryptKeys = getEncryptKeys(keyRing);
- PGPPublicKey masterKey = null;
- for (int i = 0; i < encryptKeys.size(); ++i) {
- PGPPublicKey key = encryptKeys.get(i);
- if (!isExpired(key)) {
- if (key.isMasterKey()) {
- masterKey = key;
- } else {
- usableKeys.add(key);
- }
- }
- }
- if (masterKey != null) {
- usableKeys.add(masterKey);
- }
- return usableKeys;
- }
-
- public static boolean isExpired(PGPPublicKey key) {
- Date creationDate = getCreationDate(key);
- Date expiryDate = getExpiryDate(key);
- Date now = new Date();
- if (now.compareTo(creationDate) >= 0
- && (expiryDate == null || now.compareTo(expiryDate) <= 0)) {
- return false;
- }
- return true;
- }
-
- public static boolean isExpired(PGPSecretKey key) {
- return isExpired(key.getPublicKey());
- }
-
- public static Vector getUsableSigningKeys(PGPSecretKeyRing keyRing) {
- Vector usableKeys = new Vector();
- Vector signingKeys = getSigningKeys(keyRing);
- PGPSecretKey masterKey = null;
- for (int i = 0; i < signingKeys.size(); ++i) {
- PGPSecretKey key = signingKeys.get(i);
- if (key.isMasterKey()) {
- masterKey = key;
- } else {
- usableKeys.add(key);
- }
- }
- if (masterKey != null) {
- usableKeys.add(masterKey);
- }
- return usableKeys;
- }
-
- public static Date getExpiryDate(PGPPublicKey key) {
- Date creationDate = getCreationDate(key);
- if (key.getValidDays() == 0) {
- // no expiry
- return null;
- }
- Calendar calendar = GregorianCalendar.getInstance();
- calendar.setTime(creationDate);
- calendar.add(Calendar.DATE, key.getValidDays());
- Date expiryDate = calendar.getTime();
-
- return expiryDate;
- }
-
- public static Date getExpiryDate(PGPSecretKey key) {
- return getExpiryDate(key.getPublicKey());
- }
-
- public static PGPPublicKey getEncryptPublicKey(long masterKeyId) {
- PGPPublicKeyRing keyRing = getPublicKeyRing(masterKeyId);
- if (keyRing == null) {
- return null;
- }
- Vector encryptKeys = getUsableEncryptKeys(keyRing);
- if (encryptKeys.size() == 0) {
- return null;
- }
- return encryptKeys.get(0);
- }
-
- public static PGPSecretKey getSigningKey(long masterKeyId) {
- PGPSecretKeyRing keyRing = getSecretKeyRing(masterKeyId);
- if (keyRing == null) {
- return null;
- }
- Vector signingKeys = getUsableSigningKeys(keyRing);
- if (signingKeys.size() == 0) {
- return null;
- }
- return signingKeys.get(0);
- }
-
- @SuppressWarnings("unchecked")
- public static String getMainUserId(PGPPublicKey key) {
- for (String userId : new IterableIterator(key.getUserIDs())) {
- return userId;
- }
- return null;
- }
-
- @SuppressWarnings("unchecked")
- public static String getMainUserId(PGPSecretKey key) {
- for (String userId : new IterableIterator(key.getUserIDs())) {
- return userId;
- }
- return null;
- }
-
- public static String getMainUserIdSafe(Context context, PGPPublicKey key) {
- String userId = getMainUserId(key);
- if (userId == null) {
- userId = context.getResources().getString(R.string.unknownUserId);
- }
- return userId;
- }
-
- public static String getMainUserIdSafe(Context context, PGPSecretKey key) {
- String userId = getMainUserId(key);
- if (userId == null) {
- userId = context.getResources().getString(R.string.unknownUserId);
- }
- return userId;
- }
-
- @SuppressWarnings("unchecked")
- public static boolean isEncryptionKey(PGPPublicKey key) {
- if (!key.isEncryptionKey()) {
- return false;
- }
-
- if (key.getVersion() <= 3) {
- // this must be true now
- return key.isEncryptionKey();
- }
-
- // special cases
- if (key.getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT) {
- return true;
- }
-
- if (key.getAlgorithm() == PGPPublicKey.RSA_ENCRYPT) {
- return true;
- }
-
- for (PGPSignature sig : new IterableIterator(key.getSignatures())) {
- if (key.isMasterKey() && sig.getKeyID() != key.getKeyID()) {
- continue;
- }
- PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets();
-
- if (hashed != null
- && (hashed.getKeyFlags() & (KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE)) != 0) {
- return true;
- }
-
- PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets();
-
- if (unhashed != null
- && (unhashed.getKeyFlags() & (KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE)) != 0) {
- return true;
- }
- }
- return false;
- }
-
- public static boolean isEncryptionKey(PGPSecretKey key) {
- return isEncryptionKey(key.getPublicKey());
- }
-
- @SuppressWarnings("unchecked")
- public static boolean isSigningKey(PGPPublicKey key) {
- if (key.getVersion() <= 3) {
- return true;
- }
-
- // special case
- if (key.getAlgorithm() == PGPPublicKey.RSA_SIGN) {
- return true;
- }
-
- for (PGPSignature sig : new IterableIterator(key.getSignatures())) {
- if (key.isMasterKey() && sig.getKeyID() != key.getKeyID()) {
- continue;
- }
- PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets();
-
- if (hashed != null && (hashed.getKeyFlags() & KeyFlags.SIGN_DATA) != 0) {
- return true;
- }
-
- PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets();
-
- if (unhashed != null && (unhashed.getKeyFlags() & KeyFlags.SIGN_DATA) != 0) {
- return true;
- }
- }
-
- return false;
- }
-
- public static boolean isSigningKey(PGPSecretKey key) {
- return isSigningKey(key.getPublicKey());
- }
-
- public static String getAlgorithmInfo(PGPPublicKey key) {
- return getAlgorithmInfo(key.getAlgorithm(), key.getBitStrength());
- }
-
- public static String getAlgorithmInfo(PGPSecretKey key) {
- return getAlgorithmInfo(key.getPublicKey());
- }
-
- public static String getAlgorithmInfo(int algorithm, int keySize) {
- String algorithmStr = null;
-
- switch (algorithm) {
- case PGPPublicKey.RSA_ENCRYPT:
- case PGPPublicKey.RSA_GENERAL:
- case PGPPublicKey.RSA_SIGN: {
- algorithmStr = "RSA";
- break;
- }
-
- case PGPPublicKey.DSA: {
- algorithmStr = "DSA";
- break;
- }
-
- case PGPPublicKey.ELGAMAL_ENCRYPT:
- case PGPPublicKey.ELGAMAL_GENERAL: {
- algorithmStr = "ElGamal";
- break;
- }
-
- default: {
- algorithmStr = "???";
- break;
- }
- }
- return algorithmStr + ", " + keySize + "bit";
- }
-
- public static String convertToHex(byte[] fp) {
- String fingerPrint = "";
- for (int i = 0; i < fp.length; ++i) {
- if (i != 0 && i % 10 == 0) {
- fingerPrint += " ";
- } else if (i != 0 && i % 2 == 0) {
- fingerPrint += " ";
- }
- String chunk = Integer.toHexString((fp[i] + 256) % 256).toUpperCase();
- while (chunk.length() < 2) {
- chunk = "0" + chunk;
- }
- fingerPrint += chunk;
- }
-
- return fingerPrint;
-
- }
-
- public static String getFingerPrint(long keyId) {
- PGPPublicKey key = Apg.getPublicKey(keyId);
- if (key == null) {
- PGPSecretKey secretKey = Apg.getSecretKey(keyId);
- if (secretKey == null) {
- return "";
- }
- key = secretKey.getPublicKey();
- }
-
- return convertToHex(key.getFingerprint());
- }
-
- public static String getSmallFingerPrint(long keyId) {
- String fingerPrint = Long.toHexString(keyId & 0xffffffffL).toUpperCase();
- while (fingerPrint.length() < 8) {
- fingerPrint = "0" + fingerPrint;
- }
- return fingerPrint;
- }
-
- public static String keyToHex(long keyId) {
- return getSmallFingerPrint(keyId >> 32) + getSmallFingerPrint(keyId);
- }
-
- public static long keyFromHex(String data) {
- int len = data.length();
- String s2 = data.substring(len - 8);
- String s1 = data.substring(0, len - 8);
- return (Long.parseLong(s1, 16) << 32) | Long.parseLong(s2, 16);
- }
-
- public static void deleteKey(int keyRingId) {
- mDatabase.deleteKeyRing(keyRingId);
- }
-
- public static PGPKeyRing getKeyRing(int keyRingId) {
- return (PGPKeyRing) mDatabase.getKeyRing(keyRingId);
- }
-
- public static PGPSecretKeyRing getSecretKeyRing(long keyId) {
- byte[] data = mDatabase.getKeyRingDataFromKeyId(Id.database.type_secret, keyId);
- if (data == null) {
- return null;
- }
- try {
- return new PGPSecretKeyRing(data);
- } catch (IOException e) {
- // no good way to handle this, return null
- // TODO: some info?
- } catch (PGPException e) {
- // no good way to handle this, return null
- // TODO: some info?
- }
- return null;
- }
-
- public static PGPPublicKeyRing getPublicKeyRing(long keyId) {
- byte[] data = mDatabase.getKeyRingDataFromKeyId(Id.database.type_public, keyId);
- if (data == null) {
- return null;
- }
- try {
- return new PGPPublicKeyRing(data);
- } catch (IOException e) {
- // no good way to handle this, return null
- // TODO: some info?
- }
- return null;
- }
-
- public static PGPSecretKey getSecretKey(long keyId) {
- PGPSecretKeyRing keyRing = getSecretKeyRing(keyId);
- if (keyRing == null) {
- return null;
- }
- return keyRing.getSecretKey(keyId);
- }
-
- public static PGPPublicKey getPublicKey(long keyId) {
- PGPPublicKeyRing keyRing = getPublicKeyRing(keyId);
- if (keyRing == null) {
- return null;
- }
-
- return keyRing.getPublicKey(keyId);
- }
-
- public static Vector getKeyRingIds(int type) {
- SQLiteDatabase db = mDatabase.db();
- Vector keyIds = new Vector();
- Cursor c = db.query(KeyRings.TABLE_NAME, new String[] { KeyRings._ID }, KeyRings.TYPE
- + " = ?", new String[] { "" + type }, null, null, null);
- if (c != null && c.moveToFirst()) {
- do {
- keyIds.add(c.getInt(0));
- } while (c.moveToNext());
- }
-
- if (c != null) {
- c.close();
- }
-
- return keyIds;
- }
-
- public static String getMainUserId(long keyId, int type) {
- SQLiteDatabase db = mDatabase.db();
- Cursor c = db.query(Keys.TABLE_NAME + " INNER JOIN " + KeyRings.TABLE_NAME + " ON ("
- + KeyRings.TABLE_NAME + "." + KeyRings._ID + " = " + Keys.TABLE_NAME + "."
- + Keys.KEY_RING_ID + ") " + " INNER JOIN " + Keys.TABLE_NAME + " AS masterKey ON ("
- + KeyRings.TABLE_NAME + "." + KeyRings._ID + " = " + "masterKey."
- + Keys.KEY_RING_ID + " AND " + "masterKey." + Keys.IS_MASTER_KEY + " = '1') "
- + " INNER JOIN " + UserIds.TABLE_NAME + " ON (" + UserIds.TABLE_NAME + "."
- + UserIds.KEY_ID + " = " + "masterKey." + Keys._ID + " AND " + UserIds.TABLE_NAME
- + "." + UserIds.RANK + " = '0')", new String[] { UserIds.USER_ID }, Keys.TABLE_NAME
- + "." + Keys.KEY_ID + " = ? AND " + KeyRings.TABLE_NAME + "." + KeyRings.TYPE
- + " = ?", new String[] { "" + keyId, "" + type, }, null, null, null);
- String userId = "";
- if (c != null && c.moveToFirst()) {
- do {
- userId = c.getString(0);
- } while (c.moveToNext());
- }
-
- if (c != null) {
- c.close();
- }
-
- return userId;
- }
-
- public static void encrypt(Context context, InputData data, OutputStream outStream,
- boolean armored, long encryptionKeyIds[], long signatureKeyId,
- String signaturePassPhrase, ProgressDialogUpdater progress, int symmetricAlgorithm,
- int hashAlgorithm, int compression, boolean forceV3Signature, String passPhrase)
- throws IOException, GeneralException, PGPException, NoSuchProviderException,
- NoSuchAlgorithmException, SignatureException {
-
- if (encryptionKeyIds == null) {
- encryptionKeyIds = new long[0];
- }
-
- ArmoredOutputStream armorOut = null;
- OutputStream out = null;
- OutputStream encryptOut = null;
- if (armored) {
- armorOut = new ArmoredOutputStream(outStream);
- armorOut.setHeader("Version", getFullVersion(context));
- out = armorOut;
- } else {
- out = outStream;
- }
- PGPSecretKey signingKey = null;
- PGPSecretKeyRing signingKeyRing = null;
- PGPPrivateKey signaturePrivateKey = null;
-
- if (encryptionKeyIds.length == 0 && passPhrase == null) {
- throw new GeneralException(
- context.getString(R.string.error_noEncryptionKeysOrPassPhrase));
- }
-
- if (signatureKeyId != Id.key.none) {
- signingKeyRing = getSecretKeyRing(signatureKeyId);
- signingKey = getSigningKey(signatureKeyId);
- if (signingKey == null) {
- throw new GeneralException(context.getString(R.string.error_signatureFailed));
- }
-
- if (signaturePassPhrase == null) {
- throw new GeneralException(context.getString(R.string.error_noSignaturePassPhrase));
- }
- if (progress != null)
- progress.setProgress(R.string.progress_extractingSignatureKey, 0, 100);
- PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
- "SC").build(signaturePassPhrase.toCharArray());
- signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
- if (signaturePrivateKey == null) {
- throw new GeneralException(
- context.getString(R.string.error_couldNotExtractPrivateKey));
- }
- }
- if (progress != null)
- progress.setProgress(R.string.progress_preparingStreams, 5, 100);
-
- // encrypt and compress input file content
- PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(symmetricAlgorithm, true,
- new SecureRandom(), new BouncyCastleProvider());
-
- if (encryptionKeyIds.length == 0) {
- // symmetric encryption
- Log.d(Constants.TAG, "encryptionKeyIds length is 0 -> symmetric encryption");
- cPk.addMethod(passPhrase.toCharArray());
- }
- for (int i = 0; i < encryptionKeyIds.length; ++i) {
- PGPPublicKey key = getEncryptPublicKey(encryptionKeyIds[i]);
- if (key != null) {
- cPk.addMethod(key);
- }
- }
- encryptOut = cPk.open(out, new byte[1 << 16]);
-
- PGPSignatureGenerator signatureGenerator = null;
- PGPV3SignatureGenerator signatureV3Generator = null;
-
- if (signatureKeyId != Id.key.none) {
- if (progress != null)
- progress.setProgress(R.string.progress_preparingSignature, 10, 100);
- if (forceV3Signature) {
- signatureV3Generator = new PGPV3SignatureGenerator(signingKey.getPublicKey()
- .getAlgorithm(), hashAlgorithm, new BouncyCastleProvider());
- signatureV3Generator.initSign(PGPSignature.BINARY_DOCUMENT, signaturePrivateKey);
- } else {
- signatureGenerator = new PGPSignatureGenerator(signingKey.getPublicKey()
- .getAlgorithm(), hashAlgorithm, new BouncyCastleProvider());
- signatureGenerator.initSign(PGPSignature.BINARY_DOCUMENT, signaturePrivateKey);
-
- String userId = getMainUserId(getMasterKey(signingKeyRing));
- PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
- spGen.setSignerUserID(false, userId);
- signatureGenerator.setHashedSubpackets(spGen.generate());
- }
- }
-
- PGPCompressedDataGenerator compressGen = null;
- BCPGOutputStream bcpgOut = null;
- if (compression == Id.choice.compression.none) {
- bcpgOut = new BCPGOutputStream(encryptOut);
- } else {
- compressGen = new PGPCompressedDataGenerator(compression);
- bcpgOut = new BCPGOutputStream(compressGen.open(encryptOut));
- }
- if (signatureKeyId != Id.key.none) {
- if (forceV3Signature) {
- signatureV3Generator.generateOnePassVersion(false).encode(bcpgOut);
- } else {
- signatureGenerator.generateOnePassVersion(false).encode(bcpgOut);
- }
- }
-
- PGPLiteralDataGenerator literalGen = new PGPLiteralDataGenerator();
- // file name not needed, so empty string
- OutputStream pOut = literalGen.open(bcpgOut, PGPLiteralData.BINARY, "", new Date(),
- new byte[1 << 16]);
- if (progress != null)
- progress.setProgress(R.string.progress_encrypting, 20, 100);
-
- long done = 0;
- int n = 0;
- byte[] buffer = new byte[1 << 16];
- InputStream in = data.getInputStream();
- while ((n = in.read(buffer)) > 0) {
- pOut.write(buffer, 0, n);
- if (signatureKeyId != Id.key.none) {
- if (forceV3Signature) {
- signatureV3Generator.update(buffer, 0, n);
- } else {
- signatureGenerator.update(buffer, 0, n);
- }
- }
- done += n;
- if (data.getSize() != 0) {
- if (progress != null)
- progress.setProgress((int) (20 + (95 - 20) * done / data.getSize()), 100);
- }
- }
-
- literalGen.close();
-
- if (signatureKeyId != Id.key.none) {
- if (progress != null)
- progress.setProgress(R.string.progress_generatingSignature, 95, 100);
- if (forceV3Signature) {
- signatureV3Generator.generate().encode(pOut);
- } else {
- signatureGenerator.generate().encode(pOut);
- }
- }
- if (compressGen != null) {
- compressGen.close();
- }
- encryptOut.close();
- if (armored) {
- armorOut.close();
- }
-
- if (progress != null)
- progress.setProgress(R.string.progress_done, 100, 100);
- }
-
- public static void signText(Context context, InputData data, OutputStream outStream,
- long signatureKeyId, String signaturePassPhrase, int hashAlgorithm,
- boolean forceV3Signature, ProgressDialogUpdater progress) throws GeneralException,
- PGPException, IOException, NoSuchAlgorithmException, SignatureException {
-
- ArmoredOutputStream armorOut = new ArmoredOutputStream(outStream);
- armorOut.setHeader("Version", getFullVersion(context));
-
- PGPSecretKey signingKey = null;
- PGPSecretKeyRing signingKeyRing = null;
- PGPPrivateKey signaturePrivateKey = null;
-
- if (signatureKeyId == 0) {
- throw new GeneralException(context.getString(R.string.error_noSignatureKey));
- }
-
- signingKeyRing = getSecretKeyRing(signatureKeyId);
- signingKey = getSigningKey(signatureKeyId);
- if (signingKey == null) {
- throw new GeneralException(context.getString(R.string.error_signatureFailed));
- }
-
- if (signaturePassPhrase == null) {
- throw new GeneralException(context.getString(R.string.error_noSignaturePassPhrase));
- }
- PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
- .setProvider("SC").build(signaturePassPhrase.toCharArray());
- signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
- if (signaturePrivateKey == null) {
- throw new GeneralException(context.getString(R.string.error_couldNotExtractPrivateKey));
- }
- if (progress != null)
- progress.setProgress(R.string.progress_preparingStreams, 0, 100);
-
- if (progress != null)
- progress.setProgress(R.string.progress_preparingSignature, 30, 100);
-
- PGPSignatureGenerator signatureGenerator = null;
- PGPV3SignatureGenerator signatureV3Generator = null;
-
- if (forceV3Signature) {
- signatureV3Generator = new PGPV3SignatureGenerator(signingKey.getPublicKey()
- .getAlgorithm(), hashAlgorithm, new BouncyCastleProvider());
- signatureV3Generator
- .initSign(PGPSignature.CANONICAL_TEXT_DOCUMENT, signaturePrivateKey);
- } else {
- signatureGenerator = new PGPSignatureGenerator(
- signingKey.getPublicKey().getAlgorithm(), hashAlgorithm,
- new BouncyCastleProvider());
- signatureGenerator.initSign(PGPSignature.CANONICAL_TEXT_DOCUMENT, signaturePrivateKey);
-
- PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
- String userId = getMainUserId(getMasterKey(signingKeyRing));
- spGen.setSignerUserID(false, userId);
- signatureGenerator.setHashedSubpackets(spGen.generate());
- }
-
- if (progress != null)
- progress.setProgress(R.string.progress_signing, 40, 100);
-
- armorOut.beginClearText(hashAlgorithm);
-
- InputStream inStream = data.getInputStream();
- final BufferedReader reader = new BufferedReader(new InputStreamReader(inStream));
-
- final byte[] newline = "\r\n".getBytes("UTF-8");
-
- if (forceV3Signature) {
- processLine(reader.readLine(), armorOut, signatureV3Generator);
- } else {
- processLine(reader.readLine(), armorOut, signatureGenerator);
- }
-
- while (true) {
- final String line = reader.readLine();
-
- if (line == null) {
- armorOut.write(newline);
- break;
- }
-
- armorOut.write(newline);
- if (forceV3Signature) {
- signatureV3Generator.update(newline);
- processLine(line, armorOut, signatureV3Generator);
- } else {
- signatureGenerator.update(newline);
- processLine(line, armorOut, signatureGenerator);
- }
- }
-
- armorOut.endClearText();
-
- BCPGOutputStream bOut = new BCPGOutputStream(armorOut);
- if (forceV3Signature) {
- signatureV3Generator.generate().encode(bOut);
- } else {
- signatureGenerator.generate().encode(bOut);
- }
- armorOut.close();
-
- if (progress != null)
- progress.setProgress(R.string.progress_done, 100, 100);
- }
-
- public static void generateSignature(Context context, InputData data, OutputStream outStream,
- boolean armored, boolean binary, long signatureKeyId, String signaturePassPhrase,
- int hashAlgorithm, boolean forceV3Signature, ProgressDialogUpdater progress)
- throws GeneralException, PGPException, IOException, NoSuchAlgorithmException,
- SignatureException {
-
- ArmoredOutputStream armorOut = null;
- OutputStream out = null;
- if (armored) {
- armorOut = new ArmoredOutputStream(outStream);
- armorOut.setHeader("Version", getFullVersion(context));
- out = armorOut;
- } else {
- out = outStream;
- }
-
- PGPSecretKey signingKey = null;
- PGPSecretKeyRing signingKeyRing = null;
- PGPPrivateKey signaturePrivateKey = null;
-
- if (signatureKeyId == 0) {
- throw new GeneralException(context.getString(R.string.error_noSignatureKey));
- }
-
- signingKeyRing = getSecretKeyRing(signatureKeyId);
- signingKey = getSigningKey(signatureKeyId);
- if (signingKey == null) {
- throw new GeneralException(context.getString(R.string.error_signatureFailed));
- }
-
- if (signaturePassPhrase == null) {
- throw new GeneralException(context.getString(R.string.error_noSignaturePassPhrase));
- }
- PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
- .setProvider("SC").build(signaturePassPhrase.toCharArray());
- signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
- if (signaturePrivateKey == null) {
- throw new GeneralException(context.getString(R.string.error_couldNotExtractPrivateKey));
- }
- if (progress != null)
- progress.setProgress(R.string.progress_preparingStreams, 0, 100);
-
- if (progress != null)
- progress.setProgress(R.string.progress_preparingSignature, 30, 100);
-
- PGPSignatureGenerator signatureGenerator = null;
- PGPV3SignatureGenerator signatureV3Generator = null;
-
- int type = PGPSignature.CANONICAL_TEXT_DOCUMENT;
- if (binary) {
- type = PGPSignature.BINARY_DOCUMENT;
- }
-
- if (forceV3Signature) {
- signatureV3Generator = new PGPV3SignatureGenerator(signingKey.getPublicKey()
- .getAlgorithm(), hashAlgorithm, new BouncyCastleProvider());
- signatureV3Generator.initSign(type, signaturePrivateKey);
- } else {
- signatureGenerator = new PGPSignatureGenerator(
- signingKey.getPublicKey().getAlgorithm(), hashAlgorithm,
- new BouncyCastleProvider());
- signatureGenerator.initSign(type, signaturePrivateKey);
-
- PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
- String userId = getMainUserId(getMasterKey(signingKeyRing));
- spGen.setSignerUserID(false, userId);
- signatureGenerator.setHashedSubpackets(spGen.generate());
- }
-
- if (progress != null)
- progress.setProgress(R.string.progress_signing, 40, 100);
-
- InputStream inStream = data.getInputStream();
- if (binary) {
- byte[] buffer = new byte[1 << 16];
- int n = 0;
- while ((n = inStream.read(buffer)) > 0) {
- if (forceV3Signature) {
- signatureV3Generator.update(buffer, 0, n);
- } else {
- signatureGenerator.update(buffer, 0, n);
- }
- }
- } else {
- final BufferedReader reader = new BufferedReader(new InputStreamReader(inStream));
- final byte[] newline = "\r\n".getBytes("UTF-8");
-
- while (true) {
- final String line = reader.readLine();
-
- if (line == null) {
- break;
- }
-
- if (forceV3Signature) {
- processLine(line, null, signatureV3Generator);
- signatureV3Generator.update(newline);
- } else {
- processLine(line, null, signatureGenerator);
- signatureGenerator.update(newline);
- }
- }
- }
-
- BCPGOutputStream bOut = new BCPGOutputStream(out);
- if (forceV3Signature) {
- signatureV3Generator.generate().encode(bOut);
- } else {
- signatureGenerator.generate().encode(bOut);
- }
- out.close();
- outStream.close();
-
- if (progress != null)
- progress.setProgress(R.string.progress_done, 100, 100);
- }
-
- public static long getDecryptionKeyId(Context context, InputData data) throws GeneralException,
- NoAsymmetricEncryptionException, IOException {
- InputStream in = PGPUtil.getDecoderStream(data.getInputStream());
- PGPObjectFactory pgpF = new PGPObjectFactory(in);
- PGPEncryptedDataList enc;
- Object o = pgpF.nextObject();
-
- // the first object might be a PGP marker packet.
- if (o instanceof PGPEncryptedDataList) {
- enc = (PGPEncryptedDataList) o;
- } else {
- enc = (PGPEncryptedDataList) pgpF.nextObject();
- }
-
- if (enc == null) {
- throw new GeneralException(context.getString(R.string.error_invalidData));
- }
-
- // TODO: currently we always only look at the first known key
- // find the secret key
- PGPSecretKey secretKey = null;
- Iterator> it = enc.getEncryptedDataObjects();
- boolean gotAsymmetricEncryption = false;
- while (it.hasNext()) {
- Object obj = it.next();
- if (obj instanceof PGPPublicKeyEncryptedData) {
- gotAsymmetricEncryption = true;
- PGPPublicKeyEncryptedData pbe = (PGPPublicKeyEncryptedData) obj;
- secretKey = getSecretKey(pbe.getKeyID());
- if (secretKey != null) {
- break;
- }
- }
- }
-
- if (!gotAsymmetricEncryption) {
- throw new NoAsymmetricEncryptionException();
- }
-
- if (secretKey == null) {
- return Id.key.none;
- }
-
- return secretKey.getKeyID();
- }
-
- public static boolean hasSymmetricEncryption(Context context, InputData data)
- throws GeneralException, IOException {
- InputStream in = PGPUtil.getDecoderStream(data.getInputStream());
- PGPObjectFactory pgpF = new PGPObjectFactory(in);
- PGPEncryptedDataList enc;
- Object o = pgpF.nextObject();
-
- // the first object might be a PGP marker packet.
- if (o instanceof PGPEncryptedDataList) {
- enc = (PGPEncryptedDataList) o;
- } else {
- enc = (PGPEncryptedDataList) pgpF.nextObject();
- }
-
- if (enc == null) {
- throw new GeneralException(context.getString(R.string.error_invalidData));
- }
-
- Iterator> it = enc.getEncryptedDataObjects();
- while (it.hasNext()) {
- Object obj = it.next();
- if (obj instanceof PGPPBEEncryptedData) {
- return true;
- }
- }
-
- return false;
- }
-
- public static Bundle decrypt(Context context, InputData data, OutputStream outStream,
- String passPhrase, ProgressDialogUpdater progress, boolean assumeSymmetric)
- throws IOException, GeneralException, PGPException, SignatureException {
- if (passPhrase == null) {
- passPhrase = "";
- }
- Bundle returnData = new Bundle();
- InputStream in = PGPUtil.getDecoderStream(data.getInputStream());
- PGPObjectFactory pgpF = new PGPObjectFactory(in);
- PGPEncryptedDataList enc;
- Object o = pgpF.nextObject();
- long signatureKeyId = 0;
-
- int currentProgress = 0;
- if (progress != null)
- progress.setProgress(R.string.progress_readingData, currentProgress, 100);
-
- if (o instanceof PGPEncryptedDataList) {
- enc = (PGPEncryptedDataList) o;
- } else {
- enc = (PGPEncryptedDataList) pgpF.nextObject();
- }
-
- if (enc == null) {
- throw new GeneralException(context.getString(R.string.error_invalidData));
- }
-
- InputStream clear = null;
- PGPEncryptedData encryptedData = null;
-
- currentProgress += 5;
-
- // TODO: currently we always only look at the first known key or symmetric encryption,
- // there might be more...
- if (assumeSymmetric) {
- PGPPBEEncryptedData pbe = null;
- Iterator> it = enc.getEncryptedDataObjects();
- // find secret key
- while (it.hasNext()) {
- Object obj = it.next();
- if (obj instanceof PGPPBEEncryptedData) {
- pbe = (PGPPBEEncryptedData) obj;
- break;
- }
- }
-
- if (pbe == null) {
- throw new GeneralException(
- context.getString(R.string.error_noSymmetricEncryptionPacket));
- }
-
- if (progress != null)
- progress.setProgress(R.string.progress_preparingStreams, currentProgress, 100);
- clear = pbe.getDataStream(passPhrase.toCharArray(), new BouncyCastleProvider());
- encryptedData = pbe;
- currentProgress += 5;
- } else {
- if (progress != null)
- progress.setProgress(R.string.progress_findingKey, currentProgress, 100);
- PGPPublicKeyEncryptedData pbe = null;
- PGPSecretKey secretKey = null;
- Iterator> it = enc.getEncryptedDataObjects();
- // find secret key
- while (it.hasNext()) {
- Object obj = it.next();
- if (obj instanceof PGPPublicKeyEncryptedData) {
- PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj;
- secretKey = getSecretKey(encData.getKeyID());
- if (secretKey != null) {
- pbe = encData;
- break;
- }
- }
- }
-
- if (secretKey == null) {
- throw new GeneralException(context.getString(R.string.error_noSecretKeyFound));
- }
-
- currentProgress += 5;
- if (progress != null)
- progress.setProgress(R.string.progress_extractingKey, currentProgress, 100);
- PGPPrivateKey privateKey = null;
- try {
- PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
- .setProvider("SC").build(passPhrase.toCharArray());
- privateKey = secretKey.extractPrivateKey(keyDecryptor);
- } catch (PGPException e) {
- throw new PGPException(context.getString(R.string.error_wrongPassPhrase));
- }
- if (privateKey == null) {
- throw new GeneralException(
- context.getString(R.string.error_couldNotExtractPrivateKey));
- }
- currentProgress += 5;
- if (progress != null)
- progress.setProgress(R.string.progress_preparingStreams, currentProgress, 100);
- clear = pbe.getDataStream(privateKey, new BouncyCastleProvider());
- encryptedData = pbe;
- currentProgress += 5;
- }
-
- PGPObjectFactory plainFact = new PGPObjectFactory(clear);
- Object dataChunk = plainFact.nextObject();
- PGPOnePassSignature signature = null;
- PGPPublicKey signatureKey = null;
- int signatureIndex = -1;
-
- if (dataChunk instanceof PGPCompressedData) {
- if (progress != null)
- progress.setProgress(R.string.progress_decompressingData, currentProgress, 100);
- PGPObjectFactory fact = new PGPObjectFactory(
- ((PGPCompressedData) dataChunk).getDataStream());
- dataChunk = fact.nextObject();
- plainFact = fact;
- currentProgress += 10;
- }
-
- if (dataChunk instanceof PGPOnePassSignatureList) {
- if (progress != null)
- progress.setProgress(R.string.progress_processingSignature, currentProgress, 100);
- returnData.putBoolean(EXTRA_SIGNATURE, true);
- PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) dataChunk;
- for (int i = 0; i < sigList.size(); ++i) {
- signature = sigList.get(i);
- signatureKey = getPublicKey(signature.getKeyID());
- if (signatureKeyId == 0) {
- signatureKeyId = signature.getKeyID();
- }
- if (signatureKey == null) {
- signature = null;
- } else {
- signatureIndex = i;
- signatureKeyId = signature.getKeyID();
- String userId = null;
- PGPPublicKeyRing sigKeyRing = getPublicKeyRing(signatureKeyId);
- if (sigKeyRing != null) {
- userId = getMainUserId(getMasterKey(sigKeyRing));
- }
- returnData.putString(EXTRA_SIGNATURE_USER_ID, userId);
- break;
- }
- }
-
- returnData.putLong(EXTRA_SIGNATURE_KEY_ID, signatureKeyId);
-
- if (signature != null) {
- signature.initVerify(signatureKey, new BouncyCastleProvider());
- } else {
- returnData.putBoolean(EXTRA_SIGNATURE_UNKNOWN, true);
- }
-
- dataChunk = plainFact.nextObject();
- currentProgress += 10;
- }
-
- if (dataChunk instanceof PGPSignatureList) {
- dataChunk = plainFact.nextObject();
- }
-
- if (dataChunk instanceof PGPLiteralData) {
- if (progress != null)
- progress.setProgress(R.string.progress_decrypting, currentProgress, 100);
- PGPLiteralData literalData = (PGPLiteralData) dataChunk;
- OutputStream out = outStream;
-
- byte[] buffer = new byte[1 << 16];
- InputStream dataIn = literalData.getInputStream();
-
- int startProgress = currentProgress;
- int endProgress = 100;
- if (signature != null) {
- endProgress = 90;
- } else if (encryptedData.isIntegrityProtected()) {
- endProgress = 95;
- }
- int n = 0;
- int done = 0;
- long startPos = data.getStreamPosition();
- while ((n = dataIn.read(buffer)) > 0) {
- out.write(buffer, 0, n);
- done += n;
- if (signature != null) {
- try {
- signature.update(buffer, 0, n);
- } catch (SignatureException e) {
- returnData.putBoolean(EXTRA_SIGNATURE_SUCCESS, false);
- signature = null;
- }
- }
- // unknown size, but try to at least have a moving, slowing down progress bar
- currentProgress = startProgress + (endProgress - startProgress) * done
- / (done + 100000);
- if (data.getSize() - startPos == 0) {
- currentProgress = endProgress;
- } else {
- currentProgress = (int) (startProgress + (endProgress - startProgress)
- * (data.getStreamPosition() - startPos) / (data.getSize() - startPos));
- }
- if (progress != null)
- progress.setProgress(currentProgress, 100);
- }
-
- if (signature != null) {
- if (progress != null)
- progress.setProgress(R.string.progress_verifyingSignature, 90, 100);
- PGPSignatureList signatureList = (PGPSignatureList) plainFact.nextObject();
- PGPSignature messageSignature = signatureList.get(signatureIndex);
- if (signature.verify(messageSignature)) {
- returnData.putBoolean(EXTRA_SIGNATURE_SUCCESS, true);
- } else {
- returnData.putBoolean(EXTRA_SIGNATURE_SUCCESS, false);
- }
- }
- }
-
- // TODO: add integrity somewhere
- if (encryptedData.isIntegrityProtected()) {
- if (progress != null)
- progress.setProgress(R.string.progress_verifyingIntegrity, 95, 100);
- if (encryptedData.verify()) {
- // passed
- } else {
- // failed
- }
- } else {
- // no integrity check
- }
-
- if (progress != null)
- progress.setProgress(R.string.progress_done, 100, 100);
- return returnData;
- }
-
- public static Bundle verifyText(BaseActivity context, InputData data, OutputStream outStream,
- ProgressDialogUpdater progress) throws IOException, GeneralException, PGPException,
- SignatureException {
- Bundle returnData = new Bundle();
-
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- ArmoredInputStream aIn = new ArmoredInputStream(data.getInputStream());
-
- if (progress != null)
- progress.setProgress(R.string.progress_done, 0, 100);
-
- // mostly taken from ClearSignedFileProcessor
- ByteArrayOutputStream lineOut = new ByteArrayOutputStream();
- int lookAhead = readInputLine(lineOut, aIn);
- byte[] lineSep = getLineSeparator();
-
- byte[] line = lineOut.toByteArray();
- out.write(line, 0, getLengthWithoutSeparator(line));
- out.write(lineSep);
-
- while (lookAhead != -1 && aIn.isClearText()) {
- lookAhead = readInputLine(lineOut, lookAhead, aIn);
- line = lineOut.toByteArray();
- out.write(line, 0, getLengthWithoutSeparator(line));
- out.write(lineSep);
- }
-
- out.close();
-
- byte[] clearText = out.toByteArray();
- outStream.write(clearText);
-
- returnData.putBoolean(EXTRA_SIGNATURE, true);
-
- if (progress != null)
- progress.setProgress(R.string.progress_processingSignature, 60, 100);
- PGPObjectFactory pgpFact = new PGPObjectFactory(aIn);
-
- PGPSignatureList sigList = (PGPSignatureList) pgpFact.nextObject();
- if (sigList == null) {
- throw new GeneralException(context.getString(R.string.error_corruptData));
- }
- PGPSignature signature = null;
- long signatureKeyId = 0;
- PGPPublicKey signatureKey = null;
- for (int i = 0; i < sigList.size(); ++i) {
- signature = sigList.get(i);
- signatureKey = getPublicKey(signature.getKeyID());
- if (signatureKeyId == 0) {
- signatureKeyId = signature.getKeyID();
- }
- if (signatureKey == null) {
- Bundle pauseData = new Bundle();
- pauseData.putInt(Constants.extras.STATUS, Id.message.unknown_signature_key);
- pauseData.putLong(Constants.extras.KEY_ID, signatureKeyId);
- Message msg = new Message();
- msg.setData(pauseData);
- context.sendMessage(msg);
- // pause here
- context.getRunningThread().pause();
- // see whether the key was found in the meantime
- signatureKey = getPublicKey(signature.getKeyID());
- }
-
- if (signatureKey == null) {
- signature = null;
- } else {
- signatureKeyId = signature.getKeyID();
- String userId = null;
- PGPPublicKeyRing sigKeyRing = getPublicKeyRing(signatureKeyId);
- if (sigKeyRing != null) {
- userId = getMainUserId(getMasterKey(sigKeyRing));
- }
- returnData.putString(EXTRA_SIGNATURE_USER_ID, userId);
- break;
- }
- }
-
- returnData.putLong(EXTRA_SIGNATURE_KEY_ID, signatureKeyId);
-
- if (signature == null) {
- returnData.putBoolean(EXTRA_SIGNATURE_UNKNOWN, true);
- if (progress != null)
- progress.setProgress(R.string.progress_done, 100, 100);
- return returnData;
- }
-
- signature.initVerify(signatureKey, new BouncyCastleProvider());
-
- InputStream sigIn = new BufferedInputStream(new ByteArrayInputStream(clearText));
-
- lookAhead = readInputLine(lineOut, sigIn);
-
- processLine(signature, lineOut.toByteArray());
-
- if (lookAhead != -1) {
- do {
- lookAhead = readInputLine(lineOut, lookAhead, sigIn);
-
- signature.update((byte) '\r');
- signature.update((byte) '\n');
-
- processLine(signature, lineOut.toByteArray());
- } while (lookAhead != -1);
- }
-
- returnData.putBoolean(EXTRA_SIGNATURE_SUCCESS, signature.verify());
-
- if (progress != null)
- progress.setProgress(R.string.progress_done, 100, 100);
- return returnData;
- }
-
- public static int getStreamContent(Context context, InputStream inStream) throws IOException {
- InputStream in = PGPUtil.getDecoderStream(inStream);
- PGPObjectFactory pgpF = new PGPObjectFactory(in);
- Object object = pgpF.nextObject();
- while (object != null) {
- if (object instanceof PGPPublicKeyRing || object instanceof PGPSecretKeyRing) {
- return Id.content.keys;
- } else if (object instanceof PGPEncryptedDataList) {
- return Id.content.encrypted_data;
- }
- object = pgpF.nextObject();
- }
-
- return Id.content.unknown;
- }
-
- private static void processLine(final String pLine, final ArmoredOutputStream pArmoredOutput,
- final PGPSignatureGenerator pSignatureGenerator) throws IOException, SignatureException {
-
- if (pLine == null) {
- return;
- }
-
- final char[] chars = pLine.toCharArray();
- int len = chars.length;
-
- while (len > 0) {
- if (!Character.isWhitespace(chars[len - 1])) {
- break;
- }
- len--;
- }
-
- final byte[] data = pLine.substring(0, len).getBytes("UTF-8");
-
- if (pArmoredOutput != null) {
- pArmoredOutput.write(data);
- }
- pSignatureGenerator.update(data);
- }
-
- private static void processLine(final String pLine, final ArmoredOutputStream pArmoredOutput,
- final PGPV3SignatureGenerator pSignatureGenerator) throws IOException,
- SignatureException {
-
- if (pLine == null) {
- return;
- }
-
- final char[] chars = pLine.toCharArray();
- int len = chars.length;
-
- while (len > 0) {
- if (!Character.isWhitespace(chars[len - 1])) {
- break;
- }
- len--;
- }
-
- final byte[] data = pLine.substring(0, len).getBytes("UTF-8");
-
- if (pArmoredOutput != null) {
- pArmoredOutput.write(data);
- }
- pSignatureGenerator.update(data);
- }
-
- // taken from ClearSignedFileProcessor in BC
- private static void processLine(PGPSignature sig, byte[] line) throws SignatureException,
- IOException {
- int length = getLengthWithoutWhiteSpace(line);
- if (length > 0) {
- sig.update(line, 0, length);
- }
- }
-
- private static int readInputLine(ByteArrayOutputStream bOut, InputStream fIn)
- throws IOException {
- bOut.reset();
-
- int lookAhead = -1;
- int ch;
-
- while ((ch = fIn.read()) >= 0) {
- bOut.write(ch);
- if (ch == '\r' || ch == '\n') {
- lookAhead = readPassedEOL(bOut, ch, fIn);
- break;
- }
- }
-
- return lookAhead;
- }
-
- private static int readInputLine(ByteArrayOutputStream bOut, int lookAhead, InputStream fIn)
- throws IOException {
- bOut.reset();
-
- int ch = lookAhead;
-
- do {
- bOut.write(ch);
- if (ch == '\r' || ch == '\n') {
- lookAhead = readPassedEOL(bOut, ch, fIn);
- break;
- }
- } while ((ch = fIn.read()) >= 0);
-
- if (ch < 0) {
- lookAhead = -1;
- }
-
- return lookAhead;
- }
-
- private static int readPassedEOL(ByteArrayOutputStream bOut, int lastCh, InputStream fIn)
- throws IOException {
- int lookAhead = fIn.read();
-
- if (lastCh == '\r' && lookAhead == '\n') {
- bOut.write(lookAhead);
- lookAhead = fIn.read();
- }
-
- return lookAhead;
- }
-
- private static int getLengthWithoutSeparator(byte[] line) {
- int end = line.length - 1;
-
- while (end >= 0 && isLineEnding(line[end])) {
- end--;
- }
-
- return end + 1;
- }
-
- private static boolean isLineEnding(byte b) {
- return b == '\r' || b == '\n';
- }
-
- private static int getLengthWithoutWhiteSpace(byte[] line) {
- int end = line.length - 1;
-
- while (end >= 0 && isWhiteSpace(line[end])) {
- end--;
- }
-
- return end + 1;
- }
-
- private static boolean isWhiteSpace(byte b) {
- return b == '\r' || b == '\n' || b == '\t' || b == ' ';
- }
-
- private static byte[] getLineSeparator() {
- String nl = System.getProperty("line.separator");
- byte[] nlBytes = new byte[nl.length()];
-
- for (int i = 0; i != nlBytes.length; i++) {
- nlBytes[i] = (byte) nl.charAt(i);
- }
-
- return nlBytes;
- }
-
- public static boolean isReleaseVersion(Context context) {
- try {
- PackageInfo pi = context.getPackageManager().getPackageInfo(PACKAGE_NAME, 0);
- if (pi.versionCode % 100 == 99) {
- return true;
- } else {
- return false;
- }
- } catch (NameNotFoundException e) {
- // impossible!
- return false;
- }
- }
-
- public static String getVersion(Context context) {
- if (VERSION != null) {
- return VERSION;
- }
- try {
- PackageInfo pi = context.getPackageManager().getPackageInfo(PACKAGE_NAME, 0);
- VERSION = pi.versionName;
- return VERSION;
- } catch (NameNotFoundException e) {
- // impossible!
- return "0.0.0";
- }
- }
-
- public static String getFullVersion(Context context) {
- return "APG v" + getVersion(context);
- }
-
- public static String generateRandomString(int length) {
- SecureRandom random = new SecureRandom();
- /*
- * try { random = SecureRandom.getInstance("SHA1PRNG", new BouncyCastleProvider()); } catch
- * (NoSuchAlgorithmException e) { // TODO: need to handle this case somehow return null; }
- */
- byte bytes[] = new byte[length];
- random.nextBytes(bytes);
- String result = "";
- for (int i = 0; i < length; ++i) {
- int v = (bytes[i] + 256) % 64;
- if (v < 10) {
- result += (char) ('0' + v);
- } else if (v < 36) {
- result += (char) ('A' + v - 10);
- } else if (v < 62) {
- result += (char) ('a' + v - 36);
- } else if (v == 62) {
- result += '_';
- } else if (v == 63) {
- result += '.';
- }
- }
- return result;
- }
-
- public static long getLengthOfStream(InputStream in) throws IOException {
- long size = 0;
- long n = 0;
- byte dummy[] = new byte[0x10000];
- while ((n = in.read(dummy)) > 0) {
- size += n;
- }
- return size;
- }
-
- public static void deleteFileSecurely(Context context, File file, ProgressDialogUpdater progress)
- throws FileNotFoundException, IOException {
- long length = file.length();
- SecureRandom random = new SecureRandom();
- RandomAccessFile raf = new RandomAccessFile(file, "rws");
- raf.seek(0);
- raf.getFilePointer();
- byte[] data = new byte[1 << 16];
- int pos = 0;
- String msg = context.getString(R.string.progress_deletingSecurely, file.getName());
- while (pos < length) {
- if (progress != null)
- progress.setProgress(msg, (int) (100 * pos / length), 100);
- random.nextBytes(data);
- raf.write(data);
- pos += data.length;
- }
- raf.close();
- file.delete();
- }
-}
diff --git a/org_apg/src/org/thialfihar/android/apg/ApgApplication.java b/org_apg/src/org/thialfihar/android/apg/ApgApplication.java
index b56e3182d..586685109 100644
--- a/org_apg/src/org/thialfihar/android/apg/ApgApplication.java
+++ b/org_apg/src/org/thialfihar/android/apg/ApgApplication.java
@@ -26,7 +26,7 @@ public class ApgApplication extends Application {
public void onCreate() {
super.onCreate();
- /** Start passphrase cache service */
+ /* Start passphrase cache service */
PassphraseCacheService.startCacheService(this);
}
diff --git a/org_apg/src/org/thialfihar/android/apg/Constants.java b/org_apg/src/org/thialfihar/android/apg/Constants.java
index a0aaf5b5f..a9c4d04df 100644
--- a/org_apg/src/org/thialfihar/android/apg/Constants.java
+++ b/org_apg/src/org/thialfihar/android/apg/Constants.java
@@ -27,8 +27,6 @@ public final class Constants {
}
public static final class pref {
- public static final String HAS_SEEN_HELP = "seenHelp";
- public static final String HAS_SEEN_CHANGE_LOG = "seenChangeLogDialog";
public static final String DEFAULT_ENCRYPTION_ALGORITHM = "defaultEncryptionAlgorithm";
public static final String DEFAULT_HASH_ALGORITHM = "defaultHashAlgorithm";
public static final String DEFAULT_ASCII_ARMOUR = "defaultAsciiArmour";
@@ -44,6 +42,7 @@ public final class Constants {
public static final String KEY_SERVERS = "pool.sks-keyservers.net, subkeys.pgp.net, pgp.mit.edu";
}
+ // TODO: rework!
public static final class extras {
public static final String PROGRESS = "progress";
public static final String PROGRESS_MAX = "max";
diff --git a/org_apg/src/org/thialfihar/android/apg/DataDestination.java b/org_apg/src/org/thialfihar/android/apg/DataDestination.java
deleted file mode 100644
index 6fa60889c..000000000
--- a/org_apg/src/org/thialfihar/android/apg/DataDestination.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * 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.thialfihar.android.apg;
-
-import java.io.ByteArrayOutputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.Serializable;
-
-import org.thialfihar.android.apg.R;
-import org.thialfihar.android.apg.Apg.GeneralException;
-
-import android.content.Context;
-import android.os.Environment;
-
-public class DataDestination implements Serializable {
-
- private static final long serialVersionUID = -6478075911319320498L;
-
- private String mStreamFilename;
- private String mFilename;
- private int mMode = Id.mode.undefined;
-
- public DataDestination() {
-
- }
-
- public void setMode(int mode) {
- mMode = mode;
- }
-
- public void setFilename(String filename) {
- mFilename = filename;
- }
-
- public String getStreamFilename() {
- return mStreamFilename;
- }
-
- public OutputStream getOutputStream(Context context) throws Apg.GeneralException,
- FileNotFoundException, IOException {
- OutputStream out = null;
- mStreamFilename = null;
-
- switch (mMode) {
- case Id.mode.stream: {
- try {
- while (true) {
- mStreamFilename = Apg.generateRandomString(32);
- if (mStreamFilename == null) {
- throw new Apg.GeneralException("couldn't generate random file name");
- }
- context.openFileInput(mStreamFilename).close();
- }
- } catch (FileNotFoundException e) {
- // found a name that isn't used yet
- }
- out = context.openFileOutput(mStreamFilename, Context.MODE_PRIVATE);
- break;
- }
-
- case Id.mode.byte_array: {
- out = new ByteArrayOutputStream();
- break;
- }
-
- case Id.mode.file: {
- if (mFilename.startsWith(Environment.getExternalStorageDirectory().getAbsolutePath())) {
- if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- throw new GeneralException(
- context.getString(R.string.error_externalStorageNotReady));
- }
- }
- out = new FileOutputStream(mFilename);
- break;
- }
-
- default: {
- break;
- }
- }
-
- return out;
- }
-}
diff --git a/org_apg/src/org/thialfihar/android/apg/DataSource.java b/org_apg/src/org/thialfihar/android/apg/DataSource.java
deleted file mode 100644
index 503e0867f..000000000
--- a/org_apg/src/org/thialfihar/android/apg/DataSource.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * 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.thialfihar.android.apg;
-
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.Serializable;
-
-import org.thialfihar.android.apg.R;
-import org.thialfihar.android.apg.Apg.GeneralException;
-
-import android.content.Context;
-import android.net.Uri;
-import android.os.Environment;
-
-public class DataSource implements Serializable {
-
- private static final long serialVersionUID = 2377217399907415255L;
-
- private Uri mContentUri = null;
- private String mText = null;
- private byte[] mData = null;
-
- public DataSource() {
-
- }
-
- public void setUri(Uri uri) {
- mContentUri = uri;
- mText = null;
- mData = null;
- }
-
- public void setUri(String uri) {
- if (uri.startsWith("/")) {
- setUri(Uri.parse("file://" + uri));
- } else {
- setUri(Uri.parse(uri));
- }
- }
-
- public Uri getUri() {
- return mContentUri;
- }
-
- public void setText(String text) {
- mText = text;
- mData = null;
- mContentUri = null;
- }
-
- public void setData(byte[] data) {
- mData = data;
- mText = null;
- mContentUri = null;
- }
-
- public boolean isText() {
- return mText != null;
- }
-
- public boolean isBinary() {
- return mData != null || mContentUri != null;
- }
-
- public byte[] getBytes() {
- byte[] bytes = null;
- if (mData != null) {
- bytes = mData;
- } else {
- bytes = mText.getBytes();
- }
-
- return bytes;
- }
-
- public InputData getInputData(Context context, boolean withSize) throws GeneralException,
- FileNotFoundException, IOException {
- InputStream in = null;
- long size = 0;
-
- if (mContentUri != null) {
- if (mContentUri.getScheme().equals("file")) {
- // get the rest after "file://"
- String path = Uri.decode(mContentUri.toString().substring(7));
- if (path.startsWith(Environment.getExternalStorageDirectory().getAbsolutePath())) {
- if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- throw new GeneralException(
- context.getString(R.string.error_externalStorageNotReady));
- }
- }
- in = new FileInputStream(path);
- File file = new File(path);
- if (withSize) {
- size = file.length();
- }
- } else {
- in = context.getContentResolver().openInputStream(mContentUri);
- if (withSize) {
- InputStream tmp = context.getContentResolver().openInputStream(mContentUri);
- size = Apg.getLengthOfStream(tmp);
- tmp.close();
- }
- }
- } else if (mText != null || mData != null) {
- byte[] bytes = null;
- if (mData != null) {
- bytes = mData;
- } else {
- bytes = mText.getBytes();
- }
- in = new ByteArrayInputStream(bytes);
- if (withSize) {
- size = bytes.length;
- }
- }
-
- return new InputData(in, size);
- }
-
-}
diff --git a/org_apg/src/org/thialfihar/android/apg/FileDialog.java b/org_apg/src/org/thialfihar/android/apg/FileDialog.java
deleted file mode 100644
index 742379a27..000000000
--- a/org_apg/src/org/thialfihar/android/apg/FileDialog.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2010 Thialfihar
- *
- * 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.thialfihar.android.apg;
-
-import org.thialfihar.android.apg.R;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.net.Uri;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.CheckBox;
-import android.widget.EditText;
-import android.widget.ImageButton;
-import android.widget.Toast;
-
-/**
- *
- *
- * SHOUDL BE DELTED, DileDialogFragment is the new implementation
- *
- *
- * @author ds1
- *
- */
-public class FileDialog {
- private static EditText mFilename;
- private static ImageButton mBrowse;
- private static CheckBox mCheckBox;
- private static Activity mActivity;
- private static int mRequestCode;
-
- public static interface OnClickListener {
- public void onCancelClick();
-
- public void onOkClick(String filename, boolean checkbox);
- }
-
- public static AlertDialog build(Activity activity, String title, String message,
- String defaultFile, OnClickListener onClickListener, String fileManagerTitle,
- String fileManagerButton, String checkboxText, int requestCode) {
- // TODO: fileManagerTitle and fileManagerButton are deprecated, no use for them right now,
- // but maybe the Intent now used will someday support them again, so leaving them in
- LayoutInflater inflater = (LayoutInflater) activity
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- AlertDialog.Builder alert = new AlertDialog.Builder(activity);
-
- alert.setTitle(title);
- alert.setMessage(message);
-
- View view = inflater.inflate(R.layout.file_dialog, null);
-
- mActivity = activity;
- mFilename = (EditText) view.findViewById(R.id.input);
- mFilename.setText(defaultFile);
- mBrowse = (ImageButton) view.findViewById(R.id.btn_browse);
- mBrowse.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- openFile();
- }
- });
- mRequestCode = requestCode;
- mCheckBox = (CheckBox) view.findViewById(R.id.checkbox);
- if (checkboxText == null) {
- mCheckBox.setEnabled(false);
- mCheckBox.setVisibility(View.GONE);
- } else {
- mCheckBox.setEnabled(true);
- mCheckBox.setVisibility(View.VISIBLE);
- mCheckBox.setText(checkboxText);
- }
-
- alert.setView(view);
-
- final OnClickListener clickListener = onClickListener;
-
- alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- boolean checked = false;
- if (mCheckBox.isEnabled()) {
- checked = mCheckBox.isChecked();
- }
- clickListener.onOkClick(mFilename.getText().toString(), checked);
- }
- });
-
- alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- clickListener.onCancelClick();
- }
- });
- return alert.create();
- }
-
- public static void setFilename(String filename) {
- if (mFilename != null) {
- mFilename.setText(filename);
- }
- }
-
- /**
- * Opens the file manager to select a file to open.
- */
- private static void openFile() {
- String filename = mFilename.getText().toString();
-
- Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
- intent.addCategory(Intent.CATEGORY_OPENABLE);
-
- intent.setData(Uri.parse("file://" + filename));
- intent.setType("text/plain"); // only .asc or .gpg files
-
- try {
- mActivity.startActivityForResult(intent, mRequestCode);
- } catch (ActivityNotFoundException e) {
- // No compatible file manager was found.
- Toast.makeText(mActivity, R.string.noFilemanagerInstalled, Toast.LENGTH_SHORT).show();
- }
- }
-}
diff --git a/org_apg/src/org/thialfihar/android/apg/HkpKeyServer.java b/org_apg/src/org/thialfihar/android/apg/HkpKeyServer.java
index bfbb30c8c..aa3131a92 100644
--- a/org_apg/src/org/thialfihar/android/apg/HkpKeyServer.java
+++ b/org_apg/src/org/thialfihar/android/apg/HkpKeyServer.java
@@ -1,4 +1,6 @@
/*
+ * Copyright (C) 2011 Senecaso
+ *
* 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
@@ -42,6 +44,7 @@ import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
+import org.thialfihar.android.apg.helper.PGPHelper;
import android.text.Html;
@@ -178,8 +181,8 @@ public class HkpKeyServer extends KeyServer {
KeyInfo info = new KeyInfo();
info.size = Integer.parseInt(matcher.group(1));
info.algorithm = matcher.group(2);
- info.keyId = Apg.keyFromHex(matcher.group(3));
- info.fingerPrint = Apg.getSmallFingerPrint(info.keyId);
+ info.keyId = PGPHelper.keyFromHex(matcher.group(3));
+ info.fingerPrint = PGPHelper.getSmallFingerPrint(info.keyId);
String chunks[] = matcher.group(4).split("-");
info.date = new GregorianCalendar(Integer.parseInt(chunks[0]),
Integer.parseInt(chunks[1]), Integer.parseInt(chunks[2])).getTime();
@@ -210,7 +213,7 @@ public class HkpKeyServer extends KeyServer {
HttpClient client = new DefaultHttpClient();
try {
HttpGet get = new HttpGet("http://" + mHost + ":" + mPort
- + "/pks/lookup?op=get&search=0x" + Apg.keyToHex(keyId));
+ + "/pks/lookup?op=get&search=0x" + PGPHelper.keyToHex(keyId));
HttpResponse response = client.execute(get);
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
@@ -220,7 +223,7 @@ public class HkpKeyServer extends KeyServer {
HttpEntity entity = response.getEntity();
InputStream is = entity.getContent();
String data = readAll(is, EntityUtils.getContentCharSet(entity));
- Matcher matcher = Apg.PGP_PUBLIC_KEY.matcher(data);
+ Matcher matcher = PGPHelper.PGP_PUBLIC_KEY.matcher(data);
if (matcher.find()) {
return matcher.group(1);
}
@@ -234,7 +237,7 @@ public class HkpKeyServer extends KeyServer {
}
@Override
- void add(String armouredText) throws AddKeyException {
+ public void add(String armouredText) throws AddKeyException {
HttpClient client = new DefaultHttpClient();
try {
HttpPost post = new HttpPost("http://" + mHost + ":" + mPort + "/pks/add");
diff --git a/org_apg/src/org/thialfihar/android/apg/Id.java b/org_apg/src/org/thialfihar/android/apg/Id.java
index d4d23b80e..bc40f59e6 100644
--- a/org_apg/src/org/thialfihar/android/apg/Id.java
+++ b/org_apg/src/org/thialfihar/android/apg/Id.java
@@ -18,6 +18,13 @@ package org.thialfihar.android.apg;
import org.spongycastle.bcpg.CompressionAlgorithmTags;
+/**
+ *
+ * TODO:
+ *
+ * - refactor ids, some are not needed and can be done with xml
+ *
+ */
public final class Id {
public static final String TAG = "APG";
@@ -83,7 +90,7 @@ public final class Id {
// public static final int query_done = 0x21070010;
// public static final int unknown_signature_key = 0x21070011;
// }
-
+
// use only lower 16 bits due to compatibility lib
public static final class request {
public static final int public_keys = 0x00007001;
@@ -96,18 +103,18 @@ public final class Id {
public static final int import_from_qr_code = 0x00007008;
public static final int sign_key = 0x00007009;
}
-
-// public static final class request {
-// public static final int public_keys = 0x21070001;
-// public static final int secret_keys = 0x21070002;
-// public static final int filename = 0x21070003;
-// public static final int output_filename = 0x21070004;
-// public static final int key_server_preference = 0x21070005;
-// public static final int look_up_key_id = 0x21070006;
-// public static final int export_to_server = 0x21070007;
-// public static final int import_from_qr_code = 0x21070008;
-// public static final int sign_key = 0x21070009;
-// }
+
+ // public static final class request {
+ // public static final int public_keys = 0x21070001;
+ // public static final int secret_keys = 0x21070002;
+ // public static final int filename = 0x21070003;
+ // public static final int output_filename = 0x21070004;
+ // public static final int key_server_preference = 0x21070005;
+ // public static final int look_up_key_id = 0x21070006;
+ // public static final int export_to_server = 0x21070007;
+ // public static final int import_from_qr_code = 0x21070008;
+ // public static final int sign_key = 0x21070009;
+ // }
public static final class dialog {
public static final int pass_phrase = 0x21070001;
diff --git a/org_apg/src/org/thialfihar/android/apg/InputData.java b/org_apg/src/org/thialfihar/android/apg/InputData.java
deleted file mode 100644
index ba6caa1c5..000000000
--- a/org_apg/src/org/thialfihar/android/apg/InputData.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.thialfihar.android.apg;
-
-import java.io.InputStream;
-
-public class InputData {
- private PositionAwareInputStream mInputStream;
- private long mSize;
-
- public InputData(InputStream inputStream, long size) {
- mInputStream = new PositionAwareInputStream(inputStream);
- mSize = size;
- }
-
- public InputStream getInputStream() {
- return mInputStream;
- }
-
- public long getSize() {
- return mSize;
- }
-
- public long getStreamPosition() {
- return mInputStream.position();
- }
-}
diff --git a/org_apg/src/org/thialfihar/android/apg/KeyServer.java b/org_apg/src/org/thialfihar/android/apg/KeyServer.java
index bf9335a0c..b1420ad0f 100644
--- a/org_apg/src/org/thialfihar/android/apg/KeyServer.java
+++ b/org_apg/src/org/thialfihar/android/apg/KeyServer.java
@@ -1,4 +1,6 @@
/*
+ * Copyright (C) 2011 Senecaso
+ *
* 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
diff --git a/org_apg/src/org/thialfihar/android/apg/PositionAwareInputStream.java b/org_apg/src/org/thialfihar/android/apg/PositionAwareInputStream.java
deleted file mode 100644
index d49713ae6..000000000
--- a/org_apg/src/org/thialfihar/android/apg/PositionAwareInputStream.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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.thialfihar.android.apg;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-public class PositionAwareInputStream extends InputStream {
- private InputStream mStream;
- private long mPosition;
-
- public PositionAwareInputStream(InputStream in) {
- mStream = in;
- mPosition = 0;
- }
-
- @Override
- public int read() throws IOException {
- int ch = mStream.read();
- ++mPosition;
- return ch;
- }
-
- @Override
- public int available() throws IOException {
- return mStream.available();
- }
-
- @Override
- public void close() throws IOException {
- mStream.close();
- }
-
- @Override
- public boolean markSupported() {
- return false;
- }
-
- @Override
- public int read(byte[] b) throws IOException {
- int result = mStream.read(b);
- mPosition += result;
- return result;
- }
-
- @Override
- public int read(byte[] b, int offset, int length) throws IOException {
- int result = mStream.read(b, offset, length);
- mPosition += result;
- return result;
- }
-
- @Override
- public synchronized void reset() throws IOException {
- mStream.reset();
- mPosition = 0;
- }
-
- @Override
- public long skip(long n) throws IOException {
- long result = mStream.skip(n);
- mPosition += result;
- return result;
- }
-
- public long position() {
- return mPosition;
- }
-}
diff --git a/org_apg/src/org/thialfihar/android/apg/Preferences.java b/org_apg/src/org/thialfihar/android/apg/Preferences.java
index d0b19b5d0..5c7c348ed 100644
--- a/org_apg/src/org/thialfihar/android/apg/Preferences.java
+++ b/org_apg/src/org/thialfihar/android/apg/Preferences.java
@@ -1,4 +1,7 @@
/*
+ * Copyright (C) 2012 Dominik Schürmann
+ * Copyright (C) 2010 Thialfihar
+ *
* 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
@@ -23,8 +26,7 @@ import android.content.SharedPreferences;
import java.util.Vector;
/**
- * Singelton Implementation of a Preference Helper
- *
+ * Singleton Implementation of a Preference Helper
*/
public class Preferences {
private static Preferences mPreferences;
diff --git a/org_apg/src/org/thialfihar/android/apg/Primes.java b/org_apg/src/org/thialfihar/android/apg/Primes.java
deleted file mode 100644
index f0f391291..000000000
--- a/org_apg/src/org/thialfihar/android/apg/Primes.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (C) 2010 Thialfihar
- *
- * 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.thialfihar.android.apg;
-
-import java.math.BigInteger;
-
-public final class Primes {
- // taken from http://www.ietf.org/rfc/rfc3526.txt
- public static final String P1536 =
- "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
- "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
- "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
- "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
- "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
- "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
- "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
- "670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF";
-
- public static final String P2048 =
- "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
- "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
- "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
- "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
- "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
- "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
- "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
- "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
- "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
- "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
- "15728E5A 8AACAA68 FFFFFFFF FFFFFFFF";
-
- public static final String P3072 =
- "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
- "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
- "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
- "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
- "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
- "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
- "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
- "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
- "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
- "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
- "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
- "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
- "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
- "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
- "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
- "43DB5BFC E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF";
-
- public static final String P4096 =
- "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
- "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
- "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
- "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
- "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
- "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
- "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
- "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
- "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
- "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
- "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
- "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
- "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
- "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
- "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
- "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
- "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
- "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
- "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
- "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
- "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199" +
- "FFFFFFFF FFFFFFFF";
-
- public static final String P6144 =
- "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
- "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
- "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
- "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
- "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
- "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
- "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
- "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
- "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
- "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
- "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
- "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
- "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
- "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
- "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
- "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
- "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
- "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
- "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
- "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
- "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" +
- "36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" +
- "F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" +
- "179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" +
- "DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" +
- "5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" +
- "D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" +
- "23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" +
- "CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" +
- "06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" +
- "DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" +
- "12BF2D5B 0B7474D6 E694F91E 6DCC4024 FFFFFFFF FFFFFFFF";
-
- public static final String P8192 =
- "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
- "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
- "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
- "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
- "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
- "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
- "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
- "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
- "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
- "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
- "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
- "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
- "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
- "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
- "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
- "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
- "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
- "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
- "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
- "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
- "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" +
- "36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" +
- "F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" +
- "179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" +
- "DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" +
- "5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" +
- "D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" +
- "23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" +
- "CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" +
- "06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" +
- "DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" +
- "12BF2D5B 0B7474D6 E694F91E 6DBE1159 74A3926F 12FEE5E4" +
- "38777CB6 A932DF8C D8BEC4D0 73B931BA 3BC832B6 8D9DD300" +
- "741FA7BF 8AFC47ED 2576F693 6BA42466 3AAB639C 5AE4F568" +
- "3423B474 2BF1C978 238F16CB E39D652D E3FDB8BE FC848AD9" +
- "22222E04 A4037C07 13EB57A8 1A23F0C7 3473FC64 6CEA306B" +
- "4BCBC886 2F8385DD FA9D4B7F A2C087E8 79683303 ED5BDD3A" +
- "062B3CF5 B3A278A6 6D2A13F8 3F44F82D DF310EE0 74AB6A36" +
- "4597E899 A0255DC1 64F31CC5 0846851D F9AB4819 5DED7EA1" +
- "B1D510BD 7EE74D73 FAF36BC3 1ECFA268 359046F4 EB879F92" +
- "4009438B 481C6CD7 889A002E D5EE382B C9190DA6 FC026E47" +
- "9558E447 5677E9AA 9E3050E2 765694DF C81F56E8 80B96E71" +
- "60C980DD 98EDD3DF FFFFFFFF FFFFFFFF";
-
- public static BigInteger getBestPrime(int keySize) {
- String primeString;
- if (keySize >= (8192 + 6144) / 2) {
- primeString = P8192;
- } else if (keySize >= (6144 + 4096) / 2) {
- primeString = P6144;
- } else if (keySize >= (4096 + 3072) / 2) {
- primeString = P4096;
- } else if (keySize >= (3072 + 2048) / 2) {
- primeString = P3072;
- } else if (keySize >= (2048 + 1536) / 2) {
- primeString = P2048;
- } else {
- primeString = P1536;
- }
-
- return new BigInteger(primeString.replaceAll(" ", ""), 16);
- }
-}
diff --git a/org_apg/src/org/thialfihar/android/apg/deprecated/ApgCon.java b/org_apg/src/org/thialfihar/android/apg/deprecated/ApgCon.java
new file mode 100644
index 000000000..d4d8d9a9c
--- /dev/null
+++ b/org_apg/src/org/thialfihar/android/apg/deprecated/ApgCon.java
@@ -0,0 +1,836 @@
+/*
+ * Copyright (C) 2011 Markus Doits
+ *
+ * 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.thialfihar.android.apg.deprecated;
+
+import org.thialfihar.android.apg.deprecated.ApgConInterface.OnCallFinishListener;
+import org.thialfihar.android.apg.deprecated.IApgService2;
+
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.util.Log;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+
+/**
+ * A APG-AIDL-Wrapper
+ *
+ *
+ * This class can be used by other projects to simplify connecting to the
+ * APG-AIDL-Service. Kind of wrapper of for AIDL.
+ *
+ *
+ *
+ * It is not used in this project.
+ *
+ *
+ * @author Markus Doits
+ * @version 1.1rc1
+ *
+ */
+public class ApgCon {
+ private static final boolean LOCAL_LOGV = true;
+ private static final boolean LOCAL_LOGD = true;
+
+ private final static String TAG = "ApgCon";
+ private final static int API_VERSION = 2; // aidl api-version it expects
+ private final static String BLOB_URI = "content://org.thialfihar.android.apg.provider.apgserviceblobprovider";
+
+ /**
+ * How many seconds to wait for a connection to AGP when connecting.
+ * Being unsuccessful for this number of seconds, a connection
+ * is assumed to be failed.
+ */
+ public int secondsToWaitForConnection = 15;
+
+ private class CallAsync extends AsyncTask {
+
+ @Override
+ protected Void doInBackground(String... arg) {
+ if( LOCAL_LOGD ) Log.d(TAG, "Async execution starting");
+ call(arg[0]);
+ return null;
+ }
+
+ protected void onPostExecute(Void res) {
+ if( LOCAL_LOGD ) Log.d(TAG, "Async execution finished");
+ mAsyncRunning = false;
+
+ }
+
+ }
+
+ private final Context mContext;
+ private final error mConnectionStatus;
+ private boolean mAsyncRunning = false;
+ private OnCallFinishListener mOnCallFinishListener;
+
+ private final Bundle mResult = new Bundle();
+ private final Bundle mArgs = new Bundle();
+ private final ArrayList mErrorList = new ArrayList();
+ private final ArrayList mWarningList = new ArrayList();
+
+ /** Remote service for decrypting and encrypting data */
+ private IApgService2 mApgService = null;
+
+ /** Set apgService accordingly to connection status */
+ private ServiceConnection mApgConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ if( LOCAL_LOGD ) Log.d(TAG, "IApgService bound to apgService");
+ mApgService = IApgService2.Stub.asInterface(service);
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ if( LOCAL_LOGD ) Log.d(TAG, "IApgService disconnected");
+ mApgService = null;
+ }
+ };
+
+ /**
+ * Different types of local errors
+ */
+ public static enum error {
+ /**
+ * no error
+ */
+ NO_ERROR,
+ /**
+ * generic error
+ */
+ GENERIC,
+ /**
+ * connection to apg service not possible
+ */
+ CANNOT_BIND_TO_APG,
+ /**
+ * function to call not provided
+ */
+ CALL_MISSING,
+ /**
+ * apg service does not know what to do
+ */
+ CALL_NOT_KNOWN,
+ /**
+ * could not find APG being installed
+ */
+ APG_NOT_FOUND,
+ /**
+ * found APG but without AIDL interface
+ */
+ APG_AIDL_MISSING,
+ /**
+ * found APG but with wrong API
+ */
+ APG_API_MISSMATCH
+ }
+
+ private static enum ret {
+ ERROR, // returned from AIDL
+ RESULT, // returned from AIDL
+ WARNINGS, // mixed AIDL and LOCAL
+ ERRORS, // mixed AIDL and LOCAL
+ }
+
+ /**
+ * Constructor
+ *
+ *
+ * Creates a new ApgCon object and searches for the right APG version on
+ * initialization. If not found, errors are printed to the error log.
+ *
+ *
+ * @param ctx
+ * the running context
+ */
+ public ApgCon(Context ctx) {
+ if( LOCAL_LOGV ) Log.v(TAG, "EncryptionService created");
+ mContext = ctx;
+
+ error tmpError = null;
+ try {
+ if( LOCAL_LOGV ) Log.v(TAG, "Searching for the right APG version");
+ ServiceInfo apgServices[] = ctx.getPackageManager().getPackageInfo("org.thialfihar.android.apg",
+ PackageManager.GET_SERVICES | PackageManager.GET_META_DATA).services;
+ if (apgServices == null) {
+ Log.e(TAG, "Could not fetch services");
+ tmpError = error.GENERIC;
+ } else {
+ boolean apgServiceFound = false;
+ for (ServiceInfo inf : apgServices) {
+ if( LOCAL_LOGV ) Log.v(TAG, "Found service of APG: " + inf.name);
+ if (inf.name.equals("org.thialfihar.android.apg.ApgService")) {
+ apgServiceFound = true;
+ if (inf.metaData == null) {
+ Log.w(TAG, "Could not determine ApgService API");
+ Log.w(TAG, "This probably won't work!");
+ mWarningList.add("(LOCAL) Could not determine ApgService API");
+ tmpError = error.APG_API_MISSMATCH;
+ } else if (inf.metaData.getInt("api_version") != API_VERSION) {
+ Log.w(TAG, "Found ApgService API version " + inf.metaData.getInt("api_version") + " but exspected " + API_VERSION);
+ Log.w(TAG, "This probably won't work!");
+ mWarningList.add("(LOCAL) Found ApgService API version " + inf.metaData.getInt("api_version") + " but exspected " + API_VERSION);
+ tmpError = error.APG_API_MISSMATCH;
+ } else {
+ if( LOCAL_LOGV ) Log.v(TAG, "Found api_version " + API_VERSION + ", everything should work");
+ tmpError = error.NO_ERROR;
+ }
+ }
+ }
+
+ if (!apgServiceFound) {
+ Log.e(TAG, "Could not find APG with AIDL interface, this probably won't work");
+ mErrorList.add("(LOCAL) Could not find APG with AIDL interface, this probably won't work");
+ mResult.putInt(ret.ERROR.name(), error.APG_AIDL_MISSING.ordinal());
+ tmpError = error.APG_NOT_FOUND;
+ }
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Could not find APG, is it installed?", e);
+ mErrorList.add("(LOCAL) Could not find APG, is it installed?");
+ mResult.putInt(ret.ERROR.name(), error.APG_NOT_FOUND.ordinal());
+ tmpError = error.APG_NOT_FOUND;
+ }
+
+ mConnectionStatus = tmpError;
+
+ }
+
+ /** try to connect to the apg service */
+ private boolean connect() {
+ if( LOCAL_LOGV ) Log.v(TAG, "trying to bind the apgService to context");
+
+ if (mApgService != null) {
+ if( LOCAL_LOGV ) Log.v(TAG, "allready connected");
+ return true;
+ }
+
+ try {
+ mContext.bindService(new Intent(IApgService2.class.getName()), mApgConnection, Context.BIND_AUTO_CREATE);
+ } catch (Exception e) {
+ Log.e(TAG, "could not bind APG service", e);
+ return false;
+ }
+
+ int waitCount = 0;
+ while (mApgService == null && waitCount++ < secondsToWaitForConnection) {
+ if( LOCAL_LOGV ) Log.v(TAG, "sleeping 1 second to wait for apg");
+ android.os.SystemClock.sleep(1000);
+ }
+
+ if (waitCount >= secondsToWaitForConnection) {
+ if( LOCAL_LOGV ) Log.v(TAG, "slept waiting for nothing!");
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Disconnects ApgCon from Apg
+ *
+ *
+ * This should be called whenever all work with APG is done (e.g. everything
+ * you wanted to encrypt is encrypted), since connections with AIDL should
+ * not be upheld indefinitely.
+ *
+ *
+ *
+ * Also, if you destroy you end using your ApgCon-instance, this must be
+ * called or else the connection to APG is leaked
+ *
+ */
+ public void disconnect() {
+ if( LOCAL_LOGV ) Log.v(TAG, "disconnecting apgService");
+ if (mApgService != null) {
+ mContext.unbindService(mApgConnection);
+ mApgService = null;
+ }
+ }
+
+ private boolean initialize() {
+ if (mApgService == null) {
+ if (!connect()) {
+ if( LOCAL_LOGV ) Log.v(TAG, "connection to apg service failed");
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Calls a function from APG's AIDL-interface
+ *
+ *
+ * After you have set up everything with {@link #setArg(String, String)}
+ * (and variants), you can call a function of the AIDL-interface. This
+ * will:
+ *
+ *
start connection to the remote interface (if not already connected)
+ *
call the function passed with all parameters synchronously
+ *
set up everything to retrieve the result and/or warnings/errors
+ *
call the callback if provided
+ *
+ *
+ *
+ *
+ * Note your thread will be blocked during execution - if you want to call
+ * the function asynchronously, see {@link #callAsync(String)}.
+ *
+ *
+ * @param function
+ * a remote function to call
+ * @return true, if call successful (= no errors), else false
+ *
+ * @see #callAsync(String)
+ * @see #setArg(String, String)
+ * @see #setOnCallFinishListener(OnCallFinishListener)
+ */
+ public boolean call(String function) {
+ boolean success = this.call(function, mArgs, mResult);
+ if (mOnCallFinishListener != null) {
+ try {
+ if( LOCAL_LOGD ) Log.d(TAG, "About to execute callback");
+ mOnCallFinishListener.onCallFinish(mResult);
+ if( LOCAL_LOGD ) Log.d(TAG, "Callback executed");
+ } catch (Exception e) {
+ Log.w(TAG, "Exception on callback: (" + e.getClass() + ") " + e.getMessage(), e);
+ mWarningList.add("(LOCAL) Could not execute callback (" + e.getClass() + "): " + e.getMessage());
+ }
+ }
+ return success;
+ }
+
+ /**
+ * Calls a function of remote interface asynchronously
+ *
+ *
+ * This does exactly the same as {@link #call(String)}, but asynchronously.
+ * While connection to APG and work are done in background, your thread can
+ * go on executing.
+ *
+ *
+ *
+ * To see whether the task is finished, you have two possibilities:
+ *
+ *
In your thread, poll {@link #isRunning()}
+ *
Supply a callback with {@link #setOnCallFinishListener(OnCallFinishListener)}
+ *
+ *
+ *
+ * @param function
+ * a remote function to call
+ *
+ * @see #call(String)
+ * @see #isRunning()
+ * @see #setOnCallFinishListener(OnCallFinishListener)
+ */
+ public void callAsync(String function) {
+ mAsyncRunning = true;
+ new CallAsync().execute(function);
+ }
+
+ private boolean call(String function, Bundle pArgs, Bundle pReturn) {
+
+ if (!initialize()) {
+ mErrorList.add("(LOCAL) Cannot bind to ApgService");
+ mResult.putInt(ret.ERROR.name(), error.CANNOT_BIND_TO_APG.ordinal());
+ return false;
+ }
+
+ if (function == null || function.length() == 0) {
+ mErrorList.add("(LOCAL) Function to call missing");
+ mResult.putInt(ret.ERROR.name(), error.CALL_MISSING.ordinal());
+ return false;
+ }
+
+ try {
+ Boolean success = (Boolean) IApgService2.class.getMethod(function, Bundle.class, Bundle.class).invoke(mApgService, pArgs, pReturn);
+ mErrorList.addAll(pReturn.getStringArrayList(ret.ERRORS.name()));
+ mWarningList.addAll(pReturn.getStringArrayList(ret.WARNINGS.name()));
+ return success;
+ } catch (NoSuchMethodException e) {
+ Log.e(TAG, "Remote call not known (" + function + "): " + e.getMessage(), e);
+ mErrorList.add("(LOCAL) Remote call not known (" + function + "): " + e.getMessage());
+ mResult.putInt(ret.ERROR.name(), error.CALL_NOT_KNOWN.ordinal());
+ return false;
+ } catch (InvocationTargetException e) {
+ Throwable orig = e.getTargetException();
+ Log.w(TAG, "Exception of type '" + orig.getClass() + "' on AIDL call '" + function + "': " + orig.getMessage(), orig);
+ mErrorList.add("(LOCAL) Exception of type '" + orig.getClass() + "' on AIDL call '" + function + "': " + orig.getMessage());
+ return false;
+ } catch (Exception e) {
+ Log.e(TAG, "Generic error (" + e.getClass() + "): " + e.getMessage(), e);
+ mErrorList.add("(LOCAL) Generic error (" + e.getClass() + "): " + e.getMessage());
+ mResult.putInt(ret.ERROR.name(), error.GENERIC.ordinal());
+ return false;
+ }
+
+ }
+
+ /**
+ * Set a string argument for APG
+ *
+ *
+ * This defines a string argument for APG's AIDL-interface.
+ *
+ *
+ *
+ * To know what key-value-pairs are possible (or required), take a look into
+ * the IApgService.aidl
+ *
+ *
+ *
+ * Note that parameters are not reseted after a call, so you have to
+ * reset ({@link #clearArgs()}) them manually if you want to.
+ *
+ *
+ *
+ * @param key
+ * the key
+ * @param val
+ * the value
+ *
+ * @see #clearArgs()
+ */
+ public void setArg(String key, String val) {
+ mArgs.putString(key, val);
+ }
+
+ /**
+ * Set a string-array argument for APG
+ *
+ *
+ * If the AIDL-parameter is an {@literal ArrayList}, you have to use
+ * this function.
+ *
+ *
+ *
+ * @param key
+ * the key
+ * @param vals
+ * the value
+ *
+ * @see #setArg(String, String)
+ */
+ public void setArg(String key, String vals[]) {
+ ArrayList list = new ArrayList();
+ for (String val : vals) {
+ list.add(val);
+ }
+ mArgs.putStringArrayList(key, list);
+ }
+
+ /**
+ * Set up a boolean argument for APG
+ *
+ * @param key
+ * the key
+ * @param vals
+ * the value
+ *
+ * @see #setArg(String, String)
+ */
+ public void setArg(String key, boolean val) {
+ mArgs.putBoolean(key, val);
+ }
+
+ /**
+ * Set up a int argument for APG
+ *
+ * @param key
+ * the key
+ * @param vals
+ * the value
+ *
+ * @see #setArg(String, String)
+ */
+ public void setArg(String key, int val) {
+ mArgs.putInt(key, val);
+ }
+
+ /**
+ * Set up a int-array argument for APG
+ *
+ * If the AIDL-parameter is an {@literal ArrayList}, you have to
+ * use this function.
+ *
+ *
+ * @param key
+ * the key
+ * @param vals
+ * the value
+ *
+ * @see #setArg(String, String)
+ */
+ public void setArg(String key, int vals[]) {
+ ArrayList list = new ArrayList();
+ for (int val : vals) {
+ list.add(val);
+ }
+ mArgs.putIntegerArrayList(key, list);
+ }
+
+ /**
+ * Set up binary data to en/decrypt
+ *
+ * @param is
+ * InputStream to get the data from
+ */
+ public void setBlob(InputStream is) {
+ if( LOCAL_LOGD ) Log.d(TAG, "setBlob() called");
+ // 1. get the new contentUri
+ ContentResolver cr = mContext.getContentResolver();
+ Uri contentUri = cr.insert(Uri.parse(BLOB_URI), new ContentValues());
+
+ // 2. insert binary data
+ OutputStream os = null;
+ try {
+ os = cr.openOutputStream(contentUri, "w");
+ } catch( Exception e ) {
+ Log.e(TAG, "... exception on setBlob", e);
+ }
+
+ byte[] buffer = new byte[8];
+ int len = 0;
+ try {
+ while( (len = is.read(buffer)) != -1) {
+ os.write(buffer, 0, len);
+ }
+ if(LOCAL_LOGD) Log.d(TAG, "... write finished, now closing");
+ os.close();
+ } catch (Exception e) {
+ Log.e(TAG, "... error on writing buffer", e);
+ }
+
+ mArgs.putString("BLOB", contentUri.toString() );
+ }
+
+ /**
+ * Clears all arguments
+ *
+ *
+ * Anything the has been set up with the various
+ * {@link #setArg(String, String)} functions is cleared.
+ *
+ *
+ *
+ * Note that any warning, error, callback, result, etc. is NOT cleared with
+ * this.
+ *
+ *
+ * @see #reset()
+ */
+ public void clearArgs() {
+ mArgs.clear();
+ }
+
+ /**
+ * Return the object associated with the key
+ *
+ * @param key
+ * the object's key you want to return
+ * @return an object at position key, or null if not set
+ */
+ public Object getArg(String key) {
+ return mArgs.get(key);
+ }
+
+ /**
+ * Iterates through the errors
+ *
+ *
+ * With this method you can iterate through all errors. The errors are only
+ * returned once and deleted immediately afterwards, so you can only return
+ * each error once.
+ *
+ *
+ * @return a human readable description of a error that happened, or null if
+ * no more errors
+ *
+ * @see #hasNextError()
+ * @see #clearErrors()
+ */
+ public String getNextError() {
+ if (mErrorList.size() != 0)
+ return mErrorList.remove(0);
+ else
+ return null;
+ }
+
+ /**
+ * Check if there are any new errors
+ *
+ * @return true, if there are unreturned errors, false otherwise
+ *
+ * @see #getNextError()
+ */
+ public boolean hasNextError() {
+ return mErrorList.size() != 0;
+ }
+
+ /**
+ * Get the numeric representation of the last error
+ *
+ *
+ * Values <100 mean the error happened locally, values >=100 mean the error
+ * happened at the remote side (APG). See the IApgService.aidl (or get the
+ * human readable description with {@link #getNextError()}) for what
+ * errors >=100 mean.
+ *
+ *
+ * @return the id of the error that happened
+ */
+ public int getError() {
+ if (mResult.containsKey(ret.ERROR.name()))
+ return mResult.getInt(ret.ERROR.name());
+ else
+ return -1;
+ }
+
+ /**
+ * Iterates through the warnings
+ *
+ *
+ * With this method you can iterate through all warnings. Warnings are
+ * only returned once and deleted immediately afterwards, so you can only
+ * return each warning once.
+ *
+ *
+ * @return a human readable description of a warning that happened, or null
+ * if no more warnings
+ *
+ * @see #hasNextWarning()
+ * @see #clearWarnings()
+ */
+ public String getNextWarning() {
+ if (mWarningList.size() != 0)
+ return mWarningList.remove(0);
+ else
+ return null;
+ }
+
+ /**
+ * Check if there are any new warnings
+ *
+ * @return true, if there are unreturned warnings, false otherwise
+ *
+ * @see #getNextWarning()
+ */
+ public boolean hasNextWarning() {
+ return mWarningList.size() != 0;
+ }
+
+ /**
+ * Get the result
+ *
+ *
+ * This gets your result. After doing an encryption or decryption with APG,
+ * you get the output with this function.
+ *
+ *
+ *
+ * Note when your last remote call is unsuccessful, the result will
+ * still have the same value like the last successful call (or null, if no
+ * call was successful). To ensure you do not work with old call's results,
+ * either be sure to {@link #reset()} (or at least {@link #clearResult()})
+ * your instance before each new call or always check that
+ * {@link #hasNextError()} is false.
+ *
+ *
+ *
+ * Note: When handling binary data with {@link #setBlob(InputStream)}, you
+ * get your result with {@link #getBlobResult()}.
+ *
+ *
+ * @return the mResult of the last {@link #call(String)} or
+ * {@link #callAsync(String)}.
+ *
+ * @see #reset()
+ * @see #clearResult()
+ * @see #getResultBundle()
+ * @see #getBlobResult()
+ */
+ public String getResult() {
+ return mResult.getString(ret.RESULT.name());
+ }
+
+ /**
+ * Get the binary result
+ *
+ *
+ * This gets your binary result. It only works if you called {@link #setBlob(InputStream)} before.
+ *
+ * If you did not call encrypt nor decrypt, this will be the same data as you inputed.
+ *
+ *
+ * @return InputStream of the binary data which was en/decrypted
+ *
+ * @see #setBlob(InputStream)
+ * @see #getResult()
+ */
+ public InputStream getBlobResult() {
+ if(mArgs.containsKey("BLOB")) {
+ ContentResolver cr = mContext.getContentResolver();
+ InputStream in = null;
+ try {
+ in = cr.openInputStream(Uri.parse(mArgs.getString("BLOB")));
+ } catch( Exception e ) {
+ Log.e(TAG, "Could not return blob in result", e);
+ }
+ return in;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Get the result bundle
+ *
+ *
+ * Unlike {@link #getResult()}, which only returns any en-/decrypted
+ * message, this function returns the complete information that was returned
+ * by Apg. This also includes the "RESULT", but additionally the warnings,
+ * errors and any other information.
+ *
+ *
+ * For warnings and errors it is suggested to use the functions that are
+ * provided here, namely {@link #getError()}, {@link #getNextError()},
+ * {@link #get_next_Warning()} etc.), but if any call returns something non
+ * standard, you have access to the complete result bundle to extract the
+ * information.
+ *
+ *
+ * @return the complete result bundle of the last call to apg
+ */
+ public Bundle getResultBundle() {
+ return mResult;
+ }
+
+ public error getConnectionStatus() {
+ return mConnectionStatus;
+ }
+
+ /**
+ * Clears all unfetched errors
+ *
+ * @see #getNextError()
+ * @see #hasNextError()
+ */
+ public void clearErrors() {
+ mErrorList.clear();
+ mResult.remove(ret.ERROR.name());
+ }
+
+ /**
+ * Clears all unfetched warnings
+ *
+ * @see #getNextWarning()
+ * @see #hasNextWarning()
+ */
+ public void clearWarnings() {
+ mWarningList.clear();
+ }
+
+ /**
+ * Clears the last mResult
+ *
+ * @see #getResult()
+ */
+ public void clearResult() {
+ mResult.remove(ret.RESULT.name());
+ }
+
+ /**
+ * Set a callback listener when call to AIDL finishes
+ *
+ * @param obj
+ * a object to call back after async execution
+ * @see ApgConInterface
+ */
+ public void setOnCallFinishListener(OnCallFinishListener lis) {
+ mOnCallFinishListener = lis;
+ }
+
+ /**
+ * Clears any callback object
+ *
+ * @see #setOnCallFinishListener(OnCallFinishListener)
+ */
+ public void clearOnCallFinishListener() {
+ mOnCallFinishListener = null;
+ }
+
+ /**
+ * Checks if an async execution is running
+ *
+ *
+ * If you started something with {@link #callAsync(String)}, this will
+ * return true if the task is still running
+ *
+ *
+ * @return true, if an async task is still running, false otherwise
+ *
+ * @see #callAsync(String)
+ *
+ */
+ public boolean isRunning() {
+ return mAsyncRunning;
+ }
+
+ /**
+ * Completely resets your instance
+ *
+ *
+ * This currently resets everything in this instance. Errors, warnings,
+ * results, callbacks, ... are removed. Any connection to the remote
+ * interface is upheld, though.
+ *
+ *
+ *
+ * Note when an async execution ({@link #callAsync(String)}) is
+ * running, it's result, warnings etc. will still be evaluated (which might
+ * be not what you want). Also mind that any callback you set is also
+ * reseted, so when finishing the execution any before defined callback will
+ * NOT BE TRIGGERED.
+ *
+ */
+ public void reset() {
+ clearErrors();
+ clearWarnings();
+ clearArgs();
+ clearOnCallFinishListener();
+ mResult.clear();
+ }
+
+}
diff --git a/org_apg/src/org/thialfihar/android/apg/deprecated/ApgConInterface.java b/org_apg/src/org/thialfihar/android/apg/deprecated/ApgConInterface.java
new file mode 100644
index 000000000..45eb3c5ef
--- /dev/null
+++ b/org_apg/src/org/thialfihar/android/apg/deprecated/ApgConInterface.java
@@ -0,0 +1,21 @@
+/*
+ * 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.thialfihar.android.apg.deprecated;
+
+public interface ApgConInterface {
+ public static interface OnCallFinishListener {
+ public abstract void onCallFinish(android.os.Bundle result);
+ }
+}
diff --git a/org_apg/src/org/thialfihar/android/apg/deprecated/ApgService2.java b/org_apg/src/org/thialfihar/android/apg/deprecated/ApgService2.java
new file mode 100644
index 000000000..e424c200c
--- /dev/null
+++ b/org_apg/src/org/thialfihar/android/apg/deprecated/ApgService2.java
@@ -0,0 +1,672 @@
+/*
+ * 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.thialfihar.android.apg.deprecated;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+
+import org.thialfihar.android.apg.deprecated.IApgService2;
+import org.thialfihar.android.apg.Id;
+import org.thialfihar.android.apg.Preferences;
+import org.thialfihar.android.apg.R;
+import org.thialfihar.android.apg.deprecated.IApgService2.Stub;
+import org.thialfihar.android.apg.Id.database;
+import org.thialfihar.android.apg.R.string;
+import org.thialfihar.android.apg.helper.PGPHelper;
+import org.thialfihar.android.apg.passphrase.PassphraseCacheService;
+import org.thialfihar.android.apg.provider.KeyRings;
+import org.thialfihar.android.apg.provider.Keys;
+import org.thialfihar.android.apg.provider.UserIds;
+import org.thialfihar.android.apg.util.InputData;
+
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteQueryBuilder;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.util.Log;
+
+/**
+ * ATTENTION:
+ *
+ * This is the old ApgService used as remote service over aidl interface. It will be reworked!
+ *
+ */
+public class ApgService2 extends PassphraseCacheService {
+ private final static String TAG = "ApgService";
+ public static final boolean LOCAL_LOGV = true;
+ public static final boolean LOCAL_LOGD = true;
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ if (LOCAL_LOGD)
+ Log.d(TAG, "bound");
+ return mBinder;
+ }
+
+ /** error status */
+ private static enum error {
+ ARGUMENTS_MISSING, APG_FAILURE, NO_MATCHING_SECRET_KEY, PRIVATE_KEY_PASSPHRASE_WRONG, PRIVATE_KEY_PASSPHRASE_MISSING;
+
+ public int shiftedOrdinal() {
+ return ordinal() + 100;
+ }
+ }
+
+ private static enum call {
+ encrypt_with_passphrase, encrypt_with_public_key, decrypt, get_keys
+ }
+
+ /** all arguments that can be passed by calling application */
+ public static enum arg {
+ MESSAGE, // message to encrypt or to decrypt
+ SYMMETRIC_PASSPHRASE, // key for symmetric en/decryption
+ PUBLIC_KEYS, // public keys for encryption
+ ENCRYPTION_ALGORYTHM, // encryption algorithm
+ HASH_ALGORYTHM, // hash algorithm
+ ARMORED_OUTPUT, // whether to armor output
+ FORCE_V3_SIGNATURE, // whether to force v3 signature
+ COMPRESSION, // what compression to use for encrypted output
+ SIGNATURE_KEY, // key for signing
+ PRIVATE_KEY_PASSPHRASE, // passphrase for encrypted private key
+ KEY_TYPE, // type of key (private or public)
+ BLOB, // blob passed
+ }
+
+ /** all things that might be returned */
+ private static enum ret {
+ ERRORS, // string array list with errors
+ WARNINGS, // string array list with warnings
+ ERROR, // numeric error
+ RESULT, // en-/decrypted
+ FINGERPRINTS, // fingerprints of keys
+ USER_IDS, // user ids
+ }
+
+ /** required arguments for each AIDL function */
+ private static final HashMap> FUNCTIONS_REQUIRED_ARGS = new HashMap>();
+ static {
+ HashSet args = new HashSet();
+ args.add(arg.SYMMETRIC_PASSPHRASE);
+ FUNCTIONS_REQUIRED_ARGS.put(call.encrypt_with_passphrase.name(), args);
+
+ args = new HashSet();
+ args.add(arg.PUBLIC_KEYS);
+ FUNCTIONS_REQUIRED_ARGS.put(call.encrypt_with_public_key.name(), args);
+
+ args = new HashSet();
+ FUNCTIONS_REQUIRED_ARGS.put(call.decrypt.name(), args);
+
+ args = new HashSet();
+ args.add(arg.KEY_TYPE);
+ FUNCTIONS_REQUIRED_ARGS.put(call.get_keys.name(), args);
+ }
+
+ /** optional arguments for each AIDL function */
+ private static final HashMap> FUNCTIONS_OPTIONAL_ARGS = new HashMap>();
+ static {
+ HashSet args = new HashSet();
+ args.add(arg.ENCRYPTION_ALGORYTHM);
+ args.add(arg.HASH_ALGORYTHM);
+ args.add(arg.ARMORED_OUTPUT);
+ args.add(arg.FORCE_V3_SIGNATURE);
+ args.add(arg.COMPRESSION);
+ args.add(arg.PRIVATE_KEY_PASSPHRASE);
+ args.add(arg.SIGNATURE_KEY);
+ args.add(arg.BLOB);
+ args.add(arg.MESSAGE);
+ FUNCTIONS_OPTIONAL_ARGS.put(call.encrypt_with_passphrase.name(), args);
+ FUNCTIONS_OPTIONAL_ARGS.put(call.encrypt_with_public_key.name(), args);
+
+ args = new HashSet();
+ args.add(arg.SYMMETRIC_PASSPHRASE);
+ args.add(arg.PUBLIC_KEYS);
+ args.add(arg.PRIVATE_KEY_PASSPHRASE);
+ args.add(arg.MESSAGE);
+ args.add(arg.BLOB);
+ FUNCTIONS_OPTIONAL_ARGS.put(call.decrypt.name(), args);
+ }
+
+ /** a map from ApgService parameters to function calls to get the default */
+ private static final HashMap FUNCTIONS_DEFAULTS = new HashMap();
+ static {
+ FUNCTIONS_DEFAULTS.put(arg.ENCRYPTION_ALGORYTHM, "getDefaultEncryptionAlgorithm");
+ FUNCTIONS_DEFAULTS.put(arg.HASH_ALGORYTHM, "getDefaultHashAlgorithm");
+ FUNCTIONS_DEFAULTS.put(arg.ARMORED_OUTPUT, "getDefaultAsciiArmour");
+ FUNCTIONS_DEFAULTS.put(arg.FORCE_V3_SIGNATURE, "getForceV3Signatures");
+ FUNCTIONS_DEFAULTS.put(arg.COMPRESSION, "getDefaultMessageCompression");
+ }
+
+ /** a map of the default function names to their method */
+ private static final HashMap FUNCTIONS_DEFAULTS_METHODS = new HashMap();
+ static {
+ try {
+ FUNCTIONS_DEFAULTS_METHODS.put("getDefaultEncryptionAlgorithm",
+ Preferences.class.getMethod("getDefaultEncryptionAlgorithm"));
+ FUNCTIONS_DEFAULTS_METHODS.put("getDefaultHashAlgorithm",
+ Preferences.class.getMethod("getDefaultHashAlgorithm"));
+ FUNCTIONS_DEFAULTS_METHODS.put("getDefaultAsciiArmour",
+ Preferences.class.getMethod("getDefaultAsciiArmour"));
+ FUNCTIONS_DEFAULTS_METHODS.put("getForceV3Signatures",
+ Preferences.class.getMethod("getForceV3Signatures"));
+ FUNCTIONS_DEFAULTS_METHODS.put("getDefaultMessageCompression",
+ Preferences.class.getMethod("getDefaultMessageCompression"));
+ } catch (Exception e) {
+ Log.e(TAG, "Function method exception: " + e.getMessage());
+ }
+ }
+
+ private static void writeToOutputStream(InputStream is, OutputStream os) throws IOException {
+ byte[] buffer = new byte[8];
+ int len = 0;
+ while ((len = is.read(buffer)) != -1) {
+ os.write(buffer, 0, len);
+ }
+ }
+
+ private static Cursor getKeyEntries(HashMap pParams) {
+ SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
+ qb.setTables(KeyRings.TABLE_NAME + " INNER JOIN " + Keys.TABLE_NAME + " ON " + "("
+ + KeyRings.TABLE_NAME + "." + KeyRings._ID + " = " + Keys.TABLE_NAME + "."
+ + Keys.KEY_RING_ID + " AND " + Keys.TABLE_NAME + "." + Keys.IS_MASTER_KEY
+ + " = '1'" + ") " + " INNER JOIN " + UserIds.TABLE_NAME + " ON " + "("
+ + Keys.TABLE_NAME + "." + Keys._ID + " = " + UserIds.TABLE_NAME + "."
+ + UserIds.KEY_ID + " AND " + UserIds.TABLE_NAME + "." + UserIds.RANK + " = '0') ");
+
+ String orderBy = pParams.containsKey("order_by") ? (String) pParams.get("order_by")
+ : UserIds.TABLE_NAME + "." + UserIds.USER_ID + " ASC";
+
+ String typeVal[] = null;
+ String typeWhere = null;
+ if (pParams.containsKey("key_type")) {
+ typeWhere = KeyRings.TABLE_NAME + "." + KeyRings.TYPE + " = ?";
+ typeVal = new String[] { "" + pParams.get("key_type") };
+ }
+ return qb.query(PGPHelper.getDatabase().db(), (String[]) pParams.get("columns"), typeWhere,
+ typeVal, null, null, orderBy);
+ }
+
+ /**
+ * maps a fingerprint or user id of a key to a master key in database
+ *
+ * @param search_key
+ * fingerprint or user id to search for
+ * @return master key if found, or 0
+ */
+ private static long getMasterKey(String pSearchKey, Bundle pReturn) {
+ if (pSearchKey == null || pSearchKey.length() != 8) {
+ return 0;
+ }
+ ArrayList keyList = new ArrayList();
+ keyList.add(pSearchKey);
+ long[] keys = getMasterKey(keyList, pReturn);
+ if (keys.length > 0) {
+ return keys[0];
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * maps fingerprints or user ids of keys to master keys in database
+ *
+ * @param search_keys
+ * a list of keys (fingerprints or user ids) to look for in database
+ * @return an array of master keys
+ */
+ private static long[] getMasterKey(ArrayList pSearchKeys, Bundle pReturn) {
+
+ HashMap qParams = new HashMap();
+ qParams.put("columns", new String[] { KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID, // 0
+ UserIds.TABLE_NAME + "." + UserIds.USER_ID, // 1
+ });
+ qParams.put("key_type", Id.database.type_public);
+
+ Cursor mCursor = getKeyEntries(qParams);
+
+ if (LOCAL_LOGV)
+ Log.v(TAG, "going through installed user keys");
+ ArrayList masterKeys = new ArrayList();
+ while (mCursor.moveToNext()) {
+ long curMkey = mCursor.getLong(0);
+ String curUser = mCursor.getString(1);
+
+ String curFprint = PGPHelper.getSmallFingerPrint(curMkey);
+ if (LOCAL_LOGV)
+ Log.v(TAG, "current user: " + curUser + " (" + curFprint + ")");
+ if (pSearchKeys.contains(curFprint) || pSearchKeys.contains(curUser)) {
+ if (LOCAL_LOGV)
+ Log.v(TAG, "master key found for: " + curFprint);
+ masterKeys.add(curMkey);
+ pSearchKeys.remove(curFprint);
+ } else {
+ if (LOCAL_LOGV)
+ Log.v(TAG, "Installed key " + curFprint
+ + " is not in the list of public keys to encrypt with");
+ }
+ }
+ mCursor.close();
+
+ long[] masterKeyLongs = new long[masterKeys.size()];
+ int i = 0;
+ for (Long key : masterKeys) {
+ masterKeyLongs[i++] = key;
+ }
+
+ if (i == 0) {
+ Log.w(TAG, "Found not one public key");
+ pReturn.getStringArrayList(ret.WARNINGS.name()).add(
+ "Searched for public key(s) but found not one");
+ }
+
+ for (String key : pSearchKeys) {
+ Log.w(TAG, "Searched for key " + key + " but cannot find it in APG");
+ pReturn.getStringArrayList(ret.WARNINGS.name()).add(
+ "Searched for key " + key + " but cannot find it in APG");
+ }
+
+ return masterKeyLongs;
+ }
+
+ /**
+ * Add default arguments if missing
+ *
+ * @param args
+ * the bundle to add default parameters to if missing
+ */
+ private void addDefaultArguments(String pCall, Bundle pArgs) {
+ // check whether there are optional elements defined for that call
+ if (FUNCTIONS_OPTIONAL_ARGS.containsKey(pCall)) {
+ Preferences preferences = Preferences.getPreferences(getBaseContext(), true);
+
+ Iterator iter = FUNCTIONS_DEFAULTS.keySet().iterator();
+ while (iter.hasNext()) {
+ arg currentArg = iter.next();
+ String currentKey = currentArg.name();
+ if (!pArgs.containsKey(currentKey)
+ && FUNCTIONS_OPTIONAL_ARGS.get(pCall).contains(currentArg)) {
+ String currentFunctionName = FUNCTIONS_DEFAULTS.get(currentArg);
+ try {
+ Class> returnType = FUNCTIONS_DEFAULTS_METHODS.get(currentFunctionName)
+ .getReturnType();
+ if (returnType == String.class) {
+ pArgs.putString(currentKey,
+ (String) FUNCTIONS_DEFAULTS_METHODS.get(currentFunctionName)
+ .invoke(preferences));
+ } else if (returnType == boolean.class) {
+ pArgs.putBoolean(currentKey,
+ (Boolean) FUNCTIONS_DEFAULTS_METHODS.get(currentFunctionName)
+ .invoke(preferences));
+ } else if (returnType == int.class) {
+ pArgs.putInt(currentKey,
+ (Integer) FUNCTIONS_DEFAULTS_METHODS.get(currentFunctionName)
+ .invoke(preferences));
+ } else {
+ Log.e(TAG, "Unknown return type " + returnType.toString()
+ + " for default option");
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Exception in add_default_arguments " + e.getMessage());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * updates a Bundle with default return values
+ *
+ * @param pReturn
+ * the Bundle to update
+ */
+ private void addDefaultReturns(Bundle pReturn) {
+ ArrayList errors = new ArrayList();
+ ArrayList warnings = new ArrayList();
+
+ pReturn.putStringArrayList(ret.ERRORS.name(), errors);
+ pReturn.putStringArrayList(ret.WARNINGS.name(), warnings);
+ }
+
+ /**
+ * checks for required arguments and adds them to the error if missing
+ *
+ * @param function
+ * the functions required arguments to check for
+ * @param pArgs
+ * the Bundle of arguments to check
+ * @param pReturn
+ * the bundle to write errors to
+ */
+ private void checkForRequiredArgs(String pFunction, Bundle pArgs, Bundle pReturn) {
+ if (FUNCTIONS_REQUIRED_ARGS.containsKey(pFunction)) {
+ Iterator iter = FUNCTIONS_REQUIRED_ARGS.get(pFunction).iterator();
+ while (iter.hasNext()) {
+ String curArg = iter.next().name();
+ if (!pArgs.containsKey(curArg)) {
+ pReturn.getStringArrayList(ret.ERRORS.name())
+ .add("Argument missing: " + curArg);
+ }
+ }
+ }
+
+ if (pFunction.equals(call.encrypt_with_passphrase.name())
+ || pFunction.equals(call.encrypt_with_public_key.name())
+ || pFunction.equals(call.decrypt.name())) {
+ // check that either MESSAGE or BLOB are there
+ if (!pArgs.containsKey(arg.MESSAGE.name()) && !pArgs.containsKey(arg.BLOB.name())) {
+ pReturn.getStringArrayList(ret.ERRORS.name()).add(
+ "Arguments missing: Neither MESSAGE nor BLOG found");
+ }
+
+ }
+ }
+
+ /**
+ * checks for unknown arguments and add them to warning if found
+ *
+ * @param function
+ * the functions name to check against
+ * @param pArgs
+ * the Bundle of arguments to check
+ * @param pReturn
+ * the bundle to write warnings to
+ */
+ private void checkForUnknownArgs(String pFunction, Bundle pArgs, Bundle pReturn) {
+
+ HashSet allArgs = new HashSet();
+ if (FUNCTIONS_REQUIRED_ARGS.containsKey(pFunction)) {
+ allArgs.addAll(FUNCTIONS_REQUIRED_ARGS.get(pFunction));
+ }
+ if (FUNCTIONS_OPTIONAL_ARGS.containsKey(pFunction)) {
+ allArgs.addAll(FUNCTIONS_OPTIONAL_ARGS.get(pFunction));
+ }
+
+ ArrayList unknownArgs = new ArrayList();
+ Iterator iter = pArgs.keySet().iterator();
+ while (iter.hasNext()) {
+ String curKey = iter.next();
+ try {
+ arg curArg = arg.valueOf(curKey);
+ if (!allArgs.contains(curArg)) {
+ pReturn.getStringArrayList(ret.WARNINGS.name()).add(
+ "Unknown argument: " + curKey);
+ unknownArgs.add(curKey);
+ }
+ } catch (Exception e) {
+ pReturn.getStringArrayList(ret.WARNINGS.name()).add("Unknown argument: " + curKey);
+ unknownArgs.add(curKey);
+ }
+ }
+
+ // remove unknown arguments so our bundle has just what we need
+ for (String arg : unknownArgs) {
+ pArgs.remove(arg);
+ }
+ }
+
+ private boolean prepareArgs(String pCall, Bundle pArgs, Bundle pReturn) {
+ PGPHelper.initialize(getBaseContext());
+
+ /* add default return values for all functions */
+ addDefaultReturns(pReturn);
+
+ /* add default arguments if missing */
+ addDefaultArguments(pCall, pArgs);
+ if (LOCAL_LOGV)
+ Log.v(TAG, "add_default_arguments");
+
+ /* check for required arguments */
+ checkForRequiredArgs(pCall, pArgs, pReturn);
+ if (LOCAL_LOGV)
+ Log.v(TAG, "check_required_args");
+
+ /* check for unknown arguments and add to warning if found */
+ checkForUnknownArgs(pCall, pArgs, pReturn);
+ if (LOCAL_LOGV)
+ Log.v(TAG, "check_unknown_args");
+
+ /* return if errors happened */
+ if (pReturn.getStringArrayList(ret.ERRORS.name()).size() != 0) {
+ if (LOCAL_LOGV)
+ Log.v(TAG, "Errors after preparing, not executing " + pCall);
+ pReturn.putInt(ret.ERROR.name(), error.ARGUMENTS_MISSING.shiftedOrdinal());
+ return false;
+ }
+ if (LOCAL_LOGV)
+ Log.v(TAG, "error return");
+
+ return true;
+ }
+
+ private boolean encrypt(Bundle pArgs, Bundle pReturn) {
+ boolean isBlob = pArgs.containsKey(arg.BLOB.name());
+
+ long pubMasterKeys[] = {};
+ if (pArgs.containsKey(arg.PUBLIC_KEYS.name())) {
+ ArrayList list = pArgs.getStringArrayList(arg.PUBLIC_KEYS.name());
+ ArrayList pubKeys = new ArrayList();
+ if (LOCAL_LOGV)
+ Log.v(TAG, "Long size: " + list.size());
+ Iterator iter = list.iterator();
+ while (iter.hasNext()) {
+ pubKeys.add(iter.next());
+ }
+ pubMasterKeys = getMasterKey(pubKeys, pReturn);
+ }
+
+ InputStream inStream = null;
+ if (isBlob) {
+ ContentResolver cr = getContentResolver();
+ try {
+ inStream = cr.openInputStream(Uri.parse(pArgs.getString(arg.BLOB.name())));
+ } catch (Exception e) {
+ Log.e(TAG, "... exception on opening blob", e);
+ }
+ } else {
+ inStream = new ByteArrayInputStream(pArgs.getString(arg.MESSAGE.name()).getBytes());
+ }
+ InputData in = new InputData(inStream, 0); // XXX Size second param?
+
+ OutputStream out = new ByteArrayOutputStream();
+ if (LOCAL_LOGV)
+ Log.v(TAG, "About to encrypt");
+ try {
+ PGPHelper.encrypt(getBaseContext(), // context
+ in, // input stream
+ out, // output stream
+ pArgs.getBoolean(arg.ARMORED_OUTPUT.name()), // ARMORED_OUTPUT
+ pubMasterKeys, // encryption keys
+ getMasterKey(pArgs.getString(arg.SIGNATURE_KEY.name()), pReturn), // signature
+ // key
+ pArgs.getString(arg.PRIVATE_KEY_PASSPHRASE.name()), // signature passphrase
+ null, // progress
+ pArgs.getInt(arg.ENCRYPTION_ALGORYTHM.name()), // encryption
+ pArgs.getInt(arg.HASH_ALGORYTHM.name()), // hash
+ pArgs.getInt(arg.COMPRESSION.name()), // compression
+ pArgs.getBoolean(arg.FORCE_V3_SIGNATURE.name()), // mPreferences.getForceV3Signatures(),
+ pArgs.getString(arg.SYMMETRIC_PASSPHRASE.name()) // passPhrase
+ );
+ } catch (Exception e) {
+ Log.e(TAG, "Exception in encrypt");
+ String msg = e.getMessage();
+ if (msg.equals(getBaseContext().getString(R.string.error_noSignaturePassPhrase))) {
+ pReturn.getStringArrayList(ret.ERRORS.name()).add(
+ "Cannot encrypt (" + arg.PRIVATE_KEY_PASSPHRASE.name() + " missing): "
+ + msg);
+ pReturn.putInt(ret.ERROR.name(),
+ error.PRIVATE_KEY_PASSPHRASE_MISSING.shiftedOrdinal());
+ } else if (msg.equals(getBaseContext().getString(
+ R.string.error_couldNotExtractPrivateKey))) {
+ pReturn.getStringArrayList(ret.ERRORS.name()).add(
+ "Cannot encrypt (" + arg.PRIVATE_KEY_PASSPHRASE.name()
+ + " probably wrong): " + msg);
+ pReturn.putInt(ret.ERROR.name(),
+ error.PRIVATE_KEY_PASSPHRASE_WRONG.shiftedOrdinal());
+ } else {
+ pReturn.getStringArrayList(ret.ERRORS.name()).add(
+ "Internal failure (" + e.getClass() + ") in APG when encrypting: "
+ + e.getMessage());
+ pReturn.putInt(ret.ERROR.name(), error.APG_FAILURE.shiftedOrdinal());
+ }
+ return false;
+ }
+ if (LOCAL_LOGV)
+ Log.v(TAG, "Encrypted");
+ if (isBlob) {
+ ContentResolver cr = getContentResolver();
+ try {
+ OutputStream outStream = cr.openOutputStream(Uri.parse(pArgs.getString(arg.BLOB
+ .name())));
+ writeToOutputStream(new ByteArrayInputStream(out.toString().getBytes()), outStream);
+ outStream.close();
+ } catch (Exception e) {
+ Log.e(TAG, "... exception on writing blob", e);
+ }
+ } else {
+ pReturn.putString(ret.RESULT.name(), out.toString());
+ }
+ return true;
+ }
+
+ private final IApgService2.Stub mBinder = new IApgService2.Stub() {
+
+ public boolean getKeys(Bundle pArgs, Bundle pReturn) {
+
+ prepareArgs("get_keys", pArgs, pReturn);
+
+ HashMap qParams = new HashMap();
+ qParams.put("columns", new String[] {
+ KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID, // 0
+ UserIds.TABLE_NAME + "." + UserIds.USER_ID, // 1
+ });
+
+ qParams.put("key_type", pArgs.getInt(arg.KEY_TYPE.name()));
+
+ Cursor cursor = getKeyEntries(qParams);
+ ArrayList fPrints = new ArrayList();
+ ArrayList ids = new ArrayList();
+ while (cursor.moveToNext()) {
+ if (LOCAL_LOGV)
+ Log.v(TAG, "adding key " + PGPHelper.getSmallFingerPrint(cursor.getLong(0)));
+ fPrints.add(PGPHelper.getSmallFingerPrint(cursor.getLong(0)));
+ ids.add(cursor.getString(1));
+ }
+ cursor.close();
+
+ pReturn.putStringArrayList(ret.FINGERPRINTS.name(), fPrints);
+ pReturn.putStringArrayList(ret.USER_IDS.name(), ids);
+ return true;
+ }
+
+ public boolean encryptWithPublicKey(Bundle pArgs, Bundle pReturn) {
+ if (!prepareArgs("encrypt_with_public_key", pArgs, pReturn)) {
+ return false;
+ }
+
+ return encrypt(pArgs, pReturn);
+ }
+
+ public boolean encryptWithPassphrase(Bundle pArgs, Bundle pReturn) {
+ if (!prepareArgs("encrypt_with_passphrase", pArgs, pReturn)) {
+ return false;
+ }
+
+ return encrypt(pArgs, pReturn);
+
+ }
+
+ public boolean decrypt(Bundle pArgs, Bundle pReturn) {
+ if (!prepareArgs("decrypt", pArgs, pReturn)) {
+ return false;
+ }
+
+ boolean isBlob = pArgs.containsKey(arg.BLOB.name());
+
+ String passphrase = pArgs.getString(arg.SYMMETRIC_PASSPHRASE.name()) != null ? pArgs
+ .getString(arg.SYMMETRIC_PASSPHRASE.name()) : pArgs
+ .getString(arg.PRIVATE_KEY_PASSPHRASE.name());
+
+ InputStream inStream = null;
+ if (isBlob) {
+ ContentResolver cr = getContentResolver();
+ try {
+ inStream = cr.openInputStream(Uri.parse(pArgs.getString(arg.BLOB.name())));
+ } catch (Exception e) {
+ Log.e(TAG, "... exception on opening blob", e);
+ }
+ } else {
+ inStream = new ByteArrayInputStream(pArgs.getString(arg.MESSAGE.name()).getBytes());
+ }
+
+ InputData in = new InputData(inStream, 0); // XXX what size in second parameter?
+ OutputStream out = new ByteArrayOutputStream();
+ if (LOCAL_LOGV)
+ Log.v(TAG, "About to decrypt");
+ try {
+ PGPHelper.decrypt(getBaseContext(), in, out, passphrase, null, // progress
+ pArgs.getString(arg.SYMMETRIC_PASSPHRASE.name()) != null // symmetric
+ );
+ } catch (Exception e) {
+ Log.e(TAG, "Exception in decrypt");
+ String msg = e.getMessage();
+ if (msg.equals(getBaseContext().getString(R.string.error_noSecretKeyFound))) {
+ pReturn.getStringArrayList(ret.ERRORS.name()).add("Cannot decrypt: " + msg);
+ pReturn.putInt(ret.ERROR.name(), error.NO_MATCHING_SECRET_KEY.shiftedOrdinal());
+ } else if (msg.equals(getBaseContext().getString(R.string.error_wrongPassPhrase))) {
+ pReturn.getStringArrayList(ret.ERRORS.name()).add(
+ "Cannot decrypt (" + arg.PRIVATE_KEY_PASSPHRASE.name()
+ + " wrong/missing): " + msg);
+ pReturn.putInt(ret.ERROR.name(),
+ error.PRIVATE_KEY_PASSPHRASE_WRONG.shiftedOrdinal());
+ } else {
+ pReturn.getStringArrayList(ret.ERRORS.name()).add(
+ "Internal failure (" + e.getClass() + ") in APG when decrypting: "
+ + msg);
+ pReturn.putInt(ret.ERROR.name(), error.APG_FAILURE.shiftedOrdinal());
+ }
+ return false;
+ }
+ if (LOCAL_LOGV)
+ Log.v(TAG, "... decrypted");
+
+ if (isBlob) {
+ ContentResolver cr = getContentResolver();
+ try {
+ OutputStream outStream = cr.openOutputStream(Uri.parse(pArgs.getString(arg.BLOB
+ .name())));
+ writeToOutputStream(new ByteArrayInputStream(out.toString().getBytes()),
+ outStream);
+ outStream.close();
+ } catch (Exception e) {
+ Log.e(TAG, "... exception on writing blob", e);
+ }
+ } else {
+ pReturn.putString(ret.RESULT.name(), out.toString());
+ }
+ return true;
+ }
+
+ };
+}
diff --git a/org_apg/src/org/thialfihar/android/apg/deprecated/ApgServiceBlobDatabase.java b/org_apg/src/org/thialfihar/android/apg/deprecated/ApgServiceBlobDatabase.java
new file mode 100644
index 000000000..cb06ee9ae
--- /dev/null
+++ b/org_apg/src/org/thialfihar/android/apg/deprecated/ApgServiceBlobDatabase.java
@@ -0,0 +1,71 @@
+/*
+ * 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.thialfihar.android.apg.deprecated;
+
+
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.net.Uri;
+import android.util.Log;
+
+public class ApgServiceBlobDatabase extends SQLiteOpenHelper {
+
+ private static final String TAG = "ApgServiceBlobDatabase";
+
+ private static final int VERSION = 1;
+ private static final String NAME = "apg_service_blob_data";
+ private static final String TABLE = "data";
+
+ public ApgServiceBlobDatabase(Context context) {
+ super(context, NAME, null, VERSION);
+ if (ApgService2.LOCAL_LOGD)
+ Log.d(TAG, "constructor called");
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ if (ApgService2.LOCAL_LOGD)
+ Log.d(TAG, "onCreate() called");
+ db.execSQL("create table " + TABLE + " ( _id integer primary key autoincrement,"
+ + "key text not null)");
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ if (ApgService2.LOCAL_LOGD)
+ Log.d(TAG, "onUpgrade() called");
+ // no upgrade necessary yet
+ }
+
+ public Uri insert(ContentValues vals) {
+ if (ApgService2.LOCAL_LOGD)
+ Log.d(TAG, "insert() called");
+ SQLiteDatabase db = this.getWritableDatabase();
+ long newId = db.insert(TABLE, null, vals);
+ return ContentUris.withAppendedId(ApgServiceBlobProvider.CONTENT_URI, newId);
+ }
+
+ public Cursor query(String id, String key) {
+ if (ApgService2.LOCAL_LOGD)
+ Log.d(TAG, "query() called");
+ SQLiteDatabase db = this.getReadableDatabase();
+ return db.query(TABLE, new String[] { "_id" }, "_id = ? and key = ?", new String[] { id,
+ key }, null, null, null);
+ }
+}
diff --git a/org_apg/src/org/thialfihar/android/apg/deprecated/ApgServiceBlobProvider.java b/org_apg/src/org/thialfihar/android/apg/deprecated/ApgServiceBlobProvider.java
new file mode 100644
index 000000000..823aac989
--- /dev/null
+++ b/org_apg/src/org/thialfihar/android/apg/deprecated/ApgServiceBlobProvider.java
@@ -0,0 +1,151 @@
+/*
+ * 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.thialfihar.android.apg.deprecated;
+
+import org.thialfihar.android.apg.Constants;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.List;
+import java.util.UUID;
+
+public class ApgServiceBlobProvider extends ContentProvider {
+
+ private static final String TAG = "ApgServiceBlobProvider";
+
+ public static final Uri CONTENT_URI = Uri.parse("content://org.thialfihar.android.apg.provider.apgserviceblobprovider");
+
+ private static final String COLUMN_KEY = "key";
+
+ private static final String STORE_PATH = Constants.path.APP_DIR+"/ApgServiceBlobs";
+
+ private ApgServiceBlobDatabase mDb = null;
+
+ public ApgServiceBlobProvider() {
+ if(ApgService2.LOCAL_LOGD) Log.d(TAG, "Constructor called");
+ File dir = new File(STORE_PATH);
+ dir.mkdirs();
+ if(ApgService2.LOCAL_LOGD) Log.d(TAG, "Constructor finished");
+ }
+
+ @Override
+ public int delete(Uri arg0, String arg1, String[] arg2) {
+ if(ApgService2.LOCAL_LOGD) Log.d(TAG, "delete() called");
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public String getType(Uri arg0) {
+ if(ApgService2.LOCAL_LOGD) Log.d(TAG, "getType() called");
+ // not needed for now
+ return null;
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues ignored) {
+ if(ApgService2.LOCAL_LOGD) Log.d(TAG, "insert() called");
+ // ContentValues are actually ignored, because we want to store a blob with no more information
+ // but have to create an record with the password generated here first
+
+ ContentValues vals = new ContentValues();
+
+ // Insert a random key in the database. This has to provided by the caller when updating or
+ // getting the blob
+ String password = UUID.randomUUID().toString();
+ vals.put(COLUMN_KEY, password);
+
+ Uri insertedUri = mDb.insert(vals);
+ return Uri.withAppendedPath(insertedUri, password);
+ }
+
+ @Override
+ public boolean onCreate() {
+ if(ApgService2.LOCAL_LOGD) Log.d(TAG, "onCreate() called");
+ mDb = new ApgServiceBlobDatabase(getContext());
+ // TODO Auto-generated method stub
+ return true;
+ }
+
+ @Override
+ public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3, String arg4) {
+ if(ApgService2.LOCAL_LOGD) Log.d(TAG, "query() called");
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) {
+ if(ApgService2.LOCAL_LOGD) Log.d(TAG, "update() called");
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public ParcelFileDescriptor openFile(Uri uri, String mode) throws SecurityException, FileNotFoundException {
+ if(ApgService2.LOCAL_LOGD) Log.d(TAG, "openFile() called");
+ if(ApgService2.LOCAL_LOGD) Log.d(TAG, "... with uri: "+uri.toString());
+ if(ApgService2.LOCAL_LOGD) Log.d(TAG, "... with mode: "+mode);
+
+ List segments = uri.getPathSegments();
+ if(segments.size() < 2) {
+ throw new SecurityException("Password not found in URI");
+ }
+ String id = segments.get(0);
+ String key = segments.get(1);
+
+ if(ApgService2.LOCAL_LOGD) Log.d(TAG, "... got id: "+id);
+ if(ApgService2.LOCAL_LOGD) Log.d(TAG, "... and key: "+key);
+
+ // get the data
+ Cursor result = mDb.query(id, key);
+
+ if(result.getCount() == 0) {
+ // either the key is wrong or no id exists
+ throw new FileNotFoundException("No file found with that ID and/or password");
+ }
+
+ File targetFile = new File(STORE_PATH, id);
+ if(mode.equals("w")) {
+ if(ApgService2.LOCAL_LOGD) Log.d(TAG, "... will try to open file w");
+ if( !targetFile.exists() ) {
+ try {
+ targetFile.createNewFile();
+ } catch (IOException e) {
+ Log.e(TAG, "... got IEOException on creating new file", e);
+ throw new FileNotFoundException("Could not create file to write to");
+ }
+ }
+ return ParcelFileDescriptor.open(targetFile, ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE );
+ } else if(mode.equals("r")) {
+ if(ApgService2.LOCAL_LOGD) Log.d(TAG, "... will try to open file r");
+ if( !targetFile.exists() ) {
+ throw new FileNotFoundException("Error: Could not find the file requested");
+ }
+ return ParcelFileDescriptor.open(targetFile, ParcelFileDescriptor.MODE_READ_ONLY);
+ }
+
+ return null;
+ }
+
+}
diff --git a/org_apg/src/org/thialfihar/android/apg/deprecated/BlobContract.java b/org_apg/src/org/thialfihar/android/apg/deprecated/BlobContract.java
new file mode 100644
index 000000000..0d720dabb
--- /dev/null
+++ b/org_apg/src/org/thialfihar/android/apg/deprecated/BlobContract.java
@@ -0,0 +1,43 @@
+package org.thialfihar.android.apg.deprecated;
+//package org.thialfihar.android.apg.provider.blob;
+//
+//import android.net.Uri;
+//import android.provider.BaseColumns;
+//
+//public class BlobContract {
+//
+// interface BlobColumns {
+// String DATA = "data";
+// }
+//
+// public static final String CONTENT_AUTHORITY = "org.thialfihar.android.apg";
+//
+// private static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY);
+//
+// public static final String PATH_BLOB = "blob";
+//
+// public static class Blobs implements BlobColumns, BaseColumns {
+// public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon().appendPath(PATH_BLOB)
+// .build();
+//
+// /** Use if multiple items get returned */
+// public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.apg.blob";
+//
+// /** Use if a single item is returned */
+// public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.apg.blob";
+//
+// /** Default "ORDER BY" clause. */
+// public static final String DEFAULT_SORT = BaseColumns._ID + " ASC";
+//
+// public static Uri buildUri(String id) {
+// return CONTENT_URI.buildUpon().appendPath(id).build();
+// }
+//
+// public static String getId(Uri uri) {
+// return uri.getLastPathSegment();
+// }
+// }
+//
+// private BlobContract() {
+// }
+//}
diff --git a/org_apg/src/org/thialfihar/android/apg/deprecated/IApgService2.aidl b/org_apg/src/org/thialfihar/android/apg/deprecated/IApgService2.aidl
new file mode 100644
index 000000000..8b8a35bf3
--- /dev/null
+++ b/org_apg/src/org/thialfihar/android/apg/deprecated/IApgService2.aidl
@@ -0,0 +1,125 @@
+package org.thialfihar.android.apg.deprecated;
+
+interface IApgService2 {
+
+ /* All functions fill the returnVals Bundle with the following keys:
+ *
+ * ArrayList "WARNINGS" = Warnings, if any
+ * ArrayList "ERRORS" = Human readable error descriptions, if any
+ * int "ERROR" = Numeric representation of error, if any
+ * starting with 100:
+ * 100: Required argument missing
+ * 101: Generic failure of APG
+ * 102: No matching private key found
+ * 103: Private key's passphrase wrong
+ * 104: Private key's passphrase missing
+ */
+
+ /* ********************************************************
+ * Encryption
+ * ********************************************************/
+
+ /* All encryption function's arguments
+ *
+ * Bundle params' keys:
+ * (optional/required)
+ * TYPE "STRING KEY" = EXPLANATION / VALUES
+ *
+ * (required)
+ * String "MESSAGE" = Message to encrypt
+ * OR
+ * String "BLOB" = ContentUri to a file handle
+ * with binary data to encrypt
+ * (Attention: file will be overwritten
+ * with encrypted content!)
+ *
+ * (optional)
+ * int "ENCRYPTION_ALGORYTHM" = Encryption Algorithm
+ * 7: AES-128, 8: AES-192, 9: AES-256,
+ * 4: Blowfish, 10: Twofish, 3: CAST5,
+ * 6: DES, 2: Triple DES, 1: IDEA
+ * (optional)
+ * int "HASH_ALGORYTHM" = Hash Algorithm
+ * 1: MD5, 3: RIPEMD-160, 2: SHA-1,
+ * 11: SHA-224, 8: SHA-256, 9: SHA-384,
+ * 10: SHA-512
+ * (optional)
+ * Boolean "ARMORED_OUTPUT" = Armor output
+ *
+ * (optional)
+ * Boolean "FORCE_V3_SIGNATURE" = Force V3 Signatures
+ *
+ * (optional)
+ * int "COMPRESSION" = Compression to use
+ * 0x21070001: none, 1: Zip, 2: Zlib,
+ * 3: BZip2
+ * (optional)
+ * String "SIGNATURE_KEY" = Key to sign with
+ *
+ * (optional)
+ * String "PRIVATE_KEY_PASSPHRASE" = Passphrase for signing key
+ *
+ * Bundle returnVals (in addition to the ERRORS/WARNINGS above):
+ * If "MESSAGE" was set:
+ * String "RESULT" = Encrypted message
+ */
+
+ /* Additional argument for function below:
+ * (required)
+ * String "SYMMETRIC_PASSPHRASE" = Symmetric passphrase to use
+ */
+ boolean encryptWithPassphrase(in Bundle params, out Bundle returnVals);
+
+ /* Additional argument:
+ * (required)
+ * ArrayList "PUBLIC_KEYS" = Public keys (8char fingerprint "123ABC12" OR
+ * complete id "Alice Meyer ")
+ */
+ boolean encryptWithPublicKey(in Bundle params, out Bundle returnVals);
+
+ /* ********************************************************
+ * Decryption
+ * ********************************************************/
+
+ /* Bundle params:
+ * (required)
+ * String "MESSAGE" = Message to dencrypt
+ * OR
+ * String "BLOB" = ContentUri to a file handle
+ * with binary data to dencrypt
+ * (Attention: file will be overwritten
+ * with dencrypted content!)
+ *
+ * (optional)
+ * String "SYMMETRIC_PASSPHRASE" = Symmetric passphrase for decryption
+ *
+ * (optional)
+ * String "PRIVATE_KEY_PASSPHRASE" = Private keys's passphrase on asymmetric encryption
+ *
+ * Bundle return_vals:
+ * If "MESSAGE" was set:
+ * String "RESULT" = Decrypted message
+ */
+ boolean decrypt(in Bundle params, out Bundle returnVals);
+
+ /* ********************************************************
+ * Get key information
+ * ********************************************************/
+
+ /* Get info about all available keys
+ *
+ * Bundle params:
+ * (required)
+ * int "KEY_TYPE" = info about what type of keys to return
+ * 0: public keys
+ * 1: private keys
+ *
+ * Returns:
+ * StringArrayList "FINGERPRINTS" = Short fingerprints of keys
+ *
+ * StringArrayList "USER_IDS" = User ids of corresponding fingerprints
+ * (order is the same as in FINGERPRINTS)
+ */
+ boolean getKeys(in Bundle params, out Bundle returnVals);
+
+}
\ No newline at end of file
diff --git a/org_apg/src/org/thialfihar/android/apg/helper/FileHelper.java b/org_apg/src/org/thialfihar/android/apg/helper/FileHelper.java
new file mode 100644
index 000000000..9f8b3ca8c
--- /dev/null
+++ b/org_apg/src/org/thialfihar/android/apg/helper/FileHelper.java
@@ -0,0 +1,57 @@
+package org.thialfihar.android.apg.helper;
+
+import org.thialfihar.android.apg.R;
+
+import android.app.Activity;
+import android.content.ActivityNotFoundException;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Environment;
+import android.widget.Toast;
+
+public class FileHelper {
+
+ /**
+ * Checks if external storage is mounted if file is located on external storage
+ *
+ * @param file
+ * @return true if storage is mounted
+ */
+ public static boolean isStorageMounted(String file) {
+ if (file.startsWith(Environment.getExternalStorageDirectory().getAbsolutePath())) {
+ if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Opens the preferred installed file manager on Android and shows a toast if no manager is
+ * installed.
+ *
+ * @param activity
+ * @param filename
+ * default selected file, not supported by all file managers
+ * @param type
+ * can be text/plain for example
+ * @param requestCode
+ * requestCode used to identify the result coming back from file manager to
+ * onActivityResult() in your activity
+ */
+ public static void openFile(Activity activity, String filename, String type, int requestCode) {
+ Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+
+ intent.setData(Uri.parse("file://" + filename));
+ intent.setType(type);
+
+ try {
+ activity.startActivityForResult(intent, requestCode);
+ } catch (ActivityNotFoundException e) {
+ // No compatible file manager was found.
+ Toast.makeText(activity, R.string.noFilemanagerInstalled, Toast.LENGTH_SHORT).show();
+ }
+ }
+}
diff --git a/org_apg/src/org/thialfihar/android/apg/helper/OtherHelper.java b/org_apg/src/org/thialfihar/android/apg/helper/OtherHelper.java
new file mode 100644
index 000000000..6833e9060
--- /dev/null
+++ b/org_apg/src/org/thialfihar/android/apg/helper/OtherHelper.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2012 Dominik Schürmann
+ *
+ * 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.thialfihar.android.apg.helper;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import android.content.Context;
+
+public class OtherHelper {
+
+ /**
+ * Reads html files from /res/raw/example.html to output them as string. See
+ * http://www.monocube.com/2011/02/08/android-tutorial-html-file-in-webview/
+ *
+ * @param context
+ * current context
+ * @param resourceID
+ * of html file to read
+ * @return content of html file with formatting
+ */
+ public static String readContentFromResource(Context context, int resourceID) {
+ InputStream raw = context.getResources().openRawResource(resourceID);
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ int i;
+ try {
+ i = raw.read();
+ while (i != -1) {
+ stream.write(i);
+ i = raw.read();
+ }
+ raw.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return stream.toString();
+ }
+
+ /**
+ * Return the number if days between two dates
+ *
+ * @param first
+ * @param second
+ * @return number of days
+ */
+ public static long getNumDaysBetween(GregorianCalendar first, GregorianCalendar second) {
+ GregorianCalendar tmp = new GregorianCalendar();
+ tmp.setTime(first.getTime());
+ long numDays = (second.getTimeInMillis() - first.getTimeInMillis()) / 1000 / 86400;
+ tmp.add(Calendar.DAY_OF_MONTH, (int) numDays);
+ while (tmp.before(second)) {
+ tmp.add(Calendar.DAY_OF_MONTH, 1);
+ ++numDays;
+ }
+ return numDays;
+ }
+
+}
diff --git a/org_apg/src/org/thialfihar/android/apg/helper/PGPConversionHelper.java b/org_apg/src/org/thialfihar/android/apg/helper/PGPConversionHelper.java
new file mode 100644
index 000000000..a406bf6e8
--- /dev/null
+++ b/org_apg/src/org/thialfihar/android/apg/helper/PGPConversionHelper.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2012 Dominik Schürmann
+ *
+ * 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.thialfihar.android.apg.helper;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Vector;
+
+import org.spongycastle.openpgp.PGPObjectFactory;
+import org.spongycastle.openpgp.PGPSecretKey;
+import org.spongycastle.openpgp.PGPSecretKeyRing;
+import org.thialfihar.android.apg.Constants;
+
+import android.util.Log;
+
+public class PGPConversionHelper {
+ /**
+ * Converts Vector to a byte[] array to send it by intent to service
+ *
+ * @param keys
+ * @return
+ */
+ public static byte[] PGPSecretKeyListToBytes(Vector keys) {
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ for (PGPSecretKey key : keys) {
+ try {
+ key.encode(os);
+ } catch (IOException e) {
+ Log.e(Constants.TAG,
+ "Error while converting PGPSecretKey to byte[]: " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ byte[] keysBytes = os.toByteArray();
+
+ return keysBytes;
+ }
+
+ /**
+ * Convert from byte[] to ArrayList
+ *
+ * @param keysBytes
+ * @return
+ */
+ public static PGPSecretKeyRing BytesToPGPSecretKeyRing(byte[] keysBytes) {
+ PGPObjectFactory factory = new PGPObjectFactory(keysBytes);
+ PGPSecretKeyRing keyRing = null;
+ try {
+ if ((keyRing = (PGPSecretKeyRing) factory.nextObject()) == null) {
+ Log.e(Constants.TAG, "No keys given!");
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ return keyRing;
+ }
+
+ public static ArrayList BytesToPGPSecretKeyList(byte[] keysBytes) {
+ PGPSecretKeyRing keyRing = BytesToPGPSecretKeyRing(keysBytes);
+ ArrayList keys = new ArrayList();
+
+ Iterator itr = keyRing.getSecretKeys();
+ while (itr.hasNext()) {
+ keys.add(itr.next());
+ }
+
+ return keys;
+ }
+
+ public static PGPSecretKey BytesToPGPSecretKey(byte[] keyBytes) {
+ PGPSecretKey key = BytesToPGPSecretKeyList(keyBytes).get(0);
+
+ return key;
+ }
+
+ public static byte[] PGPSecretKeyToBytes(PGPSecretKey key) {
+ try {
+ return key.getEncoded();
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "Encoding failed: ", e);
+
+ return null;
+ }
+ }
+
+ public static byte[] PGPSecretKeyRingToBytes(PGPSecretKeyRing keyRing) {
+ try {
+ return keyRing.getEncoded();
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "Encoding failed: ", e);
+
+ return null;
+ }
+ }
+}
diff --git a/org_apg/src/org/thialfihar/android/apg/helper/PGPHelper.java b/org_apg/src/org/thialfihar/android/apg/helper/PGPHelper.java
new file mode 100644
index 000000000..5eb83363f
--- /dev/null
+++ b/org_apg/src/org/thialfihar/android/apg/helper/PGPHelper.java
@@ -0,0 +1,2356 @@
+/*
+ * Copyright (C) 2012 Dominik Schürmann
+ * Copyright (C) 2010 Thialfihar
+ *
+ * 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.thialfihar.android.apg.helper;
+
+import org.spongycastle.bcpg.ArmoredInputStream;
+import org.spongycastle.bcpg.ArmoredOutputStream;
+import org.spongycastle.bcpg.BCPGOutputStream;
+import org.spongycastle.bcpg.CompressionAlgorithmTags;
+import org.spongycastle.bcpg.HashAlgorithmTags;
+import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags;
+import org.spongycastle.bcpg.sig.KeyFlags;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ElGamalParameterSpec;
+import org.spongycastle.openpgp.PGPCompressedData;
+import org.spongycastle.openpgp.PGPCompressedDataGenerator;
+import org.spongycastle.openpgp.PGPEncryptedData;
+import org.spongycastle.openpgp.PGPEncryptedDataGenerator;
+import org.spongycastle.openpgp.PGPEncryptedDataList;
+import org.spongycastle.openpgp.PGPException;
+import org.spongycastle.openpgp.PGPKeyPair;
+import org.spongycastle.openpgp.PGPKeyRing;
+import org.spongycastle.openpgp.PGPKeyRingGenerator;
+import org.spongycastle.openpgp.PGPLiteralData;
+import org.spongycastle.openpgp.PGPLiteralDataGenerator;
+import org.spongycastle.openpgp.PGPObjectFactory;
+import org.spongycastle.openpgp.PGPOnePassSignature;
+import org.spongycastle.openpgp.PGPOnePassSignatureList;
+import org.spongycastle.openpgp.PGPPBEEncryptedData;
+import org.spongycastle.openpgp.PGPPrivateKey;
+import org.spongycastle.openpgp.PGPPublicKey;
+import org.spongycastle.openpgp.PGPPublicKeyEncryptedData;
+import org.spongycastle.openpgp.PGPPublicKeyRing;
+import org.spongycastle.openpgp.PGPSecretKey;
+import org.spongycastle.openpgp.PGPSecretKeyRing;
+import org.spongycastle.openpgp.PGPSignature;
+import org.spongycastle.openpgp.PGPSignatureGenerator;
+import org.spongycastle.openpgp.PGPSignatureList;
+import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator;
+import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
+import org.spongycastle.openpgp.PGPUtil;
+import org.spongycastle.openpgp.PGPV3SignatureGenerator;
+import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
+import org.spongycastle.openpgp.operator.PBESecretKeyEncryptor;
+import org.spongycastle.openpgp.operator.PGPContentSignerBuilder;
+import org.spongycastle.openpgp.operator.PGPDigestCalculator;
+import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
+import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
+import org.spongycastle.openpgp.operator.jcajce.JcaPGPKeyPair;
+import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
+import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder;
+import org.thialfihar.android.apg.Id.choice;
+import org.thialfihar.android.apg.Id.content;
+import org.thialfihar.android.apg.Id.database;
+import org.thialfihar.android.apg.Id.key;
+import org.thialfihar.android.apg.Id.return_value;
+import org.thialfihar.android.apg.Id.type;
+import org.thialfihar.android.apg.Id.choice.algorithm;
+import org.thialfihar.android.apg.Id.choice.compression;
+import org.thialfihar.android.apg.Id.choice.usage;
+import org.thialfihar.android.apg.KeyServer.AddKeyException;
+import org.thialfihar.android.apg.R.string;
+import org.thialfihar.android.apg.passphrase.CachedPassPhrase;
+import org.thialfihar.android.apg.provider.DataProvider;
+import org.thialfihar.android.apg.provider.Database;
+import org.thialfihar.android.apg.provider.KeyRings;
+import org.thialfihar.android.apg.provider.Keys;
+import org.thialfihar.android.apg.provider.UserIds;
+import org.thialfihar.android.apg.service.ApgService;
+import org.thialfihar.android.apg.ui.BaseActivity;
+import org.thialfihar.android.apg.ui.widget.KeyEditor;
+import org.thialfihar.android.apg.ui.widget.SectionView;
+import org.thialfihar.android.apg.ui.widget.UserIdEditor;
+import org.thialfihar.android.apg.util.InputData;
+import org.thialfihar.android.apg.util.IterableIterator;
+import org.thialfihar.android.apg.util.PositionAwareInputStream;
+import org.thialfihar.android.apg.util.Primes;
+import org.thialfihar.android.apg.Constants;
+import org.thialfihar.android.apg.HkpKeyServer;
+import org.thialfihar.android.apg.Id;
+import org.thialfihar.android.apg.KeyServer;
+import org.thialfihar.android.apg.ProgressDialogUpdater;
+import org.thialfihar.android.apg.R;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Message;
+import android.util.Log;
+import android.view.ViewGroup;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.SignatureException;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Vector;
+import java.util.regex.Pattern;
+
+/**
+ * TODO:
+ *
+ * - Externalize the constants
+ *
+ * - Separate this file into different helpers
+ *
+ */
+public class PGPHelper {
+
+ static {
+ // register spongy castle provider
+ Security.addProvider(new BouncyCastleProvider());
+ }
+
+ public static final String PACKAGE_NAME = "org.thialfihar.android.apg";
+
+ private static final String INTENT_PREFIX = "org.thialfihar.android.apg.intent.";
+
+ public static class Intent {
+ public static final String DECRYPT = INTENT_PREFIX + "DECRYPT";
+ public static final String ENCRYPT = INTENT_PREFIX + "ENCRYPT";
+ public static final String DECRYPT_FILE = INTENT_PREFIX + "DECRYPT_FILE";
+ public static final String ENCRYPT_FILE = INTENT_PREFIX + "ENCRYPT_FILE";
+ public static final String DECRYPT_AND_RETURN = INTENT_PREFIX + "DECRYPT_AND_RETURN";
+ public static final String ENCRYPT_AND_RETURN = INTENT_PREFIX + "ENCRYPT_AND_RETURN";
+ public static final String SELECT_PUBLIC_KEYS = INTENT_PREFIX + "SELECT_PUBLIC_KEYS";
+ public static final String SELECT_SECRET_KEY = INTENT_PREFIX + "SELECT_SECRET_KEY";
+ public static final String IMPORT = INTENT_PREFIX + "IMPORT";
+ public static final String LOOK_UP_KEY_ID = INTENT_PREFIX + "LOOK_UP_KEY_ID";
+ public static final String LOOK_UP_KEY_ID_AND_RETURN = INTENT_PREFIX
+ + "LOOK_UP_KEY_ID_AND_RETURN";
+ public static final String GENERATE_SIGNATURE = INTENT_PREFIX + "GENERATE_SIGNATURE";
+ public static final String EXPORT_KEY_TO_SERVER = INTENT_PREFIX + "EXPORT_KEY_TO_SERVER";
+ public static final String IMPORT_FROM_QR_CODE = INTENT_PREFIX + "IMPORT_FROM_QR_CODE";
+ public static final String CREATE_KEY = INTENT_PREFIX + "CREATE_KEY";
+ public static final String EDIT_KEY = INTENT_PREFIX + "EDIT_KEY";
+ }
+
+ public static final String EXTRA_TEXT = "text";
+ public static final String EXTRA_DATA = "data";
+ public static final String EXTRA_ERROR = "error";
+ public static final String EXTRA_DECRYPTED_MESSAGE = "decryptedMessage";
+ public static final String EXTRA_DECRYPTED_DATA = "decryptedData";
+ public static final String EXTRA_ENCRYPTED_MESSAGE = "encryptedMessage";
+ public static final String EXTRA_ENCRYPTED_DATA = "encryptedData";
+ public static final String EXTRA_RESULT_URI = "resultUri";
+ public static final String EXTRA_SIGNATURE_DATA = "signatureData";
+ public static final String EXTRA_SIGNATURE_TEXT = "signatureText";
+ public static final String EXTRA_SIGNATURE_KEY_ID = "signatureKeyId";
+ public static final String EXTRA_USER_ID = "userId";
+ public static final String EXTRA_USER_IDS = "userIds";
+ public static final String EXTRA_KEY_ID = "keyId";
+ public static final String EXTRA_REPLY_TO = "replyTo";
+ public static final String EXTRA_SEND_TO = "sendTo";
+ public static final String EXTRA_SUBJECT = "subject";
+ public static final String EXTRA_ENCRYPTION_KEY_IDS = "encryptionKeyIds";
+ public static final String EXTRA_SELECTION = "selection";
+ public static final String EXTRA_ASCII_ARMOUR = "asciiArmour";
+ public static final String EXTRA_BINARY = "binary";
+ public static final String EXTRA_KEY_SERVERS = "keyServers";
+ public static final String EXTRA_EXPECTED_FINGERPRINT = "expectedFingerprint";
+ public static final String EXTRA_NO_PASSPHRASE = "noPassphrase";
+ public static final String EXTRA_GENERATE_DEFAULT_KEYS = "generateDefaultKeys";
+
+ public static final String AUTHORITY = DataProvider.AUTHORITY;
+
+ public static final Uri CONTENT_URI_SECRET_KEY_RINGS = Uri.parse("content://" + AUTHORITY
+ + "/key_rings/secret/");
+ public static final Uri CONTENT_URI_SECRET_KEY_RING_BY_KEY_ID = Uri.parse("content://"
+ + AUTHORITY + "/key_rings/secret/key_id/");
+ public static final Uri CONTENT_URI_SECRET_KEY_RING_BY_EMAILS = Uri.parse("content://"
+ + AUTHORITY + "/key_rings/secret/emails/");
+
+ public static final Uri CONTENT_URI_PUBLIC_KEY_RINGS = Uri.parse("content://" + AUTHORITY
+ + "/key_rings/public/");
+ public static final Uri CONTENT_URI_PUBLIC_KEY_RING_BY_KEY_ID = Uri.parse("content://"
+ + AUTHORITY + "/key_rings/public/key_id/");
+ public static final Uri CONTENT_URI_PUBLIC_KEY_RING_BY_EMAILS = Uri.parse("content://"
+ + AUTHORITY + "/key_rings/public/emails/");
+
+ private static String VERSION = null;
+
+ private static final int[] PREFERRED_SYMMETRIC_ALGORITHMS = new int[] {
+ SymmetricKeyAlgorithmTags.AES_256, SymmetricKeyAlgorithmTags.AES_192,
+ SymmetricKeyAlgorithmTags.AES_128, SymmetricKeyAlgorithmTags.CAST5,
+ SymmetricKeyAlgorithmTags.TRIPLE_DES };
+ private static final int[] PREFERRED_HASH_ALGORITHMS = new int[] { HashAlgorithmTags.SHA1,
+ HashAlgorithmTags.SHA256, HashAlgorithmTags.RIPEMD160 };
+ private static final int[] PREFERRED_COMPRESSION_ALGORITHMS = new int[] {
+ CompressionAlgorithmTags.ZLIB, CompressionAlgorithmTags.BZIP2,
+ CompressionAlgorithmTags.ZIP };
+
+ public static Pattern PGP_MESSAGE = Pattern.compile(
+ ".*?(-----BEGIN PGP MESSAGE-----.*?-----END PGP MESSAGE-----).*", Pattern.DOTALL);
+
+ public static Pattern PGP_SIGNED_MESSAGE = Pattern
+ .compile(
+ ".*?(-----BEGIN PGP SIGNED MESSAGE-----.*?-----BEGIN PGP SIGNATURE-----.*?-----END PGP SIGNATURE-----).*",
+ Pattern.DOTALL);
+
+ public static Pattern PGP_PUBLIC_KEY = Pattern.compile(
+ ".*?(-----BEGIN PGP PUBLIC KEY BLOCK-----.*?-----END PGP PUBLIC KEY BLOCK-----).*",
+ Pattern.DOTALL);
+
+ private static HashMap mPassPhraseCache = new HashMap();
+ private static String mEditPassPhrase = null;
+
+ private static Database mDatabase = null;
+
+ public static class GeneralException extends Exception {
+ static final long serialVersionUID = 0xf812773342L;
+
+ public GeneralException(String message) {
+ super(message);
+ }
+ }
+
+ public static class NoAsymmetricEncryptionException extends Exception {
+ static final long serialVersionUID = 0xf812773343L;
+
+ public NoAsymmetricEncryptionException() {
+ super();
+ }
+ }
+
+ public static void initialize(Context context) {
+ if (mDatabase == null) {
+ mDatabase = new Database(context);
+ }
+ }
+
+ public static Database getDatabase() {
+ return mDatabase;
+ }
+
+ public static void setEditPassPhrase(String passPhrase) {
+ mEditPassPhrase = passPhrase;
+ }
+
+ public static String getEditPassPhrase() {
+ return mEditPassPhrase;
+ }
+
+ public static void setCachedPassPhrase(long keyId, String passPhrase) {
+ mPassPhraseCache.put(keyId, new CachedPassPhrase(new Date().getTime(), passPhrase));
+ }
+
+ public static String getCachedPassPhrase(long keyId) {
+ long realId = keyId;
+ if (realId != Id.key.symmetric) {
+ PGPSecretKeyRing keyRing = getSecretKeyRing(keyId);
+ if (keyRing == null) {
+ return null;
+ }
+ PGPSecretKey masterKey = getMasterKey(keyRing);
+ if (masterKey == null) {
+ return null;
+ }
+ realId = masterKey.getKeyID();
+ }
+ CachedPassPhrase cpp = mPassPhraseCache.get(realId);
+ if (cpp == null) {
+ return null;
+ }
+ // set it again to reset the cache life cycle
+ setCachedPassPhrase(realId, cpp.passPhrase);
+ return cpp.passPhrase;
+ }
+
+ public static int cleanUpCache(int ttl, int initialDelay) {
+ int delay = initialDelay;
+ long realTtl = ttl * 1000;
+ long now = new Date().getTime();
+ Vector oldKeys = new Vector();
+ for (Map.Entry pair : mPassPhraseCache.entrySet()) {
+ long lived = now - pair.getValue().timestamp;
+ if (lived >= realTtl) {
+ oldKeys.add(pair.getKey());
+ } else {
+ // see, whether the remaining time for this cache entry improves our
+ // check delay
+ long nextCheck = realTtl - lived + 1000;
+ if (nextCheck < delay) {
+ delay = (int) nextCheck;
+ }
+ }
+ }
+
+ for (long keyId : oldKeys) {
+ mPassPhraseCache.remove(keyId);
+ }
+
+ return delay;
+ }
+
+ /**
+ * Creates new secret key. The returned PGPSecretKeyRing contains only one newly generated key
+ * when this key is the new masterkey. If a masterkey is supplied in the parameters
+ * PGPSecretKeyRing contains the masterkey and the new key as a subkey (certified by the
+ * masterkey).
+ *
+ * @param context
+ * @param algorithmChoice
+ * @param keySize
+ * @param passPhrase
+ * @param masterSecretKey
+ * @return
+ * @throws NoSuchAlgorithmException
+ * @throws PGPException
+ * @throws NoSuchProviderException
+ * @throws GeneralException
+ * @throws InvalidAlgorithmParameterException
+ */
+ public static PGPSecretKeyRing createKey(Context context, int algorithmChoice, int keySize,
+ String passPhrase, PGPSecretKey masterSecretKey) throws NoSuchAlgorithmException,
+ PGPException, NoSuchProviderException, GeneralException,
+ InvalidAlgorithmParameterException {
+
+ if (keySize < 512) {
+ throw new GeneralException(context.getString(R.string.error_keySizeMinimum512bit));
+ }
+
+ if (passPhrase == null) {
+ passPhrase = "";
+ }
+
+ int algorithm = 0;
+ KeyPairGenerator keyGen = null;
+
+ switch (algorithmChoice) {
+ case Id.choice.algorithm.dsa: {
+ keyGen = KeyPairGenerator.getInstance("DSA", "SC");
+ keyGen.initialize(keySize, new SecureRandom());
+ algorithm = PGPPublicKey.DSA;
+ break;
+ }
+
+ case Id.choice.algorithm.elgamal: {
+ if (masterSecretKey == null) {
+ throw new GeneralException(
+ context.getString(R.string.error_masterKeyMustNotBeElGamal));
+ }
+ keyGen = KeyPairGenerator.getInstance("ELGAMAL", "SC");
+ BigInteger p = Primes.getBestPrime(keySize);
+ BigInteger g = new BigInteger("2");
+
+ ElGamalParameterSpec elParams = new ElGamalParameterSpec(p, g);
+
+ keyGen.initialize(elParams);
+ algorithm = PGPPublicKey.ELGAMAL_ENCRYPT;
+ break;
+ }
+
+ case Id.choice.algorithm.rsa: {
+ keyGen = KeyPairGenerator.getInstance("RSA", "SC");
+ keyGen.initialize(keySize, new SecureRandom());
+
+ algorithm = PGPPublicKey.RSA_GENERAL;
+ break;
+ }
+
+ default: {
+ throw new GeneralException(context.getString(R.string.error_unknownAlgorithmChoice));
+ }
+ }
+
+ // build new key pair
+ PGPKeyPair keyPair = new JcaPGPKeyPair(algorithm, keyGen.generateKeyPair(), new Date());
+
+ // define hashing and signing algos
+ PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get(
+ HashAlgorithmTags.SHA1);
+ PGPContentSignerBuilder certificationSignerBuilder = new JcaPGPContentSignerBuilder(keyPair
+ .getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA1);
+
+ // Build key encrypter and decrypter based on passphrase
+ PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
+ PGPEncryptedData.CAST5, sha1Calc).setProvider("SC").build(passPhrase.toCharArray());
+ PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
+ .setProvider("SC").build(passPhrase.toCharArray());
+
+ PGPKeyRingGenerator ringGen = null;
+ if (masterSecretKey == null) {
+
+ // build keyRing with only this one master key in it!
+ ringGen = new PGPKeyRingGenerator(PGPSignature.DEFAULT_CERTIFICATION, keyPair, "",
+ sha1Calc, null, null, certificationSignerBuilder, keyEncryptor);
+ } else {
+ PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey();
+ PGPPrivateKey masterPrivateKey = masterSecretKey.extractPrivateKey(keyDecryptor);
+ PGPKeyPair masterKeyPair = new PGPKeyPair(masterPublicKey, masterPrivateKey);
+
+ // build keyRing with master key and new key as subkey (certified by masterkey)
+ ringGen = new PGPKeyRingGenerator(PGPSignature.DEFAULT_CERTIFICATION, masterKeyPair,
+ "", sha1Calc, null, null, certificationSignerBuilder, keyEncryptor);
+
+ ringGen.addSubKey(keyPair);
+ }
+
+ PGPSecretKeyRing secKeyRing = ringGen.generateSecretKeyRing();
+
+ return secKeyRing;
+ }
+
+ public static void buildSecretKey(Context context, ArrayList userIds,
+ ArrayList keys, ArrayList keysUsages, long masterKeyId,
+ String oldPassPhrase, String newPassPhrase, ProgressDialogUpdater progress)
+ throws PGPHelper.GeneralException, NoSuchProviderException, PGPException,
+ NoSuchAlgorithmException, SignatureException, IOException, Database.GeneralException {
+
+ if (progress != null)
+ progress.setProgress(R.string.progress_buildingKey, 0, 100);
+
+ if (oldPassPhrase == null || oldPassPhrase.equals("")) {
+ oldPassPhrase = "";
+ }
+
+ if (newPassPhrase == null || newPassPhrase.equals("")) {
+ newPassPhrase = "";
+ }
+
+ // Vector userIds = new Vector();
+ // Vector keys = new Vector();
+
+ // ViewGroup userIdEditors = userIdsView.getEditors();
+ // ViewGroup keyEditors = keysView.getEditors();
+ //
+ // boolean gotMainUserId = false;
+ // for (int i = 0; i < userIdEditors.getChildCount(); ++i) {
+ // UserIdEditor editor = (UserIdEditor) userIdEditors.getChildAt(i);
+ // String userId = null;
+ // try {
+ // userId = editor.getValue();
+ // } catch (UserIdEditor.NoNameException e) {
+ // throw new Apg.GeneralException(context.getString(R.string.error_userIdNeedsAName));
+ // } catch (UserIdEditor.NoEmailException e) {
+ // throw new Apg.GeneralException(
+ // context.getString(R.string.error_userIdNeedsAnEmailAddress));
+ // } catch (UserIdEditor.InvalidEmailException e) {
+ // throw new Apg.GeneralException("" + e);
+ // }
+ //
+ // if (userId.equals("")) {
+ // continue;
+ // }
+ //
+ // if (editor.isMainUserId()) {
+ // userIds.insertElementAt(userId, 0);
+ // gotMainUserId = true;
+ // } else {
+ // userIds.add(userId);
+ // }
+ // }
+
+ // if (userIds.size() == 0) {
+ // throw new Apg.GeneralException(context.getString(R.string.error_keyNeedsAUserId));
+ // }
+ //
+ // if (!gotMainUserId) {
+ // throw new Apg.GeneralException(
+ // context.getString(R.string.error_mainUserIdMustNotBeEmpty));
+ // }
+
+ // if (keyEditors.getChildCount() == 0) {
+ // throw new Apg.GeneralException(context.getString(R.string.error_keyNeedsMasterKey));
+ // }
+ //
+ // for (int i = 0; i < keyEditors.getChildCount(); ++i) {
+ // KeyEditor editor = (KeyEditor) keyEditors.getChildAt(i);
+ // keys.add(editor.getValue());
+ // }
+
+ if (progress != null)
+ progress.setProgress(R.string.progress_preparingMasterKey, 10, 100);
+
+ // KeyEditor keyEditor = (KeyEditor) keyEditors.getChildAt(0);
+ // int usageId = keyEditor.getUsage();
+
+ int usageId = keysUsages.get(0);
+ boolean canSign = (usageId == Id.choice.usage.sign_only || usageId == Id.choice.usage.sign_and_encrypt);
+ boolean canEncrypt = (usageId == Id.choice.usage.encrypt_only || usageId == Id.choice.usage.sign_and_encrypt);
+
+ String mainUserId = userIds.get(0);
+
+ PGPSecretKey masterKey = keys.get(0);
+ PGPPublicKey tmpKey = masterKey.getPublicKey();
+ PGPPublicKey masterPublicKey = new PGPPublicKey(tmpKey.getAlgorithm(),
+ tmpKey.getKey(new BouncyCastleProvider()), tmpKey.getCreationTime());
+ PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
+ .setProvider("SC").build(oldPassPhrase.toCharArray());
+ PGPPrivateKey masterPrivateKey = masterKey.extractPrivateKey(keyDecryptor);
+
+ if (progress != null)
+ progress.setProgress(R.string.progress_certifyingMasterKey, 20, 100);
+ for (int i = 0; i < userIds.size(); ++i) {
+ String userId = userIds.get(i);
+
+ PGPSignatureGenerator sGen = new PGPSignatureGenerator(masterPublicKey.getAlgorithm(),
+ HashAlgorithmTags.SHA1, new BouncyCastleProvider());
+
+ sGen.initSign(PGPSignature.POSITIVE_CERTIFICATION, masterPrivateKey);
+
+ PGPSignature certification = sGen.generateCertification(userId, masterPublicKey);
+
+ masterPublicKey = PGPPublicKey.addCertification(masterPublicKey, userId, certification);
+ }
+
+ // TODO: cross-certify the master key with every sub key
+
+ PGPKeyPair masterKeyPair = new PGPKeyPair(masterPublicKey, masterPrivateKey);
+
+ PGPSignatureSubpacketGenerator hashedPacketsGen = new PGPSignatureSubpacketGenerator();
+ PGPSignatureSubpacketGenerator unhashedPacketsGen = new PGPSignatureSubpacketGenerator();
+
+ int keyFlags = KeyFlags.CERTIFY_OTHER | KeyFlags.SIGN_DATA;
+ if (canEncrypt) {
+ keyFlags |= KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE;
+ }
+ hashedPacketsGen.setKeyFlags(true, keyFlags);
+
+ hashedPacketsGen.setPreferredSymmetricAlgorithms(true, PREFERRED_SYMMETRIC_ALGORITHMS);
+ hashedPacketsGen.setPreferredHashAlgorithms(true, PREFERRED_HASH_ALGORITHMS);
+ hashedPacketsGen.setPreferredCompressionAlgorithms(true, PREFERRED_COMPRESSION_ALGORITHMS);
+
+ // TODO: this doesn't work quite right yet
+ // if (keyEditor.getExpiryDate() != null) {
+ // GregorianCalendar creationDate = new GregorianCalendar();
+ // creationDate.setTime(getCreationDate(masterKey));
+ // GregorianCalendar expiryDate = keyEditor.getExpiryDate();
+ // long numDays = Utils.getNumDaysBetween(creationDate, expiryDate);
+ // if (numDays <= 0) {
+ // throw new GeneralException(
+ // context.getString(R.string.error_expiryMustComeAfterCreation));
+ // }
+ // hashedPacketsGen.setKeyExpirationTime(true, numDays * 86400);
+ // }
+
+ if (progress != null) {
+ progress.setProgress(R.string.progress_buildingMasterKeyRing, 30, 100);
+ }
+
+ PGPKeyRingGenerator keyGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION,
+ masterKeyPair, mainUserId, PGPEncryptedData.CAST5, newPassPhrase.toCharArray(),
+ hashedPacketsGen.generate(), unhashedPacketsGen.generate(), new SecureRandom(),
+ new BouncyCastleProvider().getName());
+
+ if (progress != null)
+ progress.setProgress(R.string.progress_addingSubKeys, 40, 100);
+ for (int i = 1; i < keys.size(); ++i) {
+ if (progress != null)
+ progress.setProgress(40 + 50 * (i - 1) / (keys.size() - 1), 100);
+ PGPSecretKey subKey = keys.get(i);
+ // keyEditor = (KeyEditor) keyEditors.getChildAt(i);
+ PGPPublicKey subPublicKey = subKey.getPublicKey();
+
+ PBESecretKeyDecryptor keyDecryptor2 = new JcePBESecretKeyDecryptorBuilder()
+ .setProvider("SC").build(oldPassPhrase.toCharArray());
+ PGPPrivateKey subPrivateKey = subKey.extractPrivateKey(keyDecryptor2);
+ PGPKeyPair subKeyPair = new PGPKeyPair(subPublicKey.getAlgorithm(),
+ subPublicKey.getKey(new BouncyCastleProvider()), subPrivateKey.getKey(),
+ subPublicKey.getCreationTime());
+
+ hashedPacketsGen = new PGPSignatureSubpacketGenerator();
+ unhashedPacketsGen = new PGPSignatureSubpacketGenerator();
+
+ keyFlags = 0;
+ // usageId = keyEditor.getUsage();
+
+ usageId = keysUsages.get(i);
+ canSign = (usageId == Id.choice.usage.sign_only || usageId == Id.choice.usage.sign_and_encrypt);
+ canEncrypt = (usageId == Id.choice.usage.encrypt_only || usageId == Id.choice.usage.sign_and_encrypt);
+ if (canSign) {
+ keyFlags |= KeyFlags.SIGN_DATA;
+ }
+ if (canEncrypt) {
+ keyFlags |= KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE;
+ }
+ hashedPacketsGen.setKeyFlags(true, keyFlags);
+
+ // TODO: this doesn't work quite right yet
+ // if (keyEditor.getExpiryDate() != null) {
+ // GregorianCalendar creationDate = new GregorianCalendar();
+ // creationDate.setTime(getCreationDate(masterKey));
+ // GregorianCalendar expiryDate = keyEditor.getExpiryDate();
+ // long numDays = Utils.getNumDaysBetween(creationDate, expiryDate);
+ // if (numDays <= 0) {
+ // throw new GeneralException(
+ // context.getString(R.string.error_expiryMustComeAfterCreation));
+ // }
+ // hashedPacketsGen.setKeyExpirationTime(true, numDays * 86400);
+ // }
+
+ keyGen.addSubKey(subKeyPair, hashedPacketsGen.generate(), unhashedPacketsGen.generate());
+ }
+
+ PGPSecretKeyRing secretKeyRing = keyGen.generateSecretKeyRing();
+ PGPPublicKeyRing publicKeyRing = keyGen.generatePublicKeyRing();
+
+ if (progress != null)
+ progress.setProgress(R.string.progress_savingKeyRing, 90, 100);
+ mDatabase.saveKeyRing(secretKeyRing);
+ mDatabase.saveKeyRing(publicKeyRing);
+
+ if (progress != null)
+ progress.setProgress(R.string.progress_done, 100, 100);
+ }
+
+ public static PGPKeyRing decodeKeyRing(InputStream is) throws IOException {
+ InputStream in = PGPUtil.getDecoderStream(is);
+ PGPObjectFactory objectFactory = new PGPObjectFactory(in);
+ Object obj = objectFactory.nextObject();
+
+ if (obj instanceof PGPKeyRing) {
+ return (PGPKeyRing) obj;
+ }
+
+ return null;
+ }
+
+ public static int storeKeyRingInCache(PGPKeyRing keyring) {
+ int status = Integer.MIN_VALUE; // out of bounds value (Id.retrun_value.*)
+ try {
+ if (keyring instanceof PGPSecretKeyRing) {
+ PGPSecretKeyRing secretKeyRing = (PGPSecretKeyRing) keyring;
+ boolean save = true;
+ try {
+ PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
+ .setProvider("SC").build(new char[] {});
+ PGPPrivateKey testKey = secretKeyRing.getSecretKey().extractPrivateKey(
+ keyDecryptor);
+ if (testKey == null) {
+ // this is bad, something is very wrong... likely a --export-secret-subkeys
+ // export
+ save = false;
+ status = Id.return_value.bad;
+ }
+ } catch (PGPException e) {
+ // all good if this fails, we likely didn't use the right password
+ }
+
+ if (save) {
+ status = mDatabase.saveKeyRing(secretKeyRing);
+ }
+ } else if (keyring instanceof PGPPublicKeyRing) {
+ PGPPublicKeyRing publicKeyRing = (PGPPublicKeyRing) keyring;
+ status = mDatabase.saveKeyRing(publicKeyRing);
+ }
+ } catch (IOException e) {
+ status = Id.return_value.error;
+ } catch (Database.GeneralException e) {
+ status = Id.return_value.error;
+ }
+
+ return status;
+ }
+
+ public static boolean uploadKeyRingToServer(HkpKeyServer server, PGPPublicKeyRing keyring) {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ArmoredOutputStream aos = new ArmoredOutputStream(bos);
+ try {
+ aos.write(keyring.getEncoded());
+ aos.close();
+
+ String armouredKey = bos.toString("UTF-8");
+ server.add(armouredKey);
+
+ return true;
+ } catch (IOException e) {
+ return false;
+ } catch (AddKeyException e) {
+ // TODO: tell the user?
+ return false;
+ } finally {
+ try {
+ bos.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ public static Bundle importKeyRings(Activity context, int type, InputData data,
+ ProgressDialogUpdater progress) throws GeneralException, FileNotFoundException,
+ PGPException, IOException {
+ Bundle returnData = new Bundle();
+
+ if (type == Id.type.secret_key) {
+ if (progress != null)
+ progress.setProgress(R.string.progress_importingSecretKeys, 0, 100);
+ } else {
+ if (progress != null)
+ progress.setProgress(R.string.progress_importingPublicKeys, 0, 100);
+ }
+
+ if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+ throw new GeneralException(context.getString(R.string.error_externalStorageNotReady));
+ }
+
+ PositionAwareInputStream progressIn = new PositionAwareInputStream(data.getInputStream());
+ // need to have access to the bufferedInput, so we can reuse it for the possible
+ // PGPObject chunks after the first one, e.g. files with several consecutive ASCII
+ // armour blocks
+ BufferedInputStream bufferedInput = new BufferedInputStream(progressIn);
+ int newKeys = 0;
+ int oldKeys = 0;
+ int badKeys = 0;
+ try {
+ PGPKeyRing keyring = decodeKeyRing(bufferedInput);
+ while (keyring != null) {
+ int status = Integer.MIN_VALUE; // out of bounds value
+
+ // if this key is what we expect it to be, save it
+ if ((type == Id.type.secret_key && keyring instanceof PGPSecretKeyRing)
+ || (type == Id.type.public_key && keyring instanceof PGPPublicKeyRing)) {
+ status = storeKeyRingInCache(keyring);
+ }
+
+ if (status == Id.return_value.error) {
+ throw new GeneralException(context.getString(R.string.error_savingKeys));
+ }
+
+ // update the counts to display to the user at the end
+ if (status == Id.return_value.updated) {
+ ++oldKeys;
+ } else if (status == Id.return_value.ok) {
+ ++newKeys;
+ } else if (status == Id.return_value.bad) {
+ ++badKeys;
+ }
+
+ if (progress != null) {
+ progress.setProgress((int) (100 * progressIn.position() / data.getSize()), 100);
+ }
+ // TODO: needed?
+ // obj = objectFactory.nextObject();
+
+ keyring = decodeKeyRing(bufferedInput);
+ }
+ } catch (EOFException e) {
+ // nothing to do, we are done
+ }
+
+ returnData.putInt("added", newKeys);
+ returnData.putInt("updated", oldKeys);
+ returnData.putInt("bad", badKeys);
+
+ if (progress != null)
+ progress.setProgress(R.string.progress_done, 100, 100);
+
+ return returnData;
+ }
+
+ public static Bundle exportKeyRings(Activity context, Vector keyRingIds,
+ OutputStream outStream, ProgressDialogUpdater progress) throws GeneralException,
+ FileNotFoundException, PGPException, IOException {
+ Bundle returnData = new Bundle();
+
+ if (keyRingIds.size() == 1) {
+ if (progress != null)
+ progress.setProgress(R.string.progress_exportingKey, 0, 100);
+ } else {
+ if (progress != null)
+ progress.setProgress(R.string.progress_exportingKeys, 0, 100);
+ }
+
+ if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+ throw new GeneralException(context.getString(R.string.error_externalStorageNotReady));
+ }
+ ArmoredOutputStream out = new ArmoredOutputStream(outStream);
+
+ int numKeys = 0;
+ for (int i = 0; i < keyRingIds.size(); ++i) {
+ if (progress != null)
+ progress.setProgress(i * 100 / keyRingIds.size(), 100);
+ Object obj = mDatabase.getKeyRing(keyRingIds.get(i));
+ PGPPublicKeyRing publicKeyRing;
+ PGPSecretKeyRing secretKeyRing;
+
+ if (obj instanceof PGPSecretKeyRing) {
+ secretKeyRing = (PGPSecretKeyRing) obj;
+ secretKeyRing.encode(out);
+ } else if (obj instanceof PGPPublicKeyRing) {
+ publicKeyRing = (PGPPublicKeyRing) obj;
+ publicKeyRing.encode(out);
+ } else {
+ continue;
+ }
+ ++numKeys;
+ }
+ out.close();
+ returnData.putInt("exported", numKeys);
+
+ if (progress != null)
+ progress.setProgress(R.string.progress_done, 100, 100);
+
+ return returnData;
+ }
+
+ public static Date getCreationDate(PGPPublicKey key) {
+ return key.getCreationTime();
+ }
+
+ public static Date getCreationDate(PGPSecretKey key) {
+ return key.getPublicKey().getCreationTime();
+ }
+
+ @SuppressWarnings("unchecked")
+ public static PGPPublicKey getMasterKey(PGPPublicKeyRing keyRing) {
+ if (keyRing == null) {
+ return null;
+ }
+ for (PGPPublicKey key : new IterableIterator(keyRing.getPublicKeys())) {
+ if (key.isMasterKey()) {
+ return key;
+ }
+ }
+
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static PGPSecretKey getMasterKey(PGPSecretKeyRing keyRing) {
+ if (keyRing == null) {
+ return null;
+ }
+ for (PGPSecretKey key : new IterableIterator(keyRing.getSecretKeys())) {
+ if (key.isMasterKey()) {
+ return key;
+ }
+ }
+
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static Vector getEncryptKeys(PGPPublicKeyRing keyRing) {
+ Vector encryptKeys = new Vector();
+
+ for (PGPPublicKey key : new IterableIterator(keyRing.getPublicKeys())) {
+ if (isEncryptionKey(key)) {
+ encryptKeys.add(key);
+ }
+ }
+
+ return encryptKeys;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static Vector getSigningKeys(PGPSecretKeyRing keyRing) {
+ Vector signingKeys = new Vector();
+
+ for (PGPSecretKey key : new IterableIterator(keyRing.getSecretKeys())) {
+ if (isSigningKey(key)) {
+ signingKeys.add(key);
+ }
+ }
+
+ return signingKeys;
+ }
+
+ public static Vector getUsableEncryptKeys(PGPPublicKeyRing keyRing) {
+ Vector usableKeys = new Vector();
+ Vector encryptKeys = getEncryptKeys(keyRing);
+ PGPPublicKey masterKey = null;
+ for (int i = 0; i < encryptKeys.size(); ++i) {
+ PGPPublicKey key = encryptKeys.get(i);
+ if (!isExpired(key)) {
+ if (key.isMasterKey()) {
+ masterKey = key;
+ } else {
+ usableKeys.add(key);
+ }
+ }
+ }
+ if (masterKey != null) {
+ usableKeys.add(masterKey);
+ }
+ return usableKeys;
+ }
+
+ public static boolean isExpired(PGPPublicKey key) {
+ Date creationDate = getCreationDate(key);
+ Date expiryDate = getExpiryDate(key);
+ Date now = new Date();
+ if (now.compareTo(creationDate) >= 0
+ && (expiryDate == null || now.compareTo(expiryDate) <= 0)) {
+ return false;
+ }
+ return true;
+ }
+
+ public static boolean isExpired(PGPSecretKey key) {
+ return isExpired(key.getPublicKey());
+ }
+
+ public static Vector getUsableSigningKeys(PGPSecretKeyRing keyRing) {
+ Vector usableKeys = new Vector();
+ Vector signingKeys = getSigningKeys(keyRing);
+ PGPSecretKey masterKey = null;
+ for (int i = 0; i < signingKeys.size(); ++i) {
+ PGPSecretKey key = signingKeys.get(i);
+ if (key.isMasterKey()) {
+ masterKey = key;
+ } else {
+ usableKeys.add(key);
+ }
+ }
+ if (masterKey != null) {
+ usableKeys.add(masterKey);
+ }
+ return usableKeys;
+ }
+
+ public static Date getExpiryDate(PGPPublicKey key) {
+ Date creationDate = getCreationDate(key);
+ if (key.getValidDays() == 0) {
+ // no expiry
+ return null;
+ }
+ Calendar calendar = GregorianCalendar.getInstance();
+ calendar.setTime(creationDate);
+ calendar.add(Calendar.DATE, key.getValidDays());
+ Date expiryDate = calendar.getTime();
+
+ return expiryDate;
+ }
+
+ public static Date getExpiryDate(PGPSecretKey key) {
+ return getExpiryDate(key.getPublicKey());
+ }
+
+ public static PGPPublicKey getEncryptPublicKey(long masterKeyId) {
+ PGPPublicKeyRing keyRing = getPublicKeyRing(masterKeyId);
+ if (keyRing == null) {
+ return null;
+ }
+ Vector encryptKeys = getUsableEncryptKeys(keyRing);
+ if (encryptKeys.size() == 0) {
+ return null;
+ }
+ return encryptKeys.get(0);
+ }
+
+ public static PGPSecretKey getSigningKey(long masterKeyId) {
+ PGPSecretKeyRing keyRing = getSecretKeyRing(masterKeyId);
+ if (keyRing == null) {
+ return null;
+ }
+ Vector signingKeys = getUsableSigningKeys(keyRing);
+ if (signingKeys.size() == 0) {
+ return null;
+ }
+ return signingKeys.get(0);
+ }
+
+ @SuppressWarnings("unchecked")
+ public static String getMainUserId(PGPPublicKey key) {
+ for (String userId : new IterableIterator(key.getUserIDs())) {
+ return userId;
+ }
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static String getMainUserId(PGPSecretKey key) {
+ for (String userId : new IterableIterator(key.getUserIDs())) {
+ return userId;
+ }
+ return null;
+ }
+
+ public static String getMainUserIdSafe(Context context, PGPPublicKey key) {
+ String userId = getMainUserId(key);
+ if (userId == null) {
+ userId = context.getResources().getString(R.string.unknownUserId);
+ }
+ return userId;
+ }
+
+ public static String getMainUserIdSafe(Context context, PGPSecretKey key) {
+ String userId = getMainUserId(key);
+ if (userId == null) {
+ userId = context.getResources().getString(R.string.unknownUserId);
+ }
+ return userId;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static boolean isEncryptionKey(PGPPublicKey key) {
+ if (!key.isEncryptionKey()) {
+ return false;
+ }
+
+ if (key.getVersion() <= 3) {
+ // this must be true now
+ return key.isEncryptionKey();
+ }
+
+ // special cases
+ if (key.getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT) {
+ return true;
+ }
+
+ if (key.getAlgorithm() == PGPPublicKey.RSA_ENCRYPT) {
+ return true;
+ }
+
+ for (PGPSignature sig : new IterableIterator(key.getSignatures())) {
+ if (key.isMasterKey() && sig.getKeyID() != key.getKeyID()) {
+ continue;
+ }
+ PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets();
+
+ if (hashed != null
+ && (hashed.getKeyFlags() & (KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE)) != 0) {
+ return true;
+ }
+
+ PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets();
+
+ if (unhashed != null
+ && (unhashed.getKeyFlags() & (KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE)) != 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static boolean isEncryptionKey(PGPSecretKey key) {
+ return isEncryptionKey(key.getPublicKey());
+ }
+
+ @SuppressWarnings("unchecked")
+ public static boolean isSigningKey(PGPPublicKey key) {
+ if (key.getVersion() <= 3) {
+ return true;
+ }
+
+ // special case
+ if (key.getAlgorithm() == PGPPublicKey.RSA_SIGN) {
+ return true;
+ }
+
+ for (PGPSignature sig : new IterableIterator(key.getSignatures())) {
+ if (key.isMasterKey() && sig.getKeyID() != key.getKeyID()) {
+ continue;
+ }
+ PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets();
+
+ if (hashed != null && (hashed.getKeyFlags() & KeyFlags.SIGN_DATA) != 0) {
+ return true;
+ }
+
+ PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets();
+
+ if (unhashed != null && (unhashed.getKeyFlags() & KeyFlags.SIGN_DATA) != 0) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public static boolean isSigningKey(PGPSecretKey key) {
+ return isSigningKey(key.getPublicKey());
+ }
+
+ public static String getAlgorithmInfo(PGPPublicKey key) {
+ return getAlgorithmInfo(key.getAlgorithm(), key.getBitStrength());
+ }
+
+ public static String getAlgorithmInfo(PGPSecretKey key) {
+ return getAlgorithmInfo(key.getPublicKey());
+ }
+
+ public static String getAlgorithmInfo(int algorithm, int keySize) {
+ String algorithmStr = null;
+
+ switch (algorithm) {
+ case PGPPublicKey.RSA_ENCRYPT:
+ case PGPPublicKey.RSA_GENERAL:
+ case PGPPublicKey.RSA_SIGN: {
+ algorithmStr = "RSA";
+ break;
+ }
+
+ case PGPPublicKey.DSA: {
+ algorithmStr = "DSA";
+ break;
+ }
+
+ case PGPPublicKey.ELGAMAL_ENCRYPT:
+ case PGPPublicKey.ELGAMAL_GENERAL: {
+ algorithmStr = "ElGamal";
+ break;
+ }
+
+ default: {
+ algorithmStr = "???";
+ break;
+ }
+ }
+ return algorithmStr + ", " + keySize + "bit";
+ }
+
+ public static String convertToHex(byte[] fp) {
+ String fingerPrint = "";
+ for (int i = 0; i < fp.length; ++i) {
+ if (i != 0 && i % 10 == 0) {
+ fingerPrint += " ";
+ } else if (i != 0 && i % 2 == 0) {
+ fingerPrint += " ";
+ }
+ String chunk = Integer.toHexString((fp[i] + 256) % 256).toUpperCase();
+ while (chunk.length() < 2) {
+ chunk = "0" + chunk;
+ }
+ fingerPrint += chunk;
+ }
+
+ return fingerPrint;
+
+ }
+
+ public static String getFingerPrint(long keyId) {
+ PGPPublicKey key = PGPHelper.getPublicKey(keyId);
+ if (key == null) {
+ PGPSecretKey secretKey = PGPHelper.getSecretKey(keyId);
+ if (secretKey == null) {
+ return "";
+ }
+ key = secretKey.getPublicKey();
+ }
+
+ return convertToHex(key.getFingerprint());
+ }
+
+ public static String getSmallFingerPrint(long keyId) {
+ String fingerPrint = Long.toHexString(keyId & 0xffffffffL).toUpperCase();
+ while (fingerPrint.length() < 8) {
+ fingerPrint = "0" + fingerPrint;
+ }
+ return fingerPrint;
+ }
+
+ public static String keyToHex(long keyId) {
+ return getSmallFingerPrint(keyId >> 32) + getSmallFingerPrint(keyId);
+ }
+
+ public static long keyFromHex(String data) {
+ int len = data.length();
+ String s2 = data.substring(len - 8);
+ String s1 = data.substring(0, len - 8);
+ return (Long.parseLong(s1, 16) << 32) | Long.parseLong(s2, 16);
+ }
+
+ public static void deleteKey(int keyRingId) {
+ mDatabase.deleteKeyRing(keyRingId);
+ }
+
+ public static PGPKeyRing getKeyRing(int keyRingId) {
+ return (PGPKeyRing) mDatabase.getKeyRing(keyRingId);
+ }
+
+ public static PGPSecretKeyRing getSecretKeyRing(long keyId) {
+ byte[] data = mDatabase.getKeyRingDataFromKeyId(Id.database.type_secret, keyId);
+ if (data == null) {
+ return null;
+ }
+ try {
+ return new PGPSecretKeyRing(data);
+ } catch (IOException e) {
+ // no good way to handle this, return null
+ // TODO: some info?
+ } catch (PGPException e) {
+ // no good way to handle this, return null
+ // TODO: some info?
+ }
+ return null;
+ }
+
+ public static PGPPublicKeyRing getPublicKeyRing(long keyId) {
+ byte[] data = mDatabase.getKeyRingDataFromKeyId(Id.database.type_public, keyId);
+ if (data == null) {
+ return null;
+ }
+ try {
+ return new PGPPublicKeyRing(data);
+ } catch (IOException e) {
+ // no good way to handle this, return null
+ // TODO: some info?
+ }
+ return null;
+ }
+
+ public static PGPSecretKey getSecretKey(long keyId) {
+ PGPSecretKeyRing keyRing = getSecretKeyRing(keyId);
+ if (keyRing == null) {
+ return null;
+ }
+ return keyRing.getSecretKey(keyId);
+ }
+
+ public static PGPPublicKey getPublicKey(long keyId) {
+ PGPPublicKeyRing keyRing = getPublicKeyRing(keyId);
+ if (keyRing == null) {
+ return null;
+ }
+
+ return keyRing.getPublicKey(keyId);
+ }
+
+ public static Vector getKeyRingIds(int type) {
+ SQLiteDatabase db = mDatabase.db();
+ Vector keyIds = new Vector();
+ Cursor c = db.query(KeyRings.TABLE_NAME, new String[] { KeyRings._ID }, KeyRings.TYPE
+ + " = ?", new String[] { "" + type }, null, null, null);
+ if (c != null && c.moveToFirst()) {
+ do {
+ keyIds.add(c.getInt(0));
+ } while (c.moveToNext());
+ }
+
+ if (c != null) {
+ c.close();
+ }
+
+ return keyIds;
+ }
+
+ public static String getMainUserId(long keyId, int type) {
+ SQLiteDatabase db = mDatabase.db();
+ Cursor c = db.query(Keys.TABLE_NAME + " INNER JOIN " + KeyRings.TABLE_NAME + " ON ("
+ + KeyRings.TABLE_NAME + "." + KeyRings._ID + " = " + Keys.TABLE_NAME + "."
+ + Keys.KEY_RING_ID + ") " + " INNER JOIN " + Keys.TABLE_NAME + " AS masterKey ON ("
+ + KeyRings.TABLE_NAME + "." + KeyRings._ID + " = " + "masterKey."
+ + Keys.KEY_RING_ID + " AND " + "masterKey." + Keys.IS_MASTER_KEY + " = '1') "
+ + " INNER JOIN " + UserIds.TABLE_NAME + " ON (" + UserIds.TABLE_NAME + "."
+ + UserIds.KEY_ID + " = " + "masterKey." + Keys._ID + " AND " + UserIds.TABLE_NAME
+ + "." + UserIds.RANK + " = '0')", new String[] { UserIds.USER_ID }, Keys.TABLE_NAME
+ + "." + Keys.KEY_ID + " = ? AND " + KeyRings.TABLE_NAME + "." + KeyRings.TYPE
+ + " = ?", new String[] { "" + keyId, "" + type, }, null, null, null);
+ String userId = "";
+ if (c != null && c.moveToFirst()) {
+ do {
+ userId = c.getString(0);
+ } while (c.moveToNext());
+ }
+
+ if (c != null) {
+ c.close();
+ }
+
+ return userId;
+ }
+
+ public static void encrypt(Context context, InputData data, OutputStream outStream,
+ boolean armored, long encryptionKeyIds[], long signatureKeyId,
+ String signaturePassPhrase, ProgressDialogUpdater progress, int symmetricAlgorithm,
+ int hashAlgorithm, int compression, boolean forceV3Signature, String passPhrase)
+ throws IOException, GeneralException, PGPException, NoSuchProviderException,
+ NoSuchAlgorithmException, SignatureException {
+
+ if (encryptionKeyIds == null) {
+ encryptionKeyIds = new long[0];
+ }
+
+ ArmoredOutputStream armorOut = null;
+ OutputStream out = null;
+ OutputStream encryptOut = null;
+ if (armored) {
+ armorOut = new ArmoredOutputStream(outStream);
+ armorOut.setHeader("Version", getFullVersion(context));
+ out = armorOut;
+ } else {
+ out = outStream;
+ }
+ PGPSecretKey signingKey = null;
+ PGPSecretKeyRing signingKeyRing = null;
+ PGPPrivateKey signaturePrivateKey = null;
+
+ if (encryptionKeyIds.length == 0 && passPhrase == null) {
+ throw new GeneralException(
+ context.getString(R.string.error_noEncryptionKeysOrPassPhrase));
+ }
+
+ if (signatureKeyId != Id.key.none) {
+ signingKeyRing = getSecretKeyRing(signatureKeyId);
+ signingKey = getSigningKey(signatureKeyId);
+ if (signingKey == null) {
+ throw new GeneralException(context.getString(R.string.error_signatureFailed));
+ }
+
+ if (signaturePassPhrase == null) {
+ throw new GeneralException(context.getString(R.string.error_noSignaturePassPhrase));
+ }
+ if (progress != null)
+ progress.setProgress(R.string.progress_extractingSignatureKey, 0, 100);
+ PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
+ "SC").build(signaturePassPhrase.toCharArray());
+ signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
+ if (signaturePrivateKey == null) {
+ throw new GeneralException(
+ context.getString(R.string.error_couldNotExtractPrivateKey));
+ }
+ }
+ if (progress != null)
+ progress.setProgress(R.string.progress_preparingStreams, 5, 100);
+
+ // encrypt and compress input file content
+ PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(symmetricAlgorithm, true,
+ new SecureRandom(), new BouncyCastleProvider());
+
+ if (encryptionKeyIds.length == 0) {
+ // symmetric encryption
+ Log.d(Constants.TAG, "encryptionKeyIds length is 0 -> symmetric encryption");
+ cPk.addMethod(passPhrase.toCharArray());
+ }
+ for (int i = 0; i < encryptionKeyIds.length; ++i) {
+ PGPPublicKey key = getEncryptPublicKey(encryptionKeyIds[i]);
+ if (key != null) {
+ cPk.addMethod(key);
+ }
+ }
+ encryptOut = cPk.open(out, new byte[1 << 16]);
+
+ PGPSignatureGenerator signatureGenerator = null;
+ PGPV3SignatureGenerator signatureV3Generator = null;
+
+ if (signatureKeyId != Id.key.none) {
+ if (progress != null)
+ progress.setProgress(R.string.progress_preparingSignature, 10, 100);
+ if (forceV3Signature) {
+ signatureV3Generator = new PGPV3SignatureGenerator(signingKey.getPublicKey()
+ .getAlgorithm(), hashAlgorithm, new BouncyCastleProvider());
+ signatureV3Generator.initSign(PGPSignature.BINARY_DOCUMENT, signaturePrivateKey);
+ } else {
+ signatureGenerator = new PGPSignatureGenerator(signingKey.getPublicKey()
+ .getAlgorithm(), hashAlgorithm, new BouncyCastleProvider());
+ signatureGenerator.initSign(PGPSignature.BINARY_DOCUMENT, signaturePrivateKey);
+
+ String userId = getMainUserId(getMasterKey(signingKeyRing));
+ PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
+ spGen.setSignerUserID(false, userId);
+ signatureGenerator.setHashedSubpackets(spGen.generate());
+ }
+ }
+
+ PGPCompressedDataGenerator compressGen = null;
+ BCPGOutputStream bcpgOut = null;
+ if (compression == Id.choice.compression.none) {
+ bcpgOut = new BCPGOutputStream(encryptOut);
+ } else {
+ compressGen = new PGPCompressedDataGenerator(compression);
+ bcpgOut = new BCPGOutputStream(compressGen.open(encryptOut));
+ }
+ if (signatureKeyId != Id.key.none) {
+ if (forceV3Signature) {
+ signatureV3Generator.generateOnePassVersion(false).encode(bcpgOut);
+ } else {
+ signatureGenerator.generateOnePassVersion(false).encode(bcpgOut);
+ }
+ }
+
+ PGPLiteralDataGenerator literalGen = new PGPLiteralDataGenerator();
+ // file name not needed, so empty string
+ OutputStream pOut = literalGen.open(bcpgOut, PGPLiteralData.BINARY, "", new Date(),
+ new byte[1 << 16]);
+ if (progress != null)
+ progress.setProgress(R.string.progress_encrypting, 20, 100);
+
+ long done = 0;
+ int n = 0;
+ byte[] buffer = new byte[1 << 16];
+ InputStream in = data.getInputStream();
+ while ((n = in.read(buffer)) > 0) {
+ pOut.write(buffer, 0, n);
+ if (signatureKeyId != Id.key.none) {
+ if (forceV3Signature) {
+ signatureV3Generator.update(buffer, 0, n);
+ } else {
+ signatureGenerator.update(buffer, 0, n);
+ }
+ }
+ done += n;
+ if (data.getSize() != 0) {
+ if (progress != null)
+ progress.setProgress((int) (20 + (95 - 20) * done / data.getSize()), 100);
+ }
+ }
+
+ literalGen.close();
+
+ if (signatureKeyId != Id.key.none) {
+ if (progress != null)
+ progress.setProgress(R.string.progress_generatingSignature, 95, 100);
+ if (forceV3Signature) {
+ signatureV3Generator.generate().encode(pOut);
+ } else {
+ signatureGenerator.generate().encode(pOut);
+ }
+ }
+ if (compressGen != null) {
+ compressGen.close();
+ }
+ encryptOut.close();
+ if (armored) {
+ armorOut.close();
+ }
+
+ if (progress != null)
+ progress.setProgress(R.string.progress_done, 100, 100);
+ }
+
+ public static void signText(Context context, InputData data, OutputStream outStream,
+ long signatureKeyId, String signaturePassPhrase, int hashAlgorithm,
+ boolean forceV3Signature, ProgressDialogUpdater progress) throws GeneralException,
+ PGPException, IOException, NoSuchAlgorithmException, SignatureException {
+
+ ArmoredOutputStream armorOut = new ArmoredOutputStream(outStream);
+ armorOut.setHeader("Version", getFullVersion(context));
+
+ PGPSecretKey signingKey = null;
+ PGPSecretKeyRing signingKeyRing = null;
+ PGPPrivateKey signaturePrivateKey = null;
+
+ if (signatureKeyId == 0) {
+ throw new GeneralException(context.getString(R.string.error_noSignatureKey));
+ }
+
+ signingKeyRing = getSecretKeyRing(signatureKeyId);
+ signingKey = getSigningKey(signatureKeyId);
+ if (signingKey == null) {
+ throw new GeneralException(context.getString(R.string.error_signatureFailed));
+ }
+
+ if (signaturePassPhrase == null) {
+ throw new GeneralException(context.getString(R.string.error_noSignaturePassPhrase));
+ }
+ PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
+ .setProvider("SC").build(signaturePassPhrase.toCharArray());
+ signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
+ if (signaturePrivateKey == null) {
+ throw new GeneralException(context.getString(R.string.error_couldNotExtractPrivateKey));
+ }
+ if (progress != null)
+ progress.setProgress(R.string.progress_preparingStreams, 0, 100);
+
+ if (progress != null)
+ progress.setProgress(R.string.progress_preparingSignature, 30, 100);
+
+ PGPSignatureGenerator signatureGenerator = null;
+ PGPV3SignatureGenerator signatureV3Generator = null;
+
+ if (forceV3Signature) {
+ signatureV3Generator = new PGPV3SignatureGenerator(signingKey.getPublicKey()
+ .getAlgorithm(), hashAlgorithm, new BouncyCastleProvider());
+ signatureV3Generator
+ .initSign(PGPSignature.CANONICAL_TEXT_DOCUMENT, signaturePrivateKey);
+ } else {
+ signatureGenerator = new PGPSignatureGenerator(
+ signingKey.getPublicKey().getAlgorithm(), hashAlgorithm,
+ new BouncyCastleProvider());
+ signatureGenerator.initSign(PGPSignature.CANONICAL_TEXT_DOCUMENT, signaturePrivateKey);
+
+ PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
+ String userId = getMainUserId(getMasterKey(signingKeyRing));
+ spGen.setSignerUserID(false, userId);
+ signatureGenerator.setHashedSubpackets(spGen.generate());
+ }
+
+ if (progress != null)
+ progress.setProgress(R.string.progress_signing, 40, 100);
+
+ armorOut.beginClearText(hashAlgorithm);
+
+ InputStream inStream = data.getInputStream();
+ final BufferedReader reader = new BufferedReader(new InputStreamReader(inStream));
+
+ final byte[] newline = "\r\n".getBytes("UTF-8");
+
+ if (forceV3Signature) {
+ processLine(reader.readLine(), armorOut, signatureV3Generator);
+ } else {
+ processLine(reader.readLine(), armorOut, signatureGenerator);
+ }
+
+ while (true) {
+ final String line = reader.readLine();
+
+ if (line == null) {
+ armorOut.write(newline);
+ break;
+ }
+
+ armorOut.write(newline);
+ if (forceV3Signature) {
+ signatureV3Generator.update(newline);
+ processLine(line, armorOut, signatureV3Generator);
+ } else {
+ signatureGenerator.update(newline);
+ processLine(line, armorOut, signatureGenerator);
+ }
+ }
+
+ armorOut.endClearText();
+
+ BCPGOutputStream bOut = new BCPGOutputStream(armorOut);
+ if (forceV3Signature) {
+ signatureV3Generator.generate().encode(bOut);
+ } else {
+ signatureGenerator.generate().encode(bOut);
+ }
+ armorOut.close();
+
+ if (progress != null)
+ progress.setProgress(R.string.progress_done, 100, 100);
+ }
+
+ public static void generateSignature(Context context, InputData data, OutputStream outStream,
+ boolean armored, boolean binary, long signatureKeyId, String signaturePassPhrase,
+ int hashAlgorithm, boolean forceV3Signature, ProgressDialogUpdater progress)
+ throws GeneralException, PGPException, IOException, NoSuchAlgorithmException,
+ SignatureException {
+
+ ArmoredOutputStream armorOut = null;
+ OutputStream out = null;
+ if (armored) {
+ armorOut = new ArmoredOutputStream(outStream);
+ armorOut.setHeader("Version", getFullVersion(context));
+ out = armorOut;
+ } else {
+ out = outStream;
+ }
+
+ PGPSecretKey signingKey = null;
+ PGPSecretKeyRing signingKeyRing = null;
+ PGPPrivateKey signaturePrivateKey = null;
+
+ if (signatureKeyId == 0) {
+ throw new GeneralException(context.getString(R.string.error_noSignatureKey));
+ }
+
+ signingKeyRing = getSecretKeyRing(signatureKeyId);
+ signingKey = getSigningKey(signatureKeyId);
+ if (signingKey == null) {
+ throw new GeneralException(context.getString(R.string.error_signatureFailed));
+ }
+
+ if (signaturePassPhrase == null) {
+ throw new GeneralException(context.getString(R.string.error_noSignaturePassPhrase));
+ }
+ PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
+ .setProvider("SC").build(signaturePassPhrase.toCharArray());
+ signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
+ if (signaturePrivateKey == null) {
+ throw new GeneralException(context.getString(R.string.error_couldNotExtractPrivateKey));
+ }
+ if (progress != null)
+ progress.setProgress(R.string.progress_preparingStreams, 0, 100);
+
+ if (progress != null)
+ progress.setProgress(R.string.progress_preparingSignature, 30, 100);
+
+ PGPSignatureGenerator signatureGenerator = null;
+ PGPV3SignatureGenerator signatureV3Generator = null;
+
+ int type = PGPSignature.CANONICAL_TEXT_DOCUMENT;
+ if (binary) {
+ type = PGPSignature.BINARY_DOCUMENT;
+ }
+
+ if (forceV3Signature) {
+ signatureV3Generator = new PGPV3SignatureGenerator(signingKey.getPublicKey()
+ .getAlgorithm(), hashAlgorithm, new BouncyCastleProvider());
+ signatureV3Generator.initSign(type, signaturePrivateKey);
+ } else {
+ signatureGenerator = new PGPSignatureGenerator(
+ signingKey.getPublicKey().getAlgorithm(), hashAlgorithm,
+ new BouncyCastleProvider());
+ signatureGenerator.initSign(type, signaturePrivateKey);
+
+ PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
+ String userId = getMainUserId(getMasterKey(signingKeyRing));
+ spGen.setSignerUserID(false, userId);
+ signatureGenerator.setHashedSubpackets(spGen.generate());
+ }
+
+ if (progress != null)
+ progress.setProgress(R.string.progress_signing, 40, 100);
+
+ InputStream inStream = data.getInputStream();
+ if (binary) {
+ byte[] buffer = new byte[1 << 16];
+ int n = 0;
+ while ((n = inStream.read(buffer)) > 0) {
+ if (forceV3Signature) {
+ signatureV3Generator.update(buffer, 0, n);
+ } else {
+ signatureGenerator.update(buffer, 0, n);
+ }
+ }
+ } else {
+ final BufferedReader reader = new BufferedReader(new InputStreamReader(inStream));
+ final byte[] newline = "\r\n".getBytes("UTF-8");
+
+ while (true) {
+ final String line = reader.readLine();
+
+ if (line == null) {
+ break;
+ }
+
+ if (forceV3Signature) {
+ processLine(line, null, signatureV3Generator);
+ signatureV3Generator.update(newline);
+ } else {
+ processLine(line, null, signatureGenerator);
+ signatureGenerator.update(newline);
+ }
+ }
+ }
+
+ BCPGOutputStream bOut = new BCPGOutputStream(out);
+ if (forceV3Signature) {
+ signatureV3Generator.generate().encode(bOut);
+ } else {
+ signatureGenerator.generate().encode(bOut);
+ }
+ out.close();
+ outStream.close();
+
+ if (progress != null)
+ progress.setProgress(R.string.progress_done, 100, 100);
+ }
+
+ public static long getDecryptionKeyId(Context context, InputStream inputStream)
+ throws GeneralException, NoAsymmetricEncryptionException, IOException {
+ InputStream in = PGPUtil.getDecoderStream(inputStream);
+ PGPObjectFactory pgpF = new PGPObjectFactory(in);
+ PGPEncryptedDataList enc;
+ Object o = pgpF.nextObject();
+
+ // the first object might be a PGP marker packet.
+ if (o instanceof PGPEncryptedDataList) {
+ enc = (PGPEncryptedDataList) o;
+ } else {
+ enc = (PGPEncryptedDataList) pgpF.nextObject();
+ }
+
+ if (enc == null) {
+ throw new GeneralException(context.getString(R.string.error_invalidData));
+ }
+
+ // TODO: currently we always only look at the first known key
+ // find the secret key
+ PGPSecretKey secretKey = null;
+ Iterator> it = enc.getEncryptedDataObjects();
+ boolean gotAsymmetricEncryption = false;
+ while (it.hasNext()) {
+ Object obj = it.next();
+ if (obj instanceof PGPPublicKeyEncryptedData) {
+ gotAsymmetricEncryption = true;
+ PGPPublicKeyEncryptedData pbe = (PGPPublicKeyEncryptedData) obj;
+ secretKey = getSecretKey(pbe.getKeyID());
+ if (secretKey != null) {
+ break;
+ }
+ }
+ }
+
+ if (!gotAsymmetricEncryption) {
+ throw new NoAsymmetricEncryptionException();
+ }
+
+ if (secretKey == null) {
+ return Id.key.none;
+ }
+
+ return secretKey.getKeyID();
+ }
+
+ public static boolean hasSymmetricEncryption(Context context, InputStream inputStream)
+ throws GeneralException, IOException {
+ InputStream in = PGPUtil.getDecoderStream(inputStream);
+ PGPObjectFactory pgpF = new PGPObjectFactory(in);
+ PGPEncryptedDataList enc;
+ Object o = pgpF.nextObject();
+
+ // the first object might be a PGP marker packet.
+ if (o instanceof PGPEncryptedDataList) {
+ enc = (PGPEncryptedDataList) o;
+ } else {
+ enc = (PGPEncryptedDataList) pgpF.nextObject();
+ }
+
+ if (enc == null) {
+ throw new GeneralException(context.getString(R.string.error_invalidData));
+ }
+
+ Iterator> it = enc.getEncryptedDataObjects();
+ while (it.hasNext()) {
+ Object obj = it.next();
+ if (obj instanceof PGPPBEEncryptedData) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public static Bundle decrypt(Context context, InputData data, OutputStream outStream,
+ String passPhrase, ProgressDialogUpdater progress, boolean assumeSymmetric)
+ throws IOException, GeneralException, PGPException, SignatureException {
+ if (passPhrase == null) {
+ passPhrase = "";
+ }
+ Bundle returnData = new Bundle();
+ InputStream in = PGPUtil.getDecoderStream(data.getInputStream());
+ PGPObjectFactory pgpF = new PGPObjectFactory(in);
+ PGPEncryptedDataList enc;
+ Object o = pgpF.nextObject();
+ long signatureKeyId = 0;
+
+ int currentProgress = 0;
+ if (progress != null)
+ progress.setProgress(R.string.progress_readingData, currentProgress, 100);
+
+ if (o instanceof PGPEncryptedDataList) {
+ enc = (PGPEncryptedDataList) o;
+ } else {
+ enc = (PGPEncryptedDataList) pgpF.nextObject();
+ }
+
+ if (enc == null) {
+ throw new GeneralException(context.getString(R.string.error_invalidData));
+ }
+
+ InputStream clear = null;
+ PGPEncryptedData encryptedData = null;
+
+ currentProgress += 5;
+
+ // TODO: currently we always only look at the first known key or symmetric encryption,
+ // there might be more...
+ if (assumeSymmetric) {
+ PGPPBEEncryptedData pbe = null;
+ Iterator> it = enc.getEncryptedDataObjects();
+ // find secret key
+ while (it.hasNext()) {
+ Object obj = it.next();
+ if (obj instanceof PGPPBEEncryptedData) {
+ pbe = (PGPPBEEncryptedData) obj;
+ break;
+ }
+ }
+
+ if (pbe == null) {
+ throw new GeneralException(
+ context.getString(R.string.error_noSymmetricEncryptionPacket));
+ }
+
+ if (progress != null)
+ progress.setProgress(R.string.progress_preparingStreams, currentProgress, 100);
+ clear = pbe.getDataStream(passPhrase.toCharArray(), new BouncyCastleProvider());
+ encryptedData = pbe;
+ currentProgress += 5;
+ } else {
+ if (progress != null)
+ progress.setProgress(R.string.progress_findingKey, currentProgress, 100);
+ PGPPublicKeyEncryptedData pbe = null;
+ PGPSecretKey secretKey = null;
+ Iterator> it = enc.getEncryptedDataObjects();
+ // find secret key
+ while (it.hasNext()) {
+ Object obj = it.next();
+ if (obj instanceof PGPPublicKeyEncryptedData) {
+ PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj;
+ secretKey = getSecretKey(encData.getKeyID());
+ if (secretKey != null) {
+ pbe = encData;
+ break;
+ }
+ }
+ }
+
+ if (secretKey == null) {
+ throw new GeneralException(context.getString(R.string.error_noSecretKeyFound));
+ }
+
+ currentProgress += 5;
+ if (progress != null)
+ progress.setProgress(R.string.progress_extractingKey, currentProgress, 100);
+ PGPPrivateKey privateKey = null;
+ try {
+ PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
+ .setProvider("SC").build(passPhrase.toCharArray());
+ privateKey = secretKey.extractPrivateKey(keyDecryptor);
+ } catch (PGPException e) {
+ throw new PGPException(context.getString(R.string.error_wrongPassPhrase));
+ }
+ if (privateKey == null) {
+ throw new GeneralException(
+ context.getString(R.string.error_couldNotExtractPrivateKey));
+ }
+ currentProgress += 5;
+ if (progress != null)
+ progress.setProgress(R.string.progress_preparingStreams, currentProgress, 100);
+ clear = pbe.getDataStream(privateKey, new BouncyCastleProvider());
+ encryptedData = pbe;
+ currentProgress += 5;
+ }
+
+ PGPObjectFactory plainFact = new PGPObjectFactory(clear);
+ Object dataChunk = plainFact.nextObject();
+ PGPOnePassSignature signature = null;
+ PGPPublicKey signatureKey = null;
+ int signatureIndex = -1;
+
+ if (dataChunk instanceof PGPCompressedData) {
+ if (progress != null)
+ progress.setProgress(R.string.progress_decompressingData, currentProgress, 100);
+ PGPObjectFactory fact = new PGPObjectFactory(
+ ((PGPCompressedData) dataChunk).getDataStream());
+ dataChunk = fact.nextObject();
+ plainFact = fact;
+ currentProgress += 10;
+ }
+
+ if (dataChunk instanceof PGPOnePassSignatureList) {
+ if (progress != null)
+ progress.setProgress(R.string.progress_processingSignature, currentProgress, 100);
+ returnData.putBoolean(ApgService.EXTRA_SIGNATURE, true);
+ PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) dataChunk;
+ for (int i = 0; i < sigList.size(); ++i) {
+ signature = sigList.get(i);
+ signatureKey = getPublicKey(signature.getKeyID());
+ if (signatureKeyId == 0) {
+ signatureKeyId = signature.getKeyID();
+ }
+ if (signatureKey == null) {
+ signature = null;
+ } else {
+ signatureIndex = i;
+ signatureKeyId = signature.getKeyID();
+ String userId = null;
+ PGPPublicKeyRing sigKeyRing = getPublicKeyRing(signatureKeyId);
+ if (sigKeyRing != null) {
+ userId = getMainUserId(getMasterKey(sigKeyRing));
+ }
+ returnData.putString(ApgService.EXTRA_SIGNATURE_USER_ID, userId);
+ break;
+ }
+ }
+
+ returnData.putLong(ApgService.EXTRA_SIGNATURE_KEY_ID, signatureKeyId);
+
+ if (signature != null) {
+ signature.initVerify(signatureKey, new BouncyCastleProvider());
+ } else {
+ returnData.putBoolean(ApgService.EXTRA_SIGNATURE_UNKNOWN, true);
+ }
+
+ dataChunk = plainFact.nextObject();
+ currentProgress += 10;
+ }
+
+ if (dataChunk instanceof PGPSignatureList) {
+ dataChunk = plainFact.nextObject();
+ }
+
+ if (dataChunk instanceof PGPLiteralData) {
+ if (progress != null)
+ progress.setProgress(R.string.progress_decrypting, currentProgress, 100);
+ PGPLiteralData literalData = (PGPLiteralData) dataChunk;
+ OutputStream out = outStream;
+
+ byte[] buffer = new byte[1 << 16];
+ InputStream dataIn = literalData.getInputStream();
+
+ int startProgress = currentProgress;
+ int endProgress = 100;
+ if (signature != null) {
+ endProgress = 90;
+ } else if (encryptedData.isIntegrityProtected()) {
+ endProgress = 95;
+ }
+ int n = 0;
+ int done = 0;
+ long startPos = data.getStreamPosition();
+ while ((n = dataIn.read(buffer)) > 0) {
+ out.write(buffer, 0, n);
+ done += n;
+ if (signature != null) {
+ try {
+ signature.update(buffer, 0, n);
+ } catch (SignatureException e) {
+ returnData.putBoolean(ApgService.EXTRA_SIGNATURE_SUCCESS, false);
+ signature = null;
+ }
+ }
+ // unknown size, but try to at least have a moving, slowing down progress bar
+ currentProgress = startProgress + (endProgress - startProgress) * done
+ / (done + 100000);
+ if (data.getSize() - startPos == 0) {
+ currentProgress = endProgress;
+ } else {
+ currentProgress = (int) (startProgress + (endProgress - startProgress)
+ * (data.getStreamPosition() - startPos) / (data.getSize() - startPos));
+ }
+ if (progress != null)
+ progress.setProgress(currentProgress, 100);
+ }
+
+ if (signature != null) {
+ if (progress != null)
+ progress.setProgress(R.string.progress_verifyingSignature, 90, 100);
+ PGPSignatureList signatureList = (PGPSignatureList) plainFact.nextObject();
+ PGPSignature messageSignature = signatureList.get(signatureIndex);
+ if (signature.verify(messageSignature)) {
+ returnData.putBoolean(ApgService.EXTRA_SIGNATURE_SUCCESS, true);
+ } else {
+ returnData.putBoolean(ApgService.EXTRA_SIGNATURE_SUCCESS, false);
+ }
+ }
+ }
+
+ // TODO: add integrity somewhere
+ if (encryptedData.isIntegrityProtected()) {
+ if (progress != null)
+ progress.setProgress(R.string.progress_verifyingIntegrity, 95, 100);
+ if (encryptedData.verify()) {
+ // passed
+ } else {
+ // failed
+ }
+ } else {
+ // no integrity check
+ }
+
+ if (progress != null)
+ progress.setProgress(R.string.progress_done, 100, 100);
+ return returnData;
+ }
+
+ public static Bundle verifyText(Context context, InputData data, OutputStream outStream,
+ ProgressDialogUpdater progress) throws IOException, GeneralException, PGPException,
+ SignatureException {
+ Bundle returnData = new Bundle();
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ArmoredInputStream aIn = new ArmoredInputStream(data.getInputStream());
+
+ if (progress != null)
+ progress.setProgress(R.string.progress_done, 0, 100);
+
+ // mostly taken from ClearSignedFileProcessor
+ ByteArrayOutputStream lineOut = new ByteArrayOutputStream();
+ int lookAhead = readInputLine(lineOut, aIn);
+ byte[] lineSep = getLineSeparator();
+
+ byte[] line = lineOut.toByteArray();
+ out.write(line, 0, getLengthWithoutSeparator(line));
+ out.write(lineSep);
+
+ while (lookAhead != -1 && aIn.isClearText()) {
+ lookAhead = readInputLine(lineOut, lookAhead, aIn);
+ line = lineOut.toByteArray();
+ out.write(line, 0, getLengthWithoutSeparator(line));
+ out.write(lineSep);
+ }
+
+ out.close();
+
+ byte[] clearText = out.toByteArray();
+ outStream.write(clearText);
+
+ returnData.putBoolean(ApgService.EXTRA_SIGNATURE, true);
+
+ if (progress != null)
+ progress.setProgress(R.string.progress_processingSignature, 60, 100);
+ PGPObjectFactory pgpFact = new PGPObjectFactory(aIn);
+
+ PGPSignatureList sigList = (PGPSignatureList) pgpFact.nextObject();
+ if (sigList == null) {
+ throw new GeneralException(context.getString(R.string.error_corruptData));
+ }
+ PGPSignature signature = null;
+ long signatureKeyId = 0;
+ PGPPublicKey signatureKey = null;
+ for (int i = 0; i < sigList.size(); ++i) {
+ signature = sigList.get(i);
+ signatureKey = getPublicKey(signature.getKeyID());
+ if (signatureKeyId == 0) {
+ signatureKeyId = signature.getKeyID();
+ }
+ if (signatureKey == null) {
+ // TODO: reimplement!
+ // Bundle pauseData = new Bundle();
+ // pauseData.putInt(Constants.extras.STATUS, Id.message.unknown_signature_key);
+ // pauseData.putLong(Constants.extras.KEY_ID, signatureKeyId);
+ // Message msg = new Message();
+ // msg.setData(pauseData);
+ // context.sendMessage(msg);
+ // // pause here
+ // context.getRunningThread().pause();
+ // // see whether the key was found in the meantime
+ // signatureKey = getPublicKey(signature.getKeyID());
+ }
+
+ if (signatureKey == null) {
+ signature = null;
+ } else {
+ signatureKeyId = signature.getKeyID();
+ String userId = null;
+ PGPPublicKeyRing sigKeyRing = getPublicKeyRing(signatureKeyId);
+ if (sigKeyRing != null) {
+ userId = getMainUserId(getMasterKey(sigKeyRing));
+ }
+ returnData.putString(ApgService.EXTRA_SIGNATURE_USER_ID, userId);
+ break;
+ }
+ }
+
+ returnData.putLong(ApgService.EXTRA_SIGNATURE_KEY_ID, signatureKeyId);
+
+ if (signature == null) {
+ returnData.putBoolean(ApgService.EXTRA_SIGNATURE_UNKNOWN, true);
+ if (progress != null)
+ progress.setProgress(R.string.progress_done, 100, 100);
+ return returnData;
+ }
+
+ signature.initVerify(signatureKey, new BouncyCastleProvider());
+
+ InputStream sigIn = new BufferedInputStream(new ByteArrayInputStream(clearText));
+
+ lookAhead = readInputLine(lineOut, sigIn);
+
+ processLine(signature, lineOut.toByteArray());
+
+ if (lookAhead != -1) {
+ do {
+ lookAhead = readInputLine(lineOut, lookAhead, sigIn);
+
+ signature.update((byte) '\r');
+ signature.update((byte) '\n');
+
+ processLine(signature, lineOut.toByteArray());
+ } while (lookAhead != -1);
+ }
+
+ returnData.putBoolean(ApgService.EXTRA_SIGNATURE_SUCCESS, signature.verify());
+
+ if (progress != null)
+ progress.setProgress(R.string.progress_done, 100, 100);
+ return returnData;
+ }
+
+ public static int getStreamContent(Context context, InputStream inStream) throws IOException {
+ InputStream in = PGPUtil.getDecoderStream(inStream);
+ PGPObjectFactory pgpF = new PGPObjectFactory(in);
+ Object object = pgpF.nextObject();
+ while (object != null) {
+ if (object instanceof PGPPublicKeyRing || object instanceof PGPSecretKeyRing) {
+ return Id.content.keys;
+ } else if (object instanceof PGPEncryptedDataList) {
+ return Id.content.encrypted_data;
+ }
+ object = pgpF.nextObject();
+ }
+
+ return Id.content.unknown;
+ }
+
+ private static void processLine(final String pLine, final ArmoredOutputStream pArmoredOutput,
+ final PGPSignatureGenerator pSignatureGenerator) throws IOException, SignatureException {
+
+ if (pLine == null) {
+ return;
+ }
+
+ final char[] chars = pLine.toCharArray();
+ int len = chars.length;
+
+ while (len > 0) {
+ if (!Character.isWhitespace(chars[len - 1])) {
+ break;
+ }
+ len--;
+ }
+
+ final byte[] data = pLine.substring(0, len).getBytes("UTF-8");
+
+ if (pArmoredOutput != null) {
+ pArmoredOutput.write(data);
+ }
+ pSignatureGenerator.update(data);
+ }
+
+ private static void processLine(final String pLine, final ArmoredOutputStream pArmoredOutput,
+ final PGPV3SignatureGenerator pSignatureGenerator) throws IOException,
+ SignatureException {
+
+ if (pLine == null) {
+ return;
+ }
+
+ final char[] chars = pLine.toCharArray();
+ int len = chars.length;
+
+ while (len > 0) {
+ if (!Character.isWhitespace(chars[len - 1])) {
+ break;
+ }
+ len--;
+ }
+
+ final byte[] data = pLine.substring(0, len).getBytes("UTF-8");
+
+ if (pArmoredOutput != null) {
+ pArmoredOutput.write(data);
+ }
+ pSignatureGenerator.update(data);
+ }
+
+ // taken from ClearSignedFileProcessor in BC
+ private static void processLine(PGPSignature sig, byte[] line) throws SignatureException,
+ IOException {
+ int length = getLengthWithoutWhiteSpace(line);
+ if (length > 0) {
+ sig.update(line, 0, length);
+ }
+ }
+
+ private static int readInputLine(ByteArrayOutputStream bOut, InputStream fIn)
+ throws IOException {
+ bOut.reset();
+
+ int lookAhead = -1;
+ int ch;
+
+ while ((ch = fIn.read()) >= 0) {
+ bOut.write(ch);
+ if (ch == '\r' || ch == '\n') {
+ lookAhead = readPassedEOL(bOut, ch, fIn);
+ break;
+ }
+ }
+
+ return lookAhead;
+ }
+
+ private static int readInputLine(ByteArrayOutputStream bOut, int lookAhead, InputStream fIn)
+ throws IOException {
+ bOut.reset();
+
+ int ch = lookAhead;
+
+ do {
+ bOut.write(ch);
+ if (ch == '\r' || ch == '\n') {
+ lookAhead = readPassedEOL(bOut, ch, fIn);
+ break;
+ }
+ } while ((ch = fIn.read()) >= 0);
+
+ if (ch < 0) {
+ lookAhead = -1;
+ }
+
+ return lookAhead;
+ }
+
+ private static int readPassedEOL(ByteArrayOutputStream bOut, int lastCh, InputStream fIn)
+ throws IOException {
+ int lookAhead = fIn.read();
+
+ if (lastCh == '\r' && lookAhead == '\n') {
+ bOut.write(lookAhead);
+ lookAhead = fIn.read();
+ }
+
+ return lookAhead;
+ }
+
+ private static int getLengthWithoutSeparator(byte[] line) {
+ int end = line.length - 1;
+
+ while (end >= 0 && isLineEnding(line[end])) {
+ end--;
+ }
+
+ return end + 1;
+ }
+
+ private static boolean isLineEnding(byte b) {
+ return b == '\r' || b == '\n';
+ }
+
+ private static int getLengthWithoutWhiteSpace(byte[] line) {
+ int end = line.length - 1;
+
+ while (end >= 0 && isWhiteSpace(line[end])) {
+ end--;
+ }
+
+ return end + 1;
+ }
+
+ private static boolean isWhiteSpace(byte b) {
+ return b == '\r' || b == '\n' || b == '\t' || b == ' ';
+ }
+
+ private static byte[] getLineSeparator() {
+ String nl = System.getProperty("line.separator");
+ byte[] nlBytes = new byte[nl.length()];
+
+ for (int i = 0; i != nlBytes.length; i++) {
+ nlBytes[i] = (byte) nl.charAt(i);
+ }
+
+ return nlBytes;
+ }
+
+ public static boolean isReleaseVersion(Context context) {
+ try {
+ PackageInfo pi = context.getPackageManager().getPackageInfo(PACKAGE_NAME, 0);
+ if (pi.versionCode % 100 == 99) {
+ return true;
+ } else {
+ return false;
+ }
+ } catch (NameNotFoundException e) {
+ // impossible!
+ return false;
+ }
+ }
+
+ public static String getVersion(Context context) {
+ if (VERSION != null) {
+ return VERSION;
+ }
+ try {
+ PackageInfo pi = context.getPackageManager().getPackageInfo(PACKAGE_NAME, 0);
+ VERSION = pi.versionName;
+ return VERSION;
+ } catch (NameNotFoundException e) {
+ // impossible!
+ return "0.0.0";
+ }
+ }
+
+ public static String getFullVersion(Context context) {
+ return "APG v" + getVersion(context);
+ }
+
+ public static String generateRandomString(int length) {
+ SecureRandom random = new SecureRandom();
+ /*
+ * try { random = SecureRandom.getInstance("SHA1PRNG", new BouncyCastleProvider()); } catch
+ * (NoSuchAlgorithmException e) { // TODO: need to handle this case somehow return null; }
+ */
+ byte bytes[] = new byte[length];
+ random.nextBytes(bytes);
+ String result = "";
+ for (int i = 0; i < length; ++i) {
+ int v = (bytes[i] + 256) % 64;
+ if (v < 10) {
+ result += (char) ('0' + v);
+ } else if (v < 36) {
+ result += (char) ('A' + v - 10);
+ } else if (v < 62) {
+ result += (char) ('a' + v - 36);
+ } else if (v == 62) {
+ result += '_';
+ } else if (v == 63) {
+ result += '.';
+ }
+ }
+ return result;
+ }
+
+ public static long getLengthOfStream(InputStream in) throws IOException {
+ long size = 0;
+ long n = 0;
+ byte dummy[] = new byte[0x10000];
+ while ((n = in.read(dummy)) > 0) {
+ size += n;
+ }
+ return size;
+ }
+
+ public static void deleteFileSecurely(Context context, File file, ProgressDialogUpdater progress)
+ throws FileNotFoundException, IOException {
+ long length = file.length();
+ SecureRandom random = new SecureRandom();
+ RandomAccessFile raf = new RandomAccessFile(file, "rws");
+ raf.seek(0);
+ raf.getFilePointer();
+ byte[] data = new byte[1 << 16];
+ int pos = 0;
+ String msg = context.getString(R.string.progress_deletingSecurely, file.getName());
+ while (pos < length) {
+ if (progress != null)
+ progress.setProgress(msg, (int) (100 * pos / length), 100);
+ random.nextBytes(data);
+ raf.write(data);
+ pos += data.length;
+ }
+ raf.close();
+ file.delete();
+ }
+}
diff --git a/org_apg/src/org/thialfihar/android/apg/passphrase/AskForPassphrase.java b/org_apg/src/org/thialfihar/android/apg/passphrase/AskForPassphrase.java
index 27cb0a41e..5711a16a8 100644
--- a/org_apg/src/org/thialfihar/android/apg/passphrase/AskForPassphrase.java
+++ b/org_apg/src/org/thialfihar/android/apg/passphrase/AskForPassphrase.java
@@ -20,9 +20,9 @@ import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPPrivateKey;
import org.spongycastle.openpgp.PGPSecretKey;
-import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Id;
import org.thialfihar.android.apg.R;
+import org.thialfihar.android.apg.helper.PGPHelper;
import android.app.Activity;
import android.app.AlertDialog;
@@ -55,7 +55,7 @@ public class AskForPassphrase {
secretKey = null;
alert.setMessage(context.getString(R.string.passPhraseForSymmetricEncryption));
} else {
- secretKey = Apg.getMasterKey(Apg.getSecretKeyRing(secretKeyId));
+ secretKey = PGPHelper.getMasterKey(PGPHelper.getSecretKeyRing(secretKeyId));
if (secretKey == null) {
alert.setTitle(R.string.title_keyNotFound);
alert.setMessage(context.getString(R.string.keyNotFound, secretKeyId));
@@ -67,7 +67,7 @@ public class AskForPassphrase {
alert.setCancelable(false);
return alert.create();
}
- String userId = Apg.getMainUserIdSafe(context, secretKey);
+ String userId = PGPHelper.getMainUserIdSafe(context, secretKey);
alert.setMessage(context.getString(R.string.passPhraseFor, userId));
}
@@ -111,7 +111,7 @@ public class AskForPassphrase {
}
// cache again
- Apg.setCachedPassPhrase(keyId, passPhrase);
+ PGPHelper.setCachedPassPhrase(keyId, passPhrase);
// return by callback
cb.passPhraseCallback(keyId, passPhrase);
}
@@ -133,7 +133,7 @@ public class AskForPassphrase {
Log.d("APG", "Key has no passphrase!");
// cache null
- Apg.setCachedPassPhrase(secretKey.getKeyID(), null);
+ PGPHelper.setCachedPassPhrase(secretKey.getKeyID(), null);
// return by callback
cb.passPhraseCallback(secretKey.getKeyID(), null);
diff --git a/org_apg/src/org/thialfihar/android/apg/passphrase/PassphraseCacheService.java b/org_apg/src/org/thialfihar/android/apg/passphrase/PassphraseCacheService.java
index 9ef6eedb8..d38d0391f 100644
--- a/org_apg/src/org/thialfihar/android/apg/passphrase/PassphraseCacheService.java
+++ b/org_apg/src/org/thialfihar/android/apg/passphrase/PassphraseCacheService.java
@@ -14,8 +14,8 @@
package org.thialfihar.android.apg.passphrase;
-import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Preferences;
+import org.thialfihar.android.apg.helper.PGPHelper;
import android.app.Service;
import android.content.Context;
@@ -47,7 +47,7 @@ public class PassphraseCacheService extends Service {
delay = 60000;
}
- delay = Apg.cleanUpCache(mPassPhraseCacheTtl, delay);
+ delay = PGPHelper.cleanUpCache(mPassPhraseCacheTtl, delay);
// don't check too often, even if we were close
if (delay < 5000) {
delay = 5000;
diff --git a/org_apg/src/org/thialfihar/android/apg/provider/Database.java b/org_apg/src/org/thialfihar/android/apg/provider/Database.java
index 8040eb56c..40e2b9203 100644
--- a/org_apg/src/org/thialfihar/android/apg/provider/Database.java
+++ b/org_apg/src/org/thialfihar/android/apg/provider/Database.java
@@ -19,8 +19,8 @@ import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPPublicKeyRing;
import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing;
-import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Id;
+import org.thialfihar.android.apg.helper.PGPHelper;
import org.thialfihar.android.apg.util.IterableIterator;
import android.content.ContentValues;
@@ -318,11 +318,11 @@ public class Database extends SQLiteOpenHelper {
values.put(Keys.IS_MASTER_KEY, key.isMasterKey());
values.put(Keys.ALGORITHM, key.getAlgorithm());
values.put(Keys.KEY_SIZE, key.getBitStrength());
- values.put(Keys.CAN_SIGN, Apg.isSigningKey(key));
- values.put(Keys.CAN_ENCRYPT, Apg.isEncryptionKey(key));
+ values.put(Keys.CAN_SIGN, PGPHelper.isSigningKey(key));
+ values.put(Keys.CAN_ENCRYPT, PGPHelper.isEncryptionKey(key));
values.put(Keys.IS_REVOKED, key.isRevoked());
- values.put(Keys.CREATION, Apg.getCreationDate(key).getTime() / 1000);
- Date expiryDate = Apg.getExpiryDate(key);
+ values.put(Keys.CREATION, PGPHelper.getCreationDate(key).getTime() / 1000);
+ Date expiryDate = PGPHelper.getExpiryDate(key);
if (expiryDate != null) {
values.put(Keys.EXPIRY, expiryDate.getTime() / 1000);
}
@@ -367,11 +367,11 @@ public class Database extends SQLiteOpenHelper {
values.put(Keys.IS_MASTER_KEY, key.isMasterKey());
values.put(Keys.ALGORITHM, key.getPublicKey().getAlgorithm());
values.put(Keys.KEY_SIZE, key.getPublicKey().getBitStrength());
- values.put(Keys.CAN_SIGN, Apg.isSigningKey(key));
- values.put(Keys.CAN_ENCRYPT, Apg.isEncryptionKey(key));
+ values.put(Keys.CAN_SIGN, PGPHelper.isSigningKey(key));
+ values.put(Keys.CAN_ENCRYPT, PGPHelper.isEncryptionKey(key));
values.put(Keys.IS_REVOKED, key.getPublicKey().isRevoked());
- values.put(Keys.CREATION, Apg.getCreationDate(key).getTime() / 1000);
- Date expiryDate = Apg.getExpiryDate(key);
+ values.put(Keys.CREATION, PGPHelper.getCreationDate(key).getTime() / 1000);
+ Date expiryDate = PGPHelper.getExpiryDate(key);
if (expiryDate != null) {
values.put(Keys.EXPIRY, expiryDate.getTime() / 1000);
}
diff --git a/org_apg/src/org/thialfihar/android/apg/provider/blob/ApgServiceBlobDatabase.java b/org_apg/src/org/thialfihar/android/apg/provider/blob/ApgServiceBlobDatabase.java
deleted file mode 100644
index 5122f9da1..000000000
--- a/org_apg/src/org/thialfihar/android/apg/provider/blob/ApgServiceBlobDatabase.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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.thialfihar.android.apg.provider.blob;
-
-import org.thialfihar.android.apg.service.ApgService2;
-
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
-import android.net.Uri;
-import android.util.Log;
-
-public class ApgServiceBlobDatabase extends SQLiteOpenHelper {
-
- private static final String TAG = "ApgServiceBlobDatabase";
-
- private static final int VERSION = 1;
- private static final String NAME = "apg_service_blob_data";
- private static final String TABLE = "data";
-
- public ApgServiceBlobDatabase(Context context) {
- super(context, NAME, null, VERSION);
- if (ApgService2.LOCAL_LOGD)
- Log.d(TAG, "constructor called");
- }
-
- @Override
- public void onCreate(SQLiteDatabase db) {
- if (ApgService2.LOCAL_LOGD)
- Log.d(TAG, "onCreate() called");
- db.execSQL("create table " + TABLE + " ( _id integer primary key autoincrement,"
- + "key text not null)");
- }
-
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- if (ApgService2.LOCAL_LOGD)
- Log.d(TAG, "onUpgrade() called");
- // no upgrade necessary yet
- }
-
- public Uri insert(ContentValues vals) {
- if (ApgService2.LOCAL_LOGD)
- Log.d(TAG, "insert() called");
- SQLiteDatabase db = this.getWritableDatabase();
- long newId = db.insert(TABLE, null, vals);
- return ContentUris.withAppendedId(ApgServiceBlobProvider.CONTENT_URI, newId);
- }
-
- public Cursor query(String id, String key) {
- if (ApgService2.LOCAL_LOGD)
- Log.d(TAG, "query() called");
- SQLiteDatabase db = this.getReadableDatabase();
- return db.query(TABLE, new String[] { "_id" }, "_id = ? and key = ?", new String[] { id,
- key }, null, null, null);
- }
-}
diff --git a/org_apg/src/org/thialfihar/android/apg/provider/blob/ApgServiceBlobProvider.java b/org_apg/src/org/thialfihar/android/apg/provider/blob/ApgServiceBlobProvider.java
deleted file mode 100644
index b16bc398e..000000000
--- a/org_apg/src/org/thialfihar/android/apg/provider/blob/ApgServiceBlobProvider.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * 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.thialfihar.android.apg.provider.blob;
-
-import org.thialfihar.android.apg.Constants;
-import org.thialfihar.android.apg.service.ApgService2;
-
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.ParcelFileDescriptor;
-import android.util.Log;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.List;
-import java.util.UUID;
-
-public class ApgServiceBlobProvider extends ContentProvider {
-
- private static final String TAG = "ApgServiceBlobProvider";
-
- public static final Uri CONTENT_URI = Uri.parse("content://org.thialfihar.android.apg.provider.apgserviceblobprovider");
-
- private static final String COLUMN_KEY = "key";
-
- private static final String STORE_PATH = Constants.path.APP_DIR+"/ApgServiceBlobs";
-
- private ApgServiceBlobDatabase mDb = null;
-
- public ApgServiceBlobProvider() {
- if(ApgService2.LOCAL_LOGD) Log.d(TAG, "Constructor called");
- File dir = new File(STORE_PATH);
- dir.mkdirs();
- if(ApgService2.LOCAL_LOGD) Log.d(TAG, "Constructor finished");
- }
-
- @Override
- public int delete(Uri arg0, String arg1, String[] arg2) {
- if(ApgService2.LOCAL_LOGD) Log.d(TAG, "delete() called");
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public String getType(Uri arg0) {
- if(ApgService2.LOCAL_LOGD) Log.d(TAG, "getType() called");
- // not needed for now
- return null;
- }
-
- @Override
- public Uri insert(Uri uri, ContentValues ignored) {
- if(ApgService2.LOCAL_LOGD) Log.d(TAG, "insert() called");
- // ContentValues are actually ignored, because we want to store a blob with no more information
- // but have to create an record with the password generated here first
-
- ContentValues vals = new ContentValues();
-
- // Insert a random key in the database. This has to provided by the caller when updating or
- // getting the blob
- String password = UUID.randomUUID().toString();
- vals.put(COLUMN_KEY, password);
-
- Uri insertedUri = mDb.insert(vals);
- return Uri.withAppendedPath(insertedUri, password);
- }
-
- @Override
- public boolean onCreate() {
- if(ApgService2.LOCAL_LOGD) Log.d(TAG, "onCreate() called");
- mDb = new ApgServiceBlobDatabase(getContext());
- // TODO Auto-generated method stub
- return true;
- }
-
- @Override
- public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3, String arg4) {
- if(ApgService2.LOCAL_LOGD) Log.d(TAG, "query() called");
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) {
- if(ApgService2.LOCAL_LOGD) Log.d(TAG, "update() called");
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public ParcelFileDescriptor openFile(Uri uri, String mode) throws SecurityException, FileNotFoundException {
- if(ApgService2.LOCAL_LOGD) Log.d(TAG, "openFile() called");
- if(ApgService2.LOCAL_LOGD) Log.d(TAG, "... with uri: "+uri.toString());
- if(ApgService2.LOCAL_LOGD) Log.d(TAG, "... with mode: "+mode);
-
- List segments = uri.getPathSegments();
- if(segments.size() < 2) {
- throw new SecurityException("Password not found in URI");
- }
- String id = segments.get(0);
- String key = segments.get(1);
-
- if(ApgService2.LOCAL_LOGD) Log.d(TAG, "... got id: "+id);
- if(ApgService2.LOCAL_LOGD) Log.d(TAG, "... and key: "+key);
-
- // get the data
- Cursor result = mDb.query(id, key);
-
- if(result.getCount() == 0) {
- // either the key is wrong or no id exists
- throw new FileNotFoundException("No file found with that ID and/or password");
- }
-
- File targetFile = new File(STORE_PATH, id);
- if(mode.equals("w")) {
- if(ApgService2.LOCAL_LOGD) Log.d(TAG, "... will try to open file w");
- if( !targetFile.exists() ) {
- try {
- targetFile.createNewFile();
- } catch (IOException e) {
- Log.e(TAG, "... got IEOException on creating new file", e);
- throw new FileNotFoundException("Could not create file to write to");
- }
- }
- return ParcelFileDescriptor.open(targetFile, ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE );
- } else if(mode.equals("r")) {
- if(ApgService2.LOCAL_LOGD) Log.d(TAG, "... will try to open file r");
- if( !targetFile.exists() ) {
- throw new FileNotFoundException("Error: Could not find the file requested");
- }
- return ParcelFileDescriptor.open(targetFile, ParcelFileDescriptor.MODE_READ_ONLY);
- }
-
- return null;
- }
-
-}
diff --git a/org_apg/src/org/thialfihar/android/apg/provider/blob/BlobContract.java b/org_apg/src/org/thialfihar/android/apg/provider/blob/BlobContract.java
deleted file mode 100644
index dd9bd2069..000000000
--- a/org_apg/src/org/thialfihar/android/apg/provider/blob/BlobContract.java
+++ /dev/null
@@ -1,42 +0,0 @@
-//package org.thialfihar.android.apg.provider.blob;
-//
-//import android.net.Uri;
-//import android.provider.BaseColumns;
-//
-//public class BlobContract {
-//
-// interface BlobColumns {
-// String DATA = "data";
-// }
-//
-// public static final String CONTENT_AUTHORITY = "org.thialfihar.android.apg";
-//
-// private static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY);
-//
-// public static final String PATH_BLOB = "blob";
-//
-// public static class Blobs implements BlobColumns, BaseColumns {
-// public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon().appendPath(PATH_BLOB)
-// .build();
-//
-// /** Use if multiple items get returned */
-// public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.apg.blob";
-//
-// /** Use if a single item is returned */
-// public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.apg.blob";
-//
-// /** Default "ORDER BY" clause. */
-// public static final String DEFAULT_SORT = BaseColumns._ID + " ASC";
-//
-// public static Uri buildUri(String id) {
-// return CONTENT_URI.buildUpon().appendPath(id).build();
-// }
-//
-// public static String getId(Uri uri) {
-// return uri.getLastPathSegment();
-// }
-// }
-//
-// private BlobContract() {
-// }
-//}
diff --git a/org_apg/src/org/thialfihar/android/apg/service/ApgService.java b/org_apg/src/org/thialfihar/android/apg/service/ApgService.java
index 6123beee8..ca9d7a817 100644
--- a/org_apg/src/org/thialfihar/android/apg/service/ApgService.java
+++ b/org_apg/src/org/thialfihar/android/apg/service/ApgService.java
@@ -28,23 +28,23 @@ import java.util.ArrayList;
import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing;
-import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Constants;
import org.thialfihar.android.apg.Id;
-import org.thialfihar.android.apg.InputData;
import org.thialfihar.android.apg.Preferences;
import org.thialfihar.android.apg.ProgressDialogUpdater;
import org.thialfihar.android.apg.R;
-import org.thialfihar.android.apg.Apg.GeneralException;
+import org.thialfihar.android.apg.helper.FileHelper;
+import org.thialfihar.android.apg.helper.PGPHelper;
+import org.thialfihar.android.apg.helper.PGPHelper.GeneralException;
+import org.thialfihar.android.apg.helper.PGPConversionHelper;
import org.thialfihar.android.apg.provider.DataProvider;
-import org.thialfihar.android.apg.util.Utils;
+import org.thialfihar.android.apg.util.InputData;
import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
-import android.os.Environment;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
@@ -55,7 +55,16 @@ import android.util.Log;
* data from the activities or other apps, queues these intents, executes them, and stops itself
* after doing them.
*/
-// TODO: ProgressDialogUpdater rework???
+
+/**
+ * TODO:
+ *
+ * - ProgressDialogUpdater rework???
+ *
+ * - put recurring things into private functions when possible
+ *
+ *
+ */
public class ApgService extends IntentService implements ProgressDialogUpdater {
// extras that can be given by intent
@@ -64,6 +73,26 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
public static final String EXTRA_DATA = "data";
// keys for data bundle
+
+ // encrypt
+ public static final String SECRET_KEY_ID = "secret_key_id";
+ public static final String USE_ASCII_AMOR = "use_ascii_amor";
+ public static final String ENCRYPTION_KEYS_IDS = "encryption_keys_ids";
+ public static final String SIGNATURE_KEY_ID = "signature_key_id";
+ public static final String COMPRESSION_ID = "compression_id";
+ public static final String GENERATE_SIGNATURE = "generate_signature";
+ public static final String SIGN_ONLY = "sign_only";
+ public static final String MESSAGE_BYTES = "message_bytes";
+ public static final String INPUT_FILE = "input_file";
+ public static final String OUTPUT_FILE = "output_file";
+ public static final String PROVIDER_URI = "provider_uri";
+
+ // decrypt
+ public static final String SIGNED_ONLY = "signed_only";
+ public static final String RETURN_BYTES = "return_binary";
+ public static final String CIPHERTEXT_BYTES = "ciphertext_bytes";
+ public static final String ASSUME_SYMMETRIC = "assume_symmetric";
+
// edit keys
public static final String NEW_PASSPHRASE = "new_passphrase";
public static final String CURRENT_PASSPHRASE = "current_passphrase";
@@ -78,41 +107,44 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
public static final String SYMMETRIC_PASSPHRASE = "passphrase";
public static final String MASTER_KEY = "master_key";
- // encrypt
- public static final String SECRET_KEY_ID = "secret_key_id";
- public static final String USE_ASCII_AMOR = "use_ascii_amor";
- public static final String ENCRYPTION_KEYS_IDS = "encryption_keys_ids";
- public static final String SIGNATURE_KEY_ID = "signature_key_id";
- public static final String COMPRESSION_ID = "compression_id";
- public static final String GENERATE_SIGNATURE = "generate_signature";
- public static final String SIGN_ONLY = "sign_only";
- public static final String BYTES = "bytes";
- public static final String INPUT_FILE = "input_file";
- public static final String OUTPUT_FILE = "output_file";
- public static final String PROVIDER_URI = "provider_uri";
-
// delete file securely
public static final String DELETE_FILE = "delete_file";
- // possible ints for EXTRA_ACTION
- public static final int ACTION_SAVE_KEYRING = 1;
- public static final int ACTION_GENERATE_KEY = 2;
- public static final int ACTION_GENERATE_DEFAULT_RSA_KEYS = 3;
+ // possible EXTRA_ACTIONs
+ public static final int ACTION_ENCRYPT_SIGN_BYTES = 10;
+ public static final int ACTION_ENCRYPT_SIGN_FILE = 11;
+ public static final int ACTION_ENCRYPT_SIGN_STREAM = 12;
- public static final int ACTION_ENCRYPT_SIGN_BYTES = 4;
- public static final int ACTION_ENCRYPT_SIGN_FILE = 5;
- public static final int ACTION_ENCRYPT_SIGN_STREAM = 6;
+ public static final int ACTION_DECRYPT_BYTES = 20;
+ public static final int ACTION_DECRYPT_FILE = 21;
+ public static final int ACTION_DECRYPT_STREAM = 22;
- public static final int ACTION_DELETE_FILE_SECURELY = 7;
+ public static final int ACTION_SAVE_KEYRING = 30;
+ public static final int ACTION_GENERATE_KEY = 31;
+ public static final int ACTION_GENERATE_DEFAULT_RSA_KEYS = 32;
+
+ public static final int ACTION_DELETE_FILE_SECURELY = 40;
// possible data keys as result
+ // keys
public static final String RESULT_NEW_KEY = "new_key";
public static final String RESULT_NEW_KEY2 = "new_key2";
- public static final String RESULT_SIGNATURE_DATA = "signatureData";
- public static final String RESULT_SIGNATURE_TEXT = "signatureText";
- public static final String RESULT_ENCRYPTED_MESSAGE = "encryptedMessage";
- public static final String RESULT_ENCRYPTED_DATA = "encryptedData";
- public static final String RESULT_URI = "resultUri";
+
+ // encrypt
+ public static final String RESULT_SIGNATURE_DATA = "signature_data";
+ public static final String RESULT_SIGNATURE_TEXT = "signature_text";
+ public static final String RESULT_ENCRYPTED_MESSAGE = "encrypted_message";
+ public static final String RESULT_ENCRYPTED_DATA = "encrypted_data";
+ public static final String RESULT_URI = "result_uri";
+
+ // decrypt
+ public static final String RESULT_DECRYPTED_MESSAGE = "decrypted_message";
+ public static final String RESULT_DECRYPTED_DATA = "decrypted_data";
+ public static final String EXTRA_SIGNATURE = "signature";
+ public static final String EXTRA_SIGNATURE_KEY_ID = "signature_key_id";
+ public static final String EXTRA_SIGNATURE_USER_ID = "signature_user_id";
+ public static final String EXTRA_SIGNATURE_SUCCESS = "signature_success";
+ public static final String EXTRA_SIGNATURE_UNKNOWN = "signature_unknown";
Messenger mMessenger;
@@ -149,7 +181,7 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
case ACTION_SAVE_KEYRING:
try {
- // Input
+ /* Input */
String oldPassPhrase = data.getString(CURRENT_PASSPHRASE);
String newPassPhrase = data.getString(NEW_PASSPHRASE);
if (newPassPhrase == null) {
@@ -157,19 +189,19 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
}
@SuppressWarnings("unchecked")
ArrayList userIds = (ArrayList) data.getSerializable(USER_IDS);
- ArrayList keys = Utils.BytesToPGPSecretKeyList(data
+ ArrayList keys = PGPConversionHelper.BytesToPGPSecretKeyList(data
.getByteArray(KEYS));
@SuppressWarnings("unchecked")
ArrayList keysUsages = (ArrayList) data
.getSerializable(KEYS_USAGES);
long masterKeyId = data.getLong(MASTER_KEY_ID);
- // Operation
- Apg.buildSecretKey(this, userIds, keys, keysUsages, masterKeyId, oldPassPhrase,
- newPassPhrase, this);
- Apg.setCachedPassPhrase(masterKeyId, newPassPhrase);
+ /* Operation */
+ PGPHelper.buildSecretKey(this, userIds, keys, keysUsages, masterKeyId,
+ oldPassPhrase, newPassPhrase, this);
+ PGPHelper.setCachedPassPhrase(masterKeyId, newPassPhrase);
- // Output
+ /* Output */
sendMessageToHandler(ApgHandler.MESSAGE_OKAY);
} catch (Exception e) {
sendErrorToHandler(e);
@@ -180,22 +212,24 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
case ACTION_GENERATE_KEY:
try {
- // Input
+ /* Input */
int algorithm = data.getInt(ALGORITHM);
String passphrase = data.getString(SYMMETRIC_PASSPHRASE);
int keysize = data.getInt(KEY_SIZE);
PGPSecretKey masterKey = null;
if (data.containsKey(MASTER_KEY)) {
- masterKey = Utils.BytesToPGPSecretKey(data.getByteArray(MASTER_KEY));
+ masterKey = PGPConversionHelper.BytesToPGPSecretKey(data
+ .getByteArray(MASTER_KEY));
}
- // Operation
- PGPSecretKeyRing newKeyRing = Apg.createKey(this, algorithm, keysize, passphrase,
- masterKey);
+ /* Operation */
+ PGPSecretKeyRing newKeyRing = PGPHelper.createKey(this, algorithm, keysize,
+ passphrase, masterKey);
- // Output
+ /* Output */
Bundle resultData = new Bundle();
- resultData.putByteArray(RESULT_NEW_KEY, Utils.PGPSecretKeyRingToBytes(newKeyRing));
+ resultData.putByteArray(RESULT_NEW_KEY,
+ PGPConversionHelper.PGPSecretKeyRingToBytes(newKeyRing));
sendMessageToHandler(ApgHandler.MESSAGE_OKAY, resultData);
} catch (Exception e) {
sendErrorToHandler(e);
@@ -206,20 +240,22 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
case ACTION_GENERATE_DEFAULT_RSA_KEYS:
// generate one RSA 2048 key for signing and one subkey for encrypting!
try {
+ /* Input */
String passphrase = data.getString(SYMMETRIC_PASSPHRASE);
- // Operation
- PGPSecretKeyRing masterKeyRing = Apg.createKey(this, Id.choice.algorithm.rsa, 2048,
- passphrase, null);
+ /* Operation */
+ PGPSecretKeyRing masterKeyRing = PGPHelper.createKey(this, Id.choice.algorithm.rsa,
+ 2048, passphrase, null);
- PGPSecretKeyRing subKeyRing = Apg.createKey(this, Id.choice.algorithm.rsa, 2048,
- passphrase, masterKeyRing.getSecretKey());
+ PGPSecretKeyRing subKeyRing = PGPHelper.createKey(this, Id.choice.algorithm.rsa,
+ 2048, passphrase, masterKeyRing.getSecretKey());
- // Output
+ /* Output */
Bundle resultData = new Bundle();
resultData.putByteArray(RESULT_NEW_KEY,
- Utils.PGPSecretKeyRingToBytes(masterKeyRing));
- resultData.putByteArray(RESULT_NEW_KEY2, Utils.PGPSecretKeyRingToBytes(subKeyRing));
+ PGPConversionHelper.PGPSecretKeyRingToBytes(masterKeyRing));
+ resultData.putByteArray(RESULT_NEW_KEY2,
+ PGPConversionHelper.PGPSecretKeyRingToBytes(subKeyRing));
sendMessageToHandler(ApgHandler.MESSAGE_OKAY, resultData);
} catch (Exception e) {
sendErrorToHandler(e);
@@ -230,11 +266,11 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
case ACTION_ENCRYPT_SIGN_BYTES:
try {
- // Input
+ /* Input */
long secretKeyId = data.getLong(SECRET_KEY_ID);
String passphrase = data.getString(SYMMETRIC_PASSPHRASE);
- byte[] bytes = data.getByteArray(BYTES);
+ byte[] bytes = data.getByteArray(MESSAGE_BYTES);
boolean useAsciiArmour = data.getBoolean(USE_ASCII_AMOR);
long encryptionKeyIds[] = data.getLongArray(ENCRYPTION_KEYS_IDS);
@@ -243,7 +279,7 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
boolean generateSignature = data.getBoolean(GENERATE_SIGNATURE);
boolean signOnly = data.getBoolean(SIGN_ONLY);
- // Operation
+ /* Operation */
ByteArrayInputStream inStream = new ByteArrayInputStream(bytes);
int inLength = bytes.length;
@@ -252,20 +288,20 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
if (generateSignature) {
Log.d(Constants.TAG, "generate signature...");
- Apg.generateSignature(this, inputData, outStream, useAsciiArmour, false,
- secretKeyId, Apg.getCachedPassPhrase(secretKeyId), Preferences
+ PGPHelper.generateSignature(this, inputData, outStream, useAsciiArmour, false,
+ secretKeyId, PGPHelper.getCachedPassPhrase(secretKeyId), Preferences
.getPreferences(this).getDefaultHashAlgorithm(), Preferences
.getPreferences(this).getForceV3Signatures(), this);
} else if (signOnly) {
Log.d(Constants.TAG, "sign only...");
- Apg.signText(this, inputData, outStream, secretKeyId, Apg
+ PGPHelper.signText(this, inputData, outStream, secretKeyId, PGPHelper
.getCachedPassPhrase(secretKeyId), Preferences.getPreferences(this)
.getDefaultHashAlgorithm(), Preferences.getPreferences(this)
.getForceV3Signatures(), this);
} else {
Log.d(Constants.TAG, "encrypt...");
- Apg.encrypt(this, inputData, outStream, useAsciiArmour, encryptionKeyIds,
- signatureKeyId, Apg.getCachedPassPhrase(signatureKeyId), this,
+ PGPHelper.encrypt(this, inputData, outStream, useAsciiArmour, encryptionKeyIds,
+ signatureKeyId, PGPHelper.getCachedPassPhrase(signatureKeyId), this,
Preferences.getPreferences(this).getDefaultEncryptionAlgorithm(),
Preferences.getPreferences(this).getDefaultHashAlgorithm(),
compressionId, Preferences.getPreferences(this).getForceV3Signatures(),
@@ -274,7 +310,7 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
outStream.close();
- // Output
+ /* Output */
Bundle resultData = new Bundle();
if (useAsciiArmour) {
@@ -302,7 +338,7 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
case ACTION_ENCRYPT_SIGN_FILE:
try {
- // Input
+ /* Input */
long secretKeyId = data.getLong(SECRET_KEY_ID);
String passphrase = data.getString(SYMMETRIC_PASSPHRASE);
@@ -316,51 +352,41 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
boolean generateSignature = data.getBoolean(GENERATE_SIGNATURE);
boolean signOnly = data.getBoolean(SIGN_ONLY);
+ /* Operation */
+ // check if storage is ready
+ if (!FileHelper.isStorageMounted(inputFile)
+ || !FileHelper.isStorageMounted(outputFile)) {
+ sendErrorToHandler(new GeneralException(
+ getString(R.string.error_externalStorageNotReady)));
+ return;
+ }
+
// InputStream
long inLength = -1;
- FileInputStream inStream = null;
- if (inputFile.startsWith(Environment.getExternalStorageDirectory()
- .getAbsolutePath())) {
- if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- sendErrorToHandler(new GeneralException(
- getString(R.string.error_externalStorageNotReady)));
- return;
- }
- }
- inStream = new FileInputStream(inputFile);
+ FileInputStream inStream = new FileInputStream(inputFile);
File file = new File(inputFile);
inLength = file.length();
-
InputData inputData = new InputData(inStream, inLength);
// OutputStream
- if (outputFile.startsWith(Environment.getExternalStorageDirectory()
- .getAbsolutePath())) {
- if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- sendErrorToHandler(new GeneralException(
- getString(R.string.error_externalStorageNotReady)));
- return;
- }
- }
FileOutputStream outStream = new FileOutputStream(outputFile);
- // Operation
if (generateSignature) {
Log.d(Constants.TAG, "generate signature...");
- Apg.generateSignature(this, inputData, outStream, useAsciiArmour, true,
- secretKeyId, Apg.getCachedPassPhrase(secretKeyId), Preferences
+ PGPHelper.generateSignature(this, inputData, outStream, useAsciiArmour, true,
+ secretKeyId, PGPHelper.getCachedPassPhrase(secretKeyId), Preferences
.getPreferences(this).getDefaultHashAlgorithm(), Preferences
.getPreferences(this).getForceV3Signatures(), this);
} else if (signOnly) {
Log.d(Constants.TAG, "sign only...");
- Apg.signText(this, inputData, outStream, secretKeyId, Apg
+ PGPHelper.signText(this, inputData, outStream, secretKeyId, PGPHelper
.getCachedPassPhrase(secretKeyId), Preferences.getPreferences(this)
.getDefaultHashAlgorithm(), Preferences.getPreferences(this)
.getForceV3Signatures(), this);
} else {
Log.d(Constants.TAG, "encrypt...");
- Apg.encrypt(this, inputData, outStream, useAsciiArmour, encryptionKeyIds,
- signatureKeyId, Apg.getCachedPassPhrase(signatureKeyId), this,
+ PGPHelper.encrypt(this, inputData, outStream, useAsciiArmour, encryptionKeyIds,
+ signatureKeyId, PGPHelper.getCachedPassPhrase(signatureKeyId), this,
Preferences.getPreferences(this).getDefaultEncryptionAlgorithm(),
Preferences.getPreferences(this).getDefaultHashAlgorithm(),
compressionId, Preferences.getPreferences(this).getForceV3Signatures(),
@@ -369,6 +395,7 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
outStream.close();
+ /* Output */
sendMessageToHandler(ApgHandler.MESSAGE_OKAY);
} catch (Exception e) {
sendErrorToHandler(e);
@@ -377,7 +404,7 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
case ACTION_ENCRYPT_SIGN_STREAM:
try {
- // Input
+ /* Input */
long secretKeyId = data.getLong(SECRET_KEY_ID);
String passphrase = data.getString(SYMMETRIC_PASSPHRASE);
@@ -389,20 +416,21 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
int compressionId = data.getInt(COMPRESSION_ID);
boolean generateSignature = data.getBoolean(GENERATE_SIGNATURE);
boolean signOnly = data.getBoolean(SIGN_ONLY);
-
+
+ /* Operation */
// InputStream
InputStream in = getContentResolver().openInputStream(providerUri);
- long inLength = Apg.getLengthOfStream(in);
-
+ long inLength = PGPHelper.getLengthOfStream(in);
InputData inputData = new InputData(in, inLength);
// OutputStream
String streamFilename = null;
try {
while (true) {
- streamFilename = Apg.generateRandomString(32);
+ streamFilename = PGPHelper.generateRandomString(32);
if (streamFilename == null) {
- throw new Apg.GeneralException("couldn't generate random file name");
+ throw new PGPHelper.GeneralException(
+ "couldn't generate random file name");
}
openFileInput(streamFilename).close();
}
@@ -411,20 +439,19 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
}
FileOutputStream outStream = openFileOutput(streamFilename, Context.MODE_PRIVATE);
- // Operation
if (generateSignature) {
- Apg.generateSignature(this, inputData, outStream, useAsciiArmour, true,
- secretKeyId, Apg.getCachedPassPhrase(secretKeyId), Preferences
+ PGPHelper.generateSignature(this, inputData, outStream, useAsciiArmour, true,
+ secretKeyId, PGPHelper.getCachedPassPhrase(secretKeyId), Preferences
.getPreferences(this).getDefaultHashAlgorithm(), Preferences
.getPreferences(this).getForceV3Signatures(), this);
} else if (signOnly) {
- Apg.signText(this, inputData, outStream, secretKeyId, Apg
+ PGPHelper.signText(this, inputData, outStream, secretKeyId, PGPHelper
.getCachedPassPhrase(secretKeyId), Preferences.getPreferences(this)
.getDefaultHashAlgorithm(), Preferences.getPreferences(this)
.getForceV3Signatures(), this);
} else {
- Apg.encrypt(this, inputData, outStream, useAsciiArmour, encryptionKeyIds,
- signatureKeyId, Apg.getCachedPassPhrase(signatureKeyId), this,
+ PGPHelper.encrypt(this, inputData, outStream, useAsciiArmour, encryptionKeyIds,
+ signatureKeyId, PGPHelper.getCachedPassPhrase(signatureKeyId), this,
Preferences.getPreferences(this).getDefaultEncryptionAlgorithm(),
Preferences.getPreferences(this).getDefaultHashAlgorithm(),
compressionId, Preferences.getPreferences(this).getForceV3Signatures(),
@@ -433,7 +460,7 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
outStream.close();
- // Output
+ /* Output */
Bundle resultData = new Bundle();
String uri = "content://" + DataProvider.AUTHORITY + "/data/" + streamFilename;
@@ -448,21 +475,21 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
case ACTION_DELETE_FILE_SECURELY:
try {
- // Input
+ /* Input */
String deleteFile = data.getString(DELETE_FILE);
- // Operation
+ /* Operation */
try {
- Apg.deleteFileSecurely(this, new File(deleteFile), this);
+ PGPHelper.deleteFileSecurely(this, new File(deleteFile), this);
} catch (FileNotFoundException e) {
- throw new Apg.GeneralException(getString(R.string.error_fileNotFound,
+ throw new PGPHelper.GeneralException(getString(R.string.error_fileNotFound,
deleteFile));
} catch (IOException e) {
- throw new Apg.GeneralException(getString(R.string.error_fileDeleteFailed,
+ throw new PGPHelper.GeneralException(getString(R.string.error_fileDeleteFailed,
deleteFile));
}
- // Output
+ /* Output */
sendMessageToHandler(ApgHandler.MESSAGE_OKAY);
} catch (Exception e) {
sendErrorToHandler(e);
@@ -470,6 +497,157 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
break;
+ case ACTION_DECRYPT_BYTES:
+ try {
+ /* Input */
+ long secretKeyId = data.getLong(SECRET_KEY_ID);
+ byte[] bytes = data.getByteArray(CIPHERTEXT_BYTES);
+ boolean signedOnly = data.getBoolean(SIGNED_ONLY);
+ boolean returnBytes = data.getBoolean(RETURN_BYTES);
+ boolean assumeSymmetricEncryption = data.getBoolean(ASSUME_SYMMETRIC);
+
+ /* Operation */
+ ByteArrayInputStream inStream = new ByteArrayInputStream(bytes);
+ int inLength = bytes.length;
+
+ InputData inputData = new InputData(inStream, inLength);
+ ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+
+ Bundle resultData = new Bundle();
+
+ // verifyText and decrypt returning additional resultData values for the
+ // verification of signatures
+ if (signedOnly) {
+ resultData = PGPHelper.verifyText(this, inputData, outStream, this);
+ } else {
+ resultData = PGPHelper.decrypt(this, inputData, outStream,
+ PGPHelper.getCachedPassPhrase(secretKeyId), this,
+ assumeSymmetricEncryption);
+ }
+
+ outStream.close();
+
+ /* Output */
+ if (returnBytes) {
+ byte output[] = outStream.toByteArray();
+ resultData.putByteArray(RESULT_DECRYPTED_DATA, output);
+ } else {
+ String output = new String(outStream.toByteArray());
+ resultData.putString(RESULT_DECRYPTED_MESSAGE, output);
+ }
+
+ sendMessageToHandler(ApgHandler.MESSAGE_OKAY, resultData);
+ } catch (Exception e) {
+ sendErrorToHandler(e);
+ }
+
+ break;
+
+ case ACTION_DECRYPT_FILE:
+ try {
+ /* Input */
+ long secretKeyId = data.getLong(SECRET_KEY_ID);
+ boolean signedOnly = data.getBoolean(SIGNED_ONLY);
+ boolean assumeSymmetricEncryption = data.getBoolean(ASSUME_SYMMETRIC);
+
+ String inputFile = data.getString(INPUT_FILE);
+ String outputFile = data.getString(OUTPUT_FILE);
+
+ /* Operation */
+ // check if storage is ready
+ if (!FileHelper.isStorageMounted(inputFile)
+ || !FileHelper.isStorageMounted(outputFile)) {
+ sendErrorToHandler(new GeneralException(
+ getString(R.string.error_externalStorageNotReady)));
+ return;
+ }
+
+ // InputStream
+ long inLength = -1;
+ FileInputStream inStream = new FileInputStream(inputFile);
+ File file = new File(inputFile);
+ inLength = file.length();
+ InputData inputData = new InputData(inStream, inLength);
+
+ // OutputStream
+ FileOutputStream outStream = new FileOutputStream(outputFile);
+
+ Bundle resultData = new Bundle();
+
+ // verifyText and decrypt returning additional output values for the
+ // verification of signatures
+ if (signedOnly) {
+ resultData = PGPHelper.verifyText(this, inputData, outStream, this);
+ } else {
+ resultData = PGPHelper.decrypt(this, inputData, outStream,
+ PGPHelper.getCachedPassPhrase(secretKeyId), this,
+ assumeSymmetricEncryption);
+ }
+
+ outStream.close();
+
+ /* Output */
+ sendMessageToHandler(ApgHandler.MESSAGE_OKAY, resultData);
+ } catch (Exception e) {
+ sendErrorToHandler(e);
+ }
+ break;
+
+ case ACTION_DECRYPT_STREAM:
+ try {
+ /* Input */
+ long secretKeyId = data.getLong(SECRET_KEY_ID);
+ boolean signedOnly = data.getBoolean(SIGNED_ONLY);
+ boolean assumeSymmetricEncryption = data.getBoolean(ASSUME_SYMMETRIC);
+ Uri providerUri = Uri.parse(data.getString(PROVIDER_URI));
+
+ /* Operation */
+ // InputStream
+ InputStream in = getContentResolver().openInputStream(providerUri);
+ long inLength = PGPHelper.getLengthOfStream(in);
+ InputData inputData = new InputData(in, inLength);
+
+ // OutputStream
+ String streamFilename = null;
+ try {
+ while (true) {
+ streamFilename = PGPHelper.generateRandomString(32);
+ if (streamFilename == null) {
+ throw new PGPHelper.GeneralException(
+ "couldn't generate random file name");
+ }
+ openFileInput(streamFilename).close();
+ }
+ } catch (FileNotFoundException e) {
+ // found a name that isn't used yet
+ }
+ FileOutputStream outStream = openFileOutput(streamFilename, Context.MODE_PRIVATE);
+
+ Bundle resultData = new Bundle();
+
+ // verifyText and decrypt returning additional output values for the
+ // verification of signatures
+ if (signedOnly) {
+ resultData = PGPHelper.verifyText(this, inputData, outStream, this);
+ } else {
+ resultData = PGPHelper.decrypt(this, inputData, outStream,
+ PGPHelper.getCachedPassPhrase(secretKeyId), this,
+ assumeSymmetricEncryption);
+ }
+
+ outStream.close();
+
+ /* Output */
+ String uri = "content://" + DataProvider.AUTHORITY + "/data/" + streamFilename;
+ resultData.putString(RESULT_URI, uri);
+
+ sendMessageToHandler(ApgHandler.MESSAGE_OKAY, resultData);
+ } catch (Exception e) {
+ sendErrorToHandler(e);
+ }
+
+ break;
+
default:
break;
}
diff --git a/org_apg/src/org/thialfihar/android/apg/service/ApgService2.java b/org_apg/src/org/thialfihar/android/apg/service/ApgService2.java
deleted file mode 100644
index 5b3de8050..000000000
--- a/org_apg/src/org/thialfihar/android/apg/service/ApgService2.java
+++ /dev/null
@@ -1,672 +0,0 @@
-/*
- * 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.thialfihar.android.apg.service;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-
-import org.thialfihar.android.apg.Apg;
-import org.thialfihar.android.apg.service.IApgService2;
-import org.thialfihar.android.apg.Id;
-import org.thialfihar.android.apg.InputData;
-import org.thialfihar.android.apg.Preferences;
-import org.thialfihar.android.apg.R;
-import org.thialfihar.android.apg.service.IApgService2.Stub;
-import org.thialfihar.android.apg.Id.database;
-import org.thialfihar.android.apg.R.string;
-import org.thialfihar.android.apg.passphrase.PassphraseCacheService;
-import org.thialfihar.android.apg.provider.KeyRings;
-import org.thialfihar.android.apg.provider.Keys;
-import org.thialfihar.android.apg.provider.UserIds;
-
-import android.content.ContentResolver;
-import android.content.Intent;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteQueryBuilder;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.util.Log;
-
-/**
- * ATTENTION:
- *
- * This is the old ApgService used as remote service over aidl interface. It will be reworked!
- *
- */
-public class ApgService2 extends PassphraseCacheService {
- private final static String TAG = "ApgService";
- public static final boolean LOCAL_LOGV = true;
- public static final boolean LOCAL_LOGD = true;
-
- @Override
- public IBinder onBind(Intent intent) {
- if (LOCAL_LOGD)
- Log.d(TAG, "bound");
- return mBinder;
- }
-
- /** error status */
- private static enum error {
- ARGUMENTS_MISSING, APG_FAILURE, NO_MATCHING_SECRET_KEY, PRIVATE_KEY_PASSPHRASE_WRONG, PRIVATE_KEY_PASSPHRASE_MISSING;
-
- public int shiftedOrdinal() {
- return ordinal() + 100;
- }
- }
-
- private static enum call {
- encrypt_with_passphrase, encrypt_with_public_key, decrypt, get_keys
- }
-
- /** all arguments that can be passed by calling application */
- public static enum arg {
- MESSAGE, // message to encrypt or to decrypt
- SYMMETRIC_PASSPHRASE, // key for symmetric en/decryption
- PUBLIC_KEYS, // public keys for encryption
- ENCRYPTION_ALGORYTHM, // encryption algorithm
- HASH_ALGORYTHM, // hash algorithm
- ARMORED_OUTPUT, // whether to armor output
- FORCE_V3_SIGNATURE, // whether to force v3 signature
- COMPRESSION, // what compression to use for encrypted output
- SIGNATURE_KEY, // key for signing
- PRIVATE_KEY_PASSPHRASE, // passphrase for encrypted private key
- KEY_TYPE, // type of key (private or public)
- BLOB, // blob passed
- }
-
- /** all things that might be returned */
- private static enum ret {
- ERRORS, // string array list with errors
- WARNINGS, // string array list with warnings
- ERROR, // numeric error
- RESULT, // en-/decrypted
- FINGERPRINTS, // fingerprints of keys
- USER_IDS, // user ids
- }
-
- /** required arguments for each AIDL function */
- private static final HashMap> FUNCTIONS_REQUIRED_ARGS = new HashMap>();
- static {
- HashSet args = new HashSet();
- args.add(arg.SYMMETRIC_PASSPHRASE);
- FUNCTIONS_REQUIRED_ARGS.put(call.encrypt_with_passphrase.name(), args);
-
- args = new HashSet();
- args.add(arg.PUBLIC_KEYS);
- FUNCTIONS_REQUIRED_ARGS.put(call.encrypt_with_public_key.name(), args);
-
- args = new HashSet();
- FUNCTIONS_REQUIRED_ARGS.put(call.decrypt.name(), args);
-
- args = new HashSet();
- args.add(arg.KEY_TYPE);
- FUNCTIONS_REQUIRED_ARGS.put(call.get_keys.name(), args);
- }
-
- /** optional arguments for each AIDL function */
- private static final HashMap> FUNCTIONS_OPTIONAL_ARGS = new HashMap>();
- static {
- HashSet args = new HashSet();
- args.add(arg.ENCRYPTION_ALGORYTHM);
- args.add(arg.HASH_ALGORYTHM);
- args.add(arg.ARMORED_OUTPUT);
- args.add(arg.FORCE_V3_SIGNATURE);
- args.add(arg.COMPRESSION);
- args.add(arg.PRIVATE_KEY_PASSPHRASE);
- args.add(arg.SIGNATURE_KEY);
- args.add(arg.BLOB);
- args.add(arg.MESSAGE);
- FUNCTIONS_OPTIONAL_ARGS.put(call.encrypt_with_passphrase.name(), args);
- FUNCTIONS_OPTIONAL_ARGS.put(call.encrypt_with_public_key.name(), args);
-
- args = new HashSet();
- args.add(arg.SYMMETRIC_PASSPHRASE);
- args.add(arg.PUBLIC_KEYS);
- args.add(arg.PRIVATE_KEY_PASSPHRASE);
- args.add(arg.MESSAGE);
- args.add(arg.BLOB);
- FUNCTIONS_OPTIONAL_ARGS.put(call.decrypt.name(), args);
- }
-
- /** a map from ApgService parameters to function calls to get the default */
- private static final HashMap FUNCTIONS_DEFAULTS = new HashMap();
- static {
- FUNCTIONS_DEFAULTS.put(arg.ENCRYPTION_ALGORYTHM, "getDefaultEncryptionAlgorithm");
- FUNCTIONS_DEFAULTS.put(arg.HASH_ALGORYTHM, "getDefaultHashAlgorithm");
- FUNCTIONS_DEFAULTS.put(arg.ARMORED_OUTPUT, "getDefaultAsciiArmour");
- FUNCTIONS_DEFAULTS.put(arg.FORCE_V3_SIGNATURE, "getForceV3Signatures");
- FUNCTIONS_DEFAULTS.put(arg.COMPRESSION, "getDefaultMessageCompression");
- }
-
- /** a map of the default function names to their method */
- private static final HashMap FUNCTIONS_DEFAULTS_METHODS = new HashMap();
- static {
- try {
- FUNCTIONS_DEFAULTS_METHODS.put("getDefaultEncryptionAlgorithm",
- Preferences.class.getMethod("getDefaultEncryptionAlgorithm"));
- FUNCTIONS_DEFAULTS_METHODS.put("getDefaultHashAlgorithm",
- Preferences.class.getMethod("getDefaultHashAlgorithm"));
- FUNCTIONS_DEFAULTS_METHODS.put("getDefaultAsciiArmour",
- Preferences.class.getMethod("getDefaultAsciiArmour"));
- FUNCTIONS_DEFAULTS_METHODS.put("getForceV3Signatures",
- Preferences.class.getMethod("getForceV3Signatures"));
- FUNCTIONS_DEFAULTS_METHODS.put("getDefaultMessageCompression",
- Preferences.class.getMethod("getDefaultMessageCompression"));
- } catch (Exception e) {
- Log.e(TAG, "Function method exception: " + e.getMessage());
- }
- }
-
- private static void writeToOutputStream(InputStream is, OutputStream os) throws IOException {
- byte[] buffer = new byte[8];
- int len = 0;
- while ((len = is.read(buffer)) != -1) {
- os.write(buffer, 0, len);
- }
- }
-
- private static Cursor getKeyEntries(HashMap pParams) {
- SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
- qb.setTables(KeyRings.TABLE_NAME + " INNER JOIN " + Keys.TABLE_NAME + " ON " + "("
- + KeyRings.TABLE_NAME + "." + KeyRings._ID + " = " + Keys.TABLE_NAME + "."
- + Keys.KEY_RING_ID + " AND " + Keys.TABLE_NAME + "." + Keys.IS_MASTER_KEY
- + " = '1'" + ") " + " INNER JOIN " + UserIds.TABLE_NAME + " ON " + "("
- + Keys.TABLE_NAME + "." + Keys._ID + " = " + UserIds.TABLE_NAME + "."
- + UserIds.KEY_ID + " AND " + UserIds.TABLE_NAME + "." + UserIds.RANK + " = '0') ");
-
- String orderBy = pParams.containsKey("order_by") ? (String) pParams.get("order_by")
- : UserIds.TABLE_NAME + "." + UserIds.USER_ID + " ASC";
-
- String typeVal[] = null;
- String typeWhere = null;
- if (pParams.containsKey("key_type")) {
- typeWhere = KeyRings.TABLE_NAME + "." + KeyRings.TYPE + " = ?";
- typeVal = new String[] { "" + pParams.get("key_type") };
- }
- return qb.query(Apg.getDatabase().db(), (String[]) pParams.get("columns"), typeWhere,
- typeVal, null, null, orderBy);
- }
-
- /**
- * maps a fingerprint or user id of a key to a master key in database
- *
- * @param search_key
- * fingerprint or user id to search for
- * @return master key if found, or 0
- */
- private static long getMasterKey(String pSearchKey, Bundle pReturn) {
- if (pSearchKey == null || pSearchKey.length() != 8) {
- return 0;
- }
- ArrayList keyList = new ArrayList();
- keyList.add(pSearchKey);
- long[] keys = getMasterKey(keyList, pReturn);
- if (keys.length > 0) {
- return keys[0];
- } else {
- return 0;
- }
- }
-
- /**
- * maps fingerprints or user ids of keys to master keys in database
- *
- * @param search_keys
- * a list of keys (fingerprints or user ids) to look for in database
- * @return an array of master keys
- */
- private static long[] getMasterKey(ArrayList pSearchKeys, Bundle pReturn) {
-
- HashMap qParams = new HashMap();
- qParams.put("columns", new String[] { KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID, // 0
- UserIds.TABLE_NAME + "." + UserIds.USER_ID, // 1
- });
- qParams.put("key_type", Id.database.type_public);
-
- Cursor mCursor = getKeyEntries(qParams);
-
- if (LOCAL_LOGV)
- Log.v(TAG, "going through installed user keys");
- ArrayList masterKeys = new ArrayList();
- while (mCursor.moveToNext()) {
- long curMkey = mCursor.getLong(0);
- String curUser = mCursor.getString(1);
-
- String curFprint = Apg.getSmallFingerPrint(curMkey);
- if (LOCAL_LOGV)
- Log.v(TAG, "current user: " + curUser + " (" + curFprint + ")");
- if (pSearchKeys.contains(curFprint) || pSearchKeys.contains(curUser)) {
- if (LOCAL_LOGV)
- Log.v(TAG, "master key found for: " + curFprint);
- masterKeys.add(curMkey);
- pSearchKeys.remove(curFprint);
- } else {
- if (LOCAL_LOGV)
- Log.v(TAG, "Installed key " + curFprint
- + " is not in the list of public keys to encrypt with");
- }
- }
- mCursor.close();
-
- long[] masterKeyLongs = new long[masterKeys.size()];
- int i = 0;
- for (Long key : masterKeys) {
- masterKeyLongs[i++] = key;
- }
-
- if (i == 0) {
- Log.w(TAG, "Found not one public key");
- pReturn.getStringArrayList(ret.WARNINGS.name()).add(
- "Searched for public key(s) but found not one");
- }
-
- for (String key : pSearchKeys) {
- Log.w(TAG, "Searched for key " + key + " but cannot find it in APG");
- pReturn.getStringArrayList(ret.WARNINGS.name()).add(
- "Searched for key " + key + " but cannot find it in APG");
- }
-
- return masterKeyLongs;
- }
-
- /**
- * Add default arguments if missing
- *
- * @param args
- * the bundle to add default parameters to if missing
- */
- private void addDefaultArguments(String pCall, Bundle pArgs) {
- // check whether there are optional elements defined for that call
- if (FUNCTIONS_OPTIONAL_ARGS.containsKey(pCall)) {
- Preferences preferences = Preferences.getPreferences(getBaseContext(), true);
-
- Iterator iter = FUNCTIONS_DEFAULTS.keySet().iterator();
- while (iter.hasNext()) {
- arg currentArg = iter.next();
- String currentKey = currentArg.name();
- if (!pArgs.containsKey(currentKey)
- && FUNCTIONS_OPTIONAL_ARGS.get(pCall).contains(currentArg)) {
- String currentFunctionName = FUNCTIONS_DEFAULTS.get(currentArg);
- try {
- Class> returnType = FUNCTIONS_DEFAULTS_METHODS.get(currentFunctionName)
- .getReturnType();
- if (returnType == String.class) {
- pArgs.putString(currentKey,
- (String) FUNCTIONS_DEFAULTS_METHODS.get(currentFunctionName)
- .invoke(preferences));
- } else if (returnType == boolean.class) {
- pArgs.putBoolean(currentKey,
- (Boolean) FUNCTIONS_DEFAULTS_METHODS.get(currentFunctionName)
- .invoke(preferences));
- } else if (returnType == int.class) {
- pArgs.putInt(currentKey,
- (Integer) FUNCTIONS_DEFAULTS_METHODS.get(currentFunctionName)
- .invoke(preferences));
- } else {
- Log.e(TAG, "Unknown return type " + returnType.toString()
- + " for default option");
- }
- } catch (Exception e) {
- Log.e(TAG, "Exception in add_default_arguments " + e.getMessage());
- }
- }
- }
- }
- }
-
- /**
- * updates a Bundle with default return values
- *
- * @param pReturn
- * the Bundle to update
- */
- private void addDefaultReturns(Bundle pReturn) {
- ArrayList errors = new ArrayList();
- ArrayList warnings = new ArrayList();
-
- pReturn.putStringArrayList(ret.ERRORS.name(), errors);
- pReturn.putStringArrayList(ret.WARNINGS.name(), warnings);
- }
-
- /**
- * checks for required arguments and adds them to the error if missing
- *
- * @param function
- * the functions required arguments to check for
- * @param pArgs
- * the Bundle of arguments to check
- * @param pReturn
- * the bundle to write errors to
- */
- private void checkForRequiredArgs(String pFunction, Bundle pArgs, Bundle pReturn) {
- if (FUNCTIONS_REQUIRED_ARGS.containsKey(pFunction)) {
- Iterator iter = FUNCTIONS_REQUIRED_ARGS.get(pFunction).iterator();
- while (iter.hasNext()) {
- String curArg = iter.next().name();
- if (!pArgs.containsKey(curArg)) {
- pReturn.getStringArrayList(ret.ERRORS.name())
- .add("Argument missing: " + curArg);
- }
- }
- }
-
- if (pFunction.equals(call.encrypt_with_passphrase.name())
- || pFunction.equals(call.encrypt_with_public_key.name())
- || pFunction.equals(call.decrypt.name())) {
- // check that either MESSAGE or BLOB are there
- if (!pArgs.containsKey(arg.MESSAGE.name()) && !pArgs.containsKey(arg.BLOB.name())) {
- pReturn.getStringArrayList(ret.ERRORS.name()).add(
- "Arguments missing: Neither MESSAGE nor BLOG found");
- }
-
- }
- }
-
- /**
- * checks for unknown arguments and add them to warning if found
- *
- * @param function
- * the functions name to check against
- * @param pArgs
- * the Bundle of arguments to check
- * @param pReturn
- * the bundle to write warnings to
- */
- private void checkForUnknownArgs(String pFunction, Bundle pArgs, Bundle pReturn) {
-
- HashSet allArgs = new HashSet();
- if (FUNCTIONS_REQUIRED_ARGS.containsKey(pFunction)) {
- allArgs.addAll(FUNCTIONS_REQUIRED_ARGS.get(pFunction));
- }
- if (FUNCTIONS_OPTIONAL_ARGS.containsKey(pFunction)) {
- allArgs.addAll(FUNCTIONS_OPTIONAL_ARGS.get(pFunction));
- }
-
- ArrayList unknownArgs = new ArrayList();
- Iterator iter = pArgs.keySet().iterator();
- while (iter.hasNext()) {
- String curKey = iter.next();
- try {
- arg curArg = arg.valueOf(curKey);
- if (!allArgs.contains(curArg)) {
- pReturn.getStringArrayList(ret.WARNINGS.name()).add(
- "Unknown argument: " + curKey);
- unknownArgs.add(curKey);
- }
- } catch (Exception e) {
- pReturn.getStringArrayList(ret.WARNINGS.name()).add("Unknown argument: " + curKey);
- unknownArgs.add(curKey);
- }
- }
-
- // remove unknown arguments so our bundle has just what we need
- for (String arg : unknownArgs) {
- pArgs.remove(arg);
- }
- }
-
- private boolean prepareArgs(String pCall, Bundle pArgs, Bundle pReturn) {
- Apg.initialize(getBaseContext());
-
- /* add default return values for all functions */
- addDefaultReturns(pReturn);
-
- /* add default arguments if missing */
- addDefaultArguments(pCall, pArgs);
- if (LOCAL_LOGV)
- Log.v(TAG, "add_default_arguments");
-
- /* check for required arguments */
- checkForRequiredArgs(pCall, pArgs, pReturn);
- if (LOCAL_LOGV)
- Log.v(TAG, "check_required_args");
-
- /* check for unknown arguments and add to warning if found */
- checkForUnknownArgs(pCall, pArgs, pReturn);
- if (LOCAL_LOGV)
- Log.v(TAG, "check_unknown_args");
-
- /* return if errors happened */
- if (pReturn.getStringArrayList(ret.ERRORS.name()).size() != 0) {
- if (LOCAL_LOGV)
- Log.v(TAG, "Errors after preparing, not executing " + pCall);
- pReturn.putInt(ret.ERROR.name(), error.ARGUMENTS_MISSING.shiftedOrdinal());
- return false;
- }
- if (LOCAL_LOGV)
- Log.v(TAG, "error return");
-
- return true;
- }
-
- private boolean encrypt(Bundle pArgs, Bundle pReturn) {
- boolean isBlob = pArgs.containsKey(arg.BLOB.name());
-
- long pubMasterKeys[] = {};
- if (pArgs.containsKey(arg.PUBLIC_KEYS.name())) {
- ArrayList list = pArgs.getStringArrayList(arg.PUBLIC_KEYS.name());
- ArrayList pubKeys = new ArrayList();
- if (LOCAL_LOGV)
- Log.v(TAG, "Long size: " + list.size());
- Iterator iter = list.iterator();
- while (iter.hasNext()) {
- pubKeys.add(iter.next());
- }
- pubMasterKeys = getMasterKey(pubKeys, pReturn);
- }
-
- InputStream inStream = null;
- if (isBlob) {
- ContentResolver cr = getContentResolver();
- try {
- inStream = cr.openInputStream(Uri.parse(pArgs.getString(arg.BLOB.name())));
- } catch (Exception e) {
- Log.e(TAG, "... exception on opening blob", e);
- }
- } else {
- inStream = new ByteArrayInputStream(pArgs.getString(arg.MESSAGE.name()).getBytes());
- }
- InputData in = new InputData(inStream, 0); // XXX Size second param?
-
- OutputStream out = new ByteArrayOutputStream();
- if (LOCAL_LOGV)
- Log.v(TAG, "About to encrypt");
- try {
- Apg.encrypt(getBaseContext(), // context
- in, // input stream
- out, // output stream
- pArgs.getBoolean(arg.ARMORED_OUTPUT.name()), // ARMORED_OUTPUT
- pubMasterKeys, // encryption keys
- getMasterKey(pArgs.getString(arg.SIGNATURE_KEY.name()), pReturn), // signature
- // key
- pArgs.getString(arg.PRIVATE_KEY_PASSPHRASE.name()), // signature passphrase
- null, // progress
- pArgs.getInt(arg.ENCRYPTION_ALGORYTHM.name()), // encryption
- pArgs.getInt(arg.HASH_ALGORYTHM.name()), // hash
- pArgs.getInt(arg.COMPRESSION.name()), // compression
- pArgs.getBoolean(arg.FORCE_V3_SIGNATURE.name()), // mPreferences.getForceV3Signatures(),
- pArgs.getString(arg.SYMMETRIC_PASSPHRASE.name()) // passPhrase
- );
- } catch (Exception e) {
- Log.e(TAG, "Exception in encrypt");
- String msg = e.getMessage();
- if (msg.equals(getBaseContext().getString(R.string.error_noSignaturePassPhrase))) {
- pReturn.getStringArrayList(ret.ERRORS.name()).add(
- "Cannot encrypt (" + arg.PRIVATE_KEY_PASSPHRASE.name() + " missing): "
- + msg);
- pReturn.putInt(ret.ERROR.name(),
- error.PRIVATE_KEY_PASSPHRASE_MISSING.shiftedOrdinal());
- } else if (msg.equals(getBaseContext().getString(
- R.string.error_couldNotExtractPrivateKey))) {
- pReturn.getStringArrayList(ret.ERRORS.name()).add(
- "Cannot encrypt (" + arg.PRIVATE_KEY_PASSPHRASE.name()
- + " probably wrong): " + msg);
- pReturn.putInt(ret.ERROR.name(),
- error.PRIVATE_KEY_PASSPHRASE_WRONG.shiftedOrdinal());
- } else {
- pReturn.getStringArrayList(ret.ERRORS.name()).add(
- "Internal failure (" + e.getClass() + ") in APG when encrypting: "
- + e.getMessage());
- pReturn.putInt(ret.ERROR.name(), error.APG_FAILURE.shiftedOrdinal());
- }
- return false;
- }
- if (LOCAL_LOGV)
- Log.v(TAG, "Encrypted");
- if (isBlob) {
- ContentResolver cr = getContentResolver();
- try {
- OutputStream outStream = cr.openOutputStream(Uri.parse(pArgs.getString(arg.BLOB
- .name())));
- writeToOutputStream(new ByteArrayInputStream(out.toString().getBytes()), outStream);
- outStream.close();
- } catch (Exception e) {
- Log.e(TAG, "... exception on writing blob", e);
- }
- } else {
- pReturn.putString(ret.RESULT.name(), out.toString());
- }
- return true;
- }
-
- private final IApgService2.Stub mBinder = new IApgService2.Stub() {
-
- public boolean getKeys(Bundle pArgs, Bundle pReturn) {
-
- prepareArgs("get_keys", pArgs, pReturn);
-
- HashMap qParams = new HashMap();
- qParams.put("columns", new String[] {
- KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID, // 0
- UserIds.TABLE_NAME + "." + UserIds.USER_ID, // 1
- });
-
- qParams.put("key_type", pArgs.getInt(arg.KEY_TYPE.name()));
-
- Cursor cursor = getKeyEntries(qParams);
- ArrayList fPrints = new ArrayList();
- ArrayList ids = new ArrayList();
- while (cursor.moveToNext()) {
- if (LOCAL_LOGV)
- Log.v(TAG, "adding key " + Apg.getSmallFingerPrint(cursor.getLong(0)));
- fPrints.add(Apg.getSmallFingerPrint(cursor.getLong(0)));
- ids.add(cursor.getString(1));
- }
- cursor.close();
-
- pReturn.putStringArrayList(ret.FINGERPRINTS.name(), fPrints);
- pReturn.putStringArrayList(ret.USER_IDS.name(), ids);
- return true;
- }
-
- public boolean encryptWithPublicKey(Bundle pArgs, Bundle pReturn) {
- if (!prepareArgs("encrypt_with_public_key", pArgs, pReturn)) {
- return false;
- }
-
- return encrypt(pArgs, pReturn);
- }
-
- public boolean encryptWithPassphrase(Bundle pArgs, Bundle pReturn) {
- if (!prepareArgs("encrypt_with_passphrase", pArgs, pReturn)) {
- return false;
- }
-
- return encrypt(pArgs, pReturn);
-
- }
-
- public boolean decrypt(Bundle pArgs, Bundle pReturn) {
- if (!prepareArgs("decrypt", pArgs, pReturn)) {
- return false;
- }
-
- boolean isBlob = pArgs.containsKey(arg.BLOB.name());
-
- String passphrase = pArgs.getString(arg.SYMMETRIC_PASSPHRASE.name()) != null ? pArgs
- .getString(arg.SYMMETRIC_PASSPHRASE.name()) : pArgs
- .getString(arg.PRIVATE_KEY_PASSPHRASE.name());
-
- InputStream inStream = null;
- if (isBlob) {
- ContentResolver cr = getContentResolver();
- try {
- inStream = cr.openInputStream(Uri.parse(pArgs.getString(arg.BLOB.name())));
- } catch (Exception e) {
- Log.e(TAG, "... exception on opening blob", e);
- }
- } else {
- inStream = new ByteArrayInputStream(pArgs.getString(arg.MESSAGE.name()).getBytes());
- }
-
- InputData in = new InputData(inStream, 0); // XXX what size in second parameter?
- OutputStream out = new ByteArrayOutputStream();
- if (LOCAL_LOGV)
- Log.v(TAG, "About to decrypt");
- try {
- Apg.decrypt(getBaseContext(), in, out, passphrase, null, // progress
- pArgs.getString(arg.SYMMETRIC_PASSPHRASE.name()) != null // symmetric
- );
- } catch (Exception e) {
- Log.e(TAG, "Exception in decrypt");
- String msg = e.getMessage();
- if (msg.equals(getBaseContext().getString(R.string.error_noSecretKeyFound))) {
- pReturn.getStringArrayList(ret.ERRORS.name()).add("Cannot decrypt: " + msg);
- pReturn.putInt(ret.ERROR.name(), error.NO_MATCHING_SECRET_KEY.shiftedOrdinal());
- } else if (msg.equals(getBaseContext().getString(R.string.error_wrongPassPhrase))) {
- pReturn.getStringArrayList(ret.ERRORS.name()).add(
- "Cannot decrypt (" + arg.PRIVATE_KEY_PASSPHRASE.name()
- + " wrong/missing): " + msg);
- pReturn.putInt(ret.ERROR.name(),
- error.PRIVATE_KEY_PASSPHRASE_WRONG.shiftedOrdinal());
- } else {
- pReturn.getStringArrayList(ret.ERRORS.name()).add(
- "Internal failure (" + e.getClass() + ") in APG when decrypting: "
- + msg);
- pReturn.putInt(ret.ERROR.name(), error.APG_FAILURE.shiftedOrdinal());
- }
- return false;
- }
- if (LOCAL_LOGV)
- Log.v(TAG, "... decrypted");
-
- if (isBlob) {
- ContentResolver cr = getContentResolver();
- try {
- OutputStream outStream = cr.openOutputStream(Uri.parse(pArgs.getString(arg.BLOB
- .name())));
- writeToOutputStream(new ByteArrayInputStream(out.toString().getBytes()),
- outStream);
- outStream.close();
- } catch (Exception e) {
- Log.e(TAG, "... exception on writing blob", e);
- }
- } else {
- pReturn.putString(ret.RESULT.name(), out.toString());
- }
- return true;
- }
-
- };
-}
diff --git a/org_apg/src/org/thialfihar/android/apg/service/IApgService2.aidl b/org_apg/src/org/thialfihar/android/apg/service/IApgService2.aidl
deleted file mode 100644
index 4eba62655..000000000
--- a/org_apg/src/org/thialfihar/android/apg/service/IApgService2.aidl
+++ /dev/null
@@ -1,125 +0,0 @@
-package org.thialfihar.android.apg.service;
-
-interface IApgService2 {
-
- /* All functions fill the returnVals Bundle with the following keys:
- *
- * ArrayList "WARNINGS" = Warnings, if any
- * ArrayList "ERRORS" = Human readable error descriptions, if any
- * int "ERROR" = Numeric representation of error, if any
- * starting with 100:
- * 100: Required argument missing
- * 101: Generic failure of APG
- * 102: No matching private key found
- * 103: Private key's passphrase wrong
- * 104: Private key's passphrase missing
- */
-
- /* ********************************************************
- * Encryption
- * ********************************************************/
-
- /* All encryption function's arguments
- *
- * Bundle params' keys:
- * (optional/required)
- * TYPE "STRING KEY" = EXPLANATION / VALUES
- *
- * (required)
- * String "MESSAGE" = Message to encrypt
- * OR
- * String "BLOB" = ContentUri to a file handle
- * with binary data to encrypt
- * (Attention: file will be overwritten
- * with encrypted content!)
- *
- * (optional)
- * int "ENCRYPTION_ALGORYTHM" = Encryption Algorithm
- * 7: AES-128, 8: AES-192, 9: AES-256,
- * 4: Blowfish, 10: Twofish, 3: CAST5,
- * 6: DES, 2: Triple DES, 1: IDEA
- * (optional)
- * int "HASH_ALGORYTHM" = Hash Algorithm
- * 1: MD5, 3: RIPEMD-160, 2: SHA-1,
- * 11: SHA-224, 8: SHA-256, 9: SHA-384,
- * 10: SHA-512
- * (optional)
- * Boolean "ARMORED_OUTPUT" = Armor output
- *
- * (optional)
- * Boolean "FORCE_V3_SIGNATURE" = Force V3 Signatures
- *
- * (optional)
- * int "COMPRESSION" = Compression to use
- * 0x21070001: none, 1: Zip, 2: Zlib,
- * 3: BZip2
- * (optional)
- * String "SIGNATURE_KEY" = Key to sign with
- *
- * (optional)
- * String "PRIVATE_KEY_PASSPHRASE" = Passphrase for signing key
- *
- * Bundle returnVals (in addition to the ERRORS/WARNINGS above):
- * If "MESSAGE" was set:
- * String "RESULT" = Encrypted message
- */
-
- /* Additional argument for function below:
- * (required)
- * String "SYMMETRIC_PASSPHRASE" = Symmetric passphrase to use
- */
- boolean encryptWithPassphrase(in Bundle params, out Bundle returnVals);
-
- /* Additional argument:
- * (required)
- * ArrayList "PUBLIC_KEYS" = Public keys (8char fingerprint "123ABC12" OR
- * complete id "Alice Meyer ")
- */
- boolean encryptWithPublicKey(in Bundle params, out Bundle returnVals);
-
- /* ********************************************************
- * Decryption
- * ********************************************************/
-
- /* Bundle params:
- * (required)
- * String "MESSAGE" = Message to dencrypt
- * OR
- * String "BLOB" = ContentUri to a file handle
- * with binary data to dencrypt
- * (Attention: file will be overwritten
- * with dencrypted content!)
- *
- * (optional)
- * String "SYMMETRIC_PASSPHRASE" = Symmetric passphrase for decryption
- *
- * (optional)
- * String "PRIVATE_KEY_PASSPHRASE" = Private keys's passphrase on asymmetric encryption
- *
- * Bundle return_vals:
- * If "MESSAGE" was set:
- * String "RESULT" = Decrypted message
- */
- boolean decrypt(in Bundle params, out Bundle returnVals);
-
- /* ********************************************************
- * Get key information
- * ********************************************************/
-
- /* Get info about all available keys
- *
- * Bundle params:
- * (required)
- * int "KEY_TYPE" = info about what type of keys to return
- * 0: public keys
- * 1: private keys
- *
- * Returns:
- * StringArrayList "FINGERPRINTS" = Short fingerprints of keys
- *
- * StringArrayList "USER_IDS" = User ids of corresponding fingerprints
- * (order is the same as in FINGERPRINTS)
- */
- boolean getKeys(in Bundle params, out Bundle returnVals);
-
-}
\ No newline at end of file
diff --git a/org_apg/src/org/thialfihar/android/apg/ui/BaseActivity.java b/org_apg/src/org/thialfihar/android/apg/ui/BaseActivity.java
index 5310c2fb9..39fc30347 100644
--- a/org_apg/src/org/thialfihar/android/apg/ui/BaseActivity.java
+++ b/org_apg/src/org/thialfihar/android/apg/ui/BaseActivity.java
@@ -21,12 +21,12 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import org.thialfihar.android.apg.R;
-import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Constants;
import org.thialfihar.android.apg.Id;
import org.thialfihar.android.apg.PausableThread;
import org.thialfihar.android.apg.Preferences;
import org.thialfihar.android.apg.ProgressDialogUpdater;
+import org.thialfihar.android.apg.helper.PGPHelper;
import org.thialfihar.android.apg.passphrase.AskForPassphrase;
import org.thialfihar.android.apg.passphrase.PassphraseCacheService;
@@ -79,7 +79,7 @@ public class BaseActivity extends SherlockFragmentActivity implements Runnable,
// not needed later:
mPreferences = Preferences.getPreferences(this);
- Apg.initialize(this);
+ PGPHelper.initialize(this);
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
File dir = new File(Constants.path.APP_DIR);
@@ -275,7 +275,7 @@ public class BaseActivity extends SherlockFragmentActivity implements Runnable,
case Id.request.secret_keys: {
if (resultCode == RESULT_OK) {
Bundle bundle = data.getExtras();
- setSecretKeyId(bundle.getLong(Apg.EXTRA_KEY_ID));
+ setSecretKeyId(bundle.getLong(PGPHelper.EXTRA_KEY_ID));
} else {
setSecretKeyId(Id.key.none);
}
@@ -378,7 +378,7 @@ public class BaseActivity extends SherlockFragmentActivity implements Runnable,
public void passPhraseCallback(long keyId, String passPhrase) {
// TODO: Not needed anymore, now implemented in AskForSecretKeyPass
- Apg.setCachedPassPhrase(keyId, passPhrase);
+ PGPHelper.setCachedPassPhrase(keyId, passPhrase);
}
public void sendMessage(Message msg) {
diff --git a/org_apg/src/org/thialfihar/android/apg/ui/DecryptActivity.java b/org_apg/src/org/thialfihar/android/apg/ui/DecryptActivity.java
index 63adb9826..a19f6c5b6 100644
--- a/org_apg/src/org/thialfihar/android/apg/ui/DecryptActivity.java
+++ b/org_apg/src/org/thialfihar/android/apg/ui/DecryptActivity.java
@@ -19,31 +19,40 @@ package org.thialfihar.android.apg.ui;
import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPPublicKeyRing;
-import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Constants;
-import org.thialfihar.android.apg.DataDestination;
-import org.thialfihar.android.apg.DataSource;
-import org.thialfihar.android.apg.FileDialog;
import org.thialfihar.android.apg.Id;
-import org.thialfihar.android.apg.InputData;
import org.thialfihar.android.apg.PausableThread;
+import org.thialfihar.android.apg.helper.FileHelper;
+import org.thialfihar.android.apg.helper.PGPHelper;
+import org.thialfihar.android.apg.helper.OtherHelper;
+import org.thialfihar.android.apg.helper.PGPHelper.GeneralException;
import org.thialfihar.android.apg.provider.DataProvider;
+import org.thialfihar.android.apg.service.ApgHandler;
+import org.thialfihar.android.apg.service.ApgService;
+import org.thialfihar.android.apg.ui.dialog.DeleteFileDialogFragment;
+import org.thialfihar.android.apg.ui.dialog.FileDialogFragment;
+import org.thialfihar.android.apg.ui.dialog.PassphraseDialogFragment;
+import org.thialfihar.android.apg.ui.dialog.ProgressDialogFragment;
import org.thialfihar.android.apg.util.Compatibility;
-import org.thialfihar.android.apg.util.Utils;
+import org.thialfihar.android.apg.util.InputData;
import org.thialfihar.android.apg.R;
import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import android.app.AlertDialog;
import android.app.Dialog;
+import android.app.ProgressDialog;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Handler;
import android.os.Message;
+import android.os.Messenger;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
@@ -57,8 +66,10 @@ import android.widget.TextView;
import android.widget.Toast;
import android.widget.ViewFlipper;
+import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
@@ -67,7 +78,7 @@ import java.security.Security;
import java.security.SignatureException;
import java.util.regex.Matcher;
-public class DecryptActivity extends BaseActivity {
+public class DecryptActivity extends SherlockFragmentActivity {
private long mSignatureKeyId = 0;
private Intent mIntent;
@@ -110,11 +121,24 @@ public class DecryptActivity extends BaseActivity {
private byte[] mData = null;
private boolean mReturnBinary = false;
- private DataSource mDataSource = null;
- private DataDestination mDataDestination = null;
+ // private DataSource mDataSource = null;
+ // private DataDestination mDataDestination = null;
private long mUnknownSignatureKeyId = 0;
+ private long mSecretKeyId = Id.key.none;
+
+ private ProgressDialogFragment mDecryptingDialog;
+ private FileDialogFragment mFileDialog;
+
+ public void setSecretKeyId(long id) {
+ mSecretKeyId = id;
+ }
+
+ public long getSecretKeyId() {
+ return mSecretKeyId;
+ }
+
@Override
public boolean onCreateOptionsMenu(Menu menu) {
@@ -163,6 +187,18 @@ public class DecryptActivity extends BaseActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.decrypt);
+ // set actionbar without home button if called from another app
+ final ActionBar actionBar = getSupportActionBar();
+ Log.d(Constants.TAG, "calling package (only set when using startActivityForResult)="
+ + getCallingPackage());
+ if (getCallingPackage() != null && getCallingPackage().equals(PGPHelper.PACKAGE_NAME)) {
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setHomeButtonEnabled(true);
+ } else {
+ actionBar.setDisplayHomeAsUpEnabled(false);
+ actionBar.setHomeButtonEnabled(false);
+ }
+
mSource = (ViewFlipper) findViewById(R.id.source);
mSourceLabel = (TextView) findViewById(R.id.sourceLabel);
mSourcePrevious = (ImageView) findViewById(R.id.sourcePrevious);
@@ -213,7 +249,7 @@ public class DecryptActivity extends BaseActivity {
mBrowse = (ImageButton) findViewById(R.id.btn_browse);
mBrowse.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
- Utils.openFile(DecryptActivity.this, mFilename.getText().toString(), "*/*",
+ FileHelper.openFile(DecryptActivity.this, mFilename.getText().toString(), "*/*",
Id.request.filename);
}
});
@@ -246,7 +282,7 @@ public class DecryptActivity extends BaseActivity {
} catch (IOException e) {
// ignore, then
}
- } else if (Apg.Intent.DECRYPT.equals(mIntent.getAction())) {
+ } else if (PGPHelper.Intent.DECRYPT.equals(mIntent.getAction())) {
Log.d(Constants.TAG, "Apg Intent DECRYPT startet");
Bundle extras = mIntent.getExtras();
if (extras == null) {
@@ -256,17 +292,17 @@ public class DecryptActivity extends BaseActivity {
Log.d(Constants.TAG, "got extras");
}
- mData = extras.getByteArray(Apg.EXTRA_DATA);
+ mData = extras.getByteArray(PGPHelper.EXTRA_DATA);
String textData = null;
if (mData == null) {
Log.d(Constants.TAG, "EXTRA_DATA was null");
- textData = extras.getString(Apg.EXTRA_TEXT);
+ textData = extras.getString(PGPHelper.EXTRA_TEXT);
} else {
Log.d(Constants.TAG, "Got data from EXTRA_DATA");
}
if (textData != null) {
Log.d(Constants.TAG, "textData null, matching text ...");
- Matcher matcher = Apg.PGP_MESSAGE.matcher(textData);
+ Matcher matcher = PGPHelper.PGP_MESSAGE.matcher(textData);
if (matcher.matches()) {
Log.d(Constants.TAG, "PGP_MESSAGE matched");
textData = matcher.group(1);
@@ -274,7 +310,7 @@ public class DecryptActivity extends BaseActivity {
textData = textData.replaceAll("\\xa0", " ");
mMessage.setText(textData);
} else {
- matcher = Apg.PGP_SIGNED_MESSAGE.matcher(textData);
+ matcher = PGPHelper.PGP_SIGNED_MESSAGE.matcher(textData);
if (matcher.matches()) {
Log.d(Constants.TAG, "PGP_SIGNED_MESSAGE matched");
textData = matcher.group(1);
@@ -290,9 +326,9 @@ public class DecryptActivity extends BaseActivity {
}
}
}
- mReplyTo = extras.getString(Apg.EXTRA_REPLY_TO);
- mSubject = extras.getString(Apg.EXTRA_SUBJECT);
- } else if (Apg.Intent.DECRYPT_FILE.equals(mIntent.getAction())) {
+ mReplyTo = extras.getString(PGPHelper.EXTRA_REPLY_TO);
+ mSubject = extras.getString(PGPHelper.EXTRA_SUBJECT);
+ } else if (PGPHelper.Intent.DECRYPT_FILE.equals(mIntent.getAction())) {
mInputFilename = mIntent.getDataString();
if ("file".equals(mIntent.getScheme())) {
mInputFilename = Uri.decode(mInputFilename.substring(7));
@@ -304,37 +340,27 @@ public class DecryptActivity extends BaseActivity {
while (mSource.getCurrentView().getId() != R.id.sourceFile) {
mSource.showNext();
}
- } else if (Apg.Intent.DECRYPT_AND_RETURN.equals(mIntent.getAction())) {
+ } else if (PGPHelper.Intent.DECRYPT_AND_RETURN.equals(mIntent.getAction())) {
mContentUri = mIntent.getData();
Bundle extras = mIntent.getExtras();
if (extras == null) {
extras = new Bundle();
}
- // set actionbar without home button if called from another app
- final ActionBar actionBar = getSupportActionBar();
- if (getCallingPackage() != null && getCallingPackage().equals(Apg.PACKAGE_NAME)) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setHomeButtonEnabled(true);
- } else {
- actionBar.setDisplayHomeAsUpEnabled(false);
- actionBar.setHomeButtonEnabled(false);
- }
-
- mReturnBinary = extras.getBoolean(Apg.EXTRA_BINARY, false);
+ mReturnBinary = extras.getBoolean(PGPHelper.EXTRA_BINARY, false);
if (mContentUri == null) {
- mData = extras.getByteArray(Apg.EXTRA_DATA);
- String data = extras.getString(Apg.EXTRA_TEXT);
+ mData = extras.getByteArray(PGPHelper.EXTRA_DATA);
+ String data = extras.getString(PGPHelper.EXTRA_TEXT);
if (data != null) {
- Matcher matcher = Apg.PGP_MESSAGE.matcher(data);
+ Matcher matcher = PGPHelper.PGP_MESSAGE.matcher(data);
if (matcher.matches()) {
data = matcher.group(1);
// replace non breakable spaces
data = data.replaceAll("\\xa0", " ");
mMessage.setText(data);
} else {
- matcher = Apg.PGP_SIGNED_MESSAGE.matcher(data);
+ matcher = PGPHelper.PGP_SIGNED_MESSAGE.matcher(data);
if (matcher.matches()) {
data = matcher.group(1);
// replace non breakable spaces
@@ -358,9 +384,9 @@ public class DecryptActivity extends BaseActivity {
String data = "";
if (clipboardText != null) {
- Matcher matcher = Apg.PGP_MESSAGE.matcher(clipboardText);
+ Matcher matcher = PGPHelper.PGP_MESSAGE.matcher(clipboardText);
if (!matcher.matches()) {
- matcher = Apg.PGP_SIGNED_MESSAGE.matcher(clipboardText);
+ matcher = PGPHelper.PGP_SIGNED_MESSAGE.matcher(clipboardText);
}
if (matcher.matches()) {
data = matcher.group(1);
@@ -376,11 +402,11 @@ public class DecryptActivity extends BaseActivity {
if (mSignatureKeyId == 0) {
return;
}
- PGPPublicKeyRing key = Apg.getPublicKeyRing(mSignatureKeyId);
+ PGPPublicKeyRing key = PGPHelper.getPublicKeyRing(mSignatureKeyId);
if (key != null) {
Intent intent = new Intent(DecryptActivity.this, KeyServerQueryActivity.class);
- intent.setAction(Apg.Intent.LOOK_UP_KEY_ID);
- intent.putExtra(Apg.EXTRA_KEY_ID, mSignatureKeyId);
+ intent.setAction(PGPHelper.Intent.LOOK_UP_KEY_ID);
+ intent.putExtra(PGPHelper.EXTRA_KEY_ID, mSignatureKeyId);
startActivity(intent);
}
}
@@ -483,7 +509,7 @@ public class DecryptActivity extends BaseActivity {
if (mDecryptTarget == Id.target.message) {
String messageData = mMessage.getText().toString();
- Matcher matcher = Apg.PGP_SIGNED_MESSAGE.matcher(messageData);
+ Matcher matcher = PGPHelper.PGP_SIGNED_MESSAGE.matcher(messageData);
if (matcher.matches()) {
mSignedOnly = true;
decryptStart();
@@ -493,248 +519,466 @@ public class DecryptActivity extends BaseActivity {
// else treat it as an decrypted message/file
mSignedOnly = false;
- String error = null;
- fillDataSource();
+
+ getDecryptionKeyFromInputStream();
+
+ Log.d(Constants.TAG, "secretKeyId: " + getSecretKeyId());
+
+ // if we need a symmetric passphrase or a passphrase to use a sekret key ask for it
+ if (getSecretKeyId() == Id.key.symmetric
+ || PGPHelper.getCachedPassPhrase(getSecretKeyId()) == null) {
+ // showDialog(Id.dialog.pass_phrase);
+ showPassphraseDialog();
+ } else {
+ if (mDecryptTarget == Id.target.file) {
+ askForOutputFilename();
+ } else {
+ decryptStart();
+ }
+ }
+ }
+
+ /**
+ * Shows passphrase dialog to cache a new passphrase the user enters for using it later for
+ * encryption. Based on mSecretKeyId it asks for a passphrase to open a private key or it asks
+ * for a symmetric passphrase
+ */
+ private void showPassphraseDialog() {
+ // Message is received after passphrase is cached
+ Handler returnHandler = new Handler() {
+ @Override
+ public void handleMessage(Message message) {
+ if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
+ if (mDecryptTarget == Id.target.file) {
+ askForOutputFilename();
+ } else {
+ decryptStart();
+ }
+ }
+ }
+ };
+
+ // Create a new Messenger for the communication back
+ Messenger messenger = new Messenger(returnHandler);
+
try {
- InputData in = mDataSource.getInputData(this, false);
+ PassphraseDialogFragment passphraseDialog = PassphraseDialogFragment.newInstance(
+ messenger, mSecretKeyId);
+
+ passphraseDialog.show(getSupportFragmentManager(), "passphraseDialog");
+ } catch (PGPHelper.GeneralException e) {
+ Log.d(Constants.TAG, "No passphrase for this secret key, encrypt directly!");
+ // send message to handler to start encryption directly
+ returnHandler.sendEmptyMessage(PassphraseDialogFragment.MESSAGE_OKAY);
+ }
+ }
+
+ /**
+ * TODO: externalize this into ApgService???
+ */
+ private void getDecryptionKeyFromInputStream() {
+ InputStream inStream = null;
+ if (mContentUri != null) {
+ try {
+ inStream = getContentResolver().openInputStream(mContentUri);
+ } catch (FileNotFoundException e) {
+ Log.e(Constants.TAG, "File not found!", e);
+ Toast.makeText(this, getString(R.string.error_fileNotFound, e.getMessage()),
+ Toast.LENGTH_SHORT).show();
+ }
+ } else if (mDecryptTarget == Id.target.file) {
+ // check if storage is ready
+ if (!FileHelper.isStorageMounted(mInputFilename)) {
+ Toast.makeText(this, getString(R.string.error_externalStorageNotReady),
+ Toast.LENGTH_SHORT).show();
+ return;
+ }
+
try {
- setSecretKeyId(Apg.getDecryptionKeyId(this, in));
+ inStream = new FileInputStream(mInputFilename);
+ } catch (FileNotFoundException e) {
+ Log.e(Constants.TAG, "File not found!", e);
+ Toast.makeText(this, getString(R.string.error_fileNotFound, e.getMessage()),
+ Toast.LENGTH_SHORT).show();
+ }
+ } else {
+ if (mData != null) {
+ inStream = new ByteArrayInputStream(mData);
+ } else {
+ inStream = new ByteArrayInputStream(mMessage.getText().toString().getBytes());
+
+ }
+ }
+
+ try {
+ try {
+ setSecretKeyId(PGPHelper.getDecryptionKeyId(this, inStream));
if (getSecretKeyId() == Id.key.none) {
- throw new Apg.GeneralException(getString(R.string.error_noSecretKeyFound));
+ throw new PGPHelper.GeneralException(getString(R.string.error_noSecretKeyFound));
}
mAssumeSymmetricEncryption = false;
- } catch (Apg.NoAsymmetricEncryptionException e) {
+ } catch (PGPHelper.NoAsymmetricEncryptionException e) {
setSecretKeyId(Id.key.symmetric);
- in = mDataSource.getInputData(this, false);
- if (!Apg.hasSymmetricEncryption(this, in)) {
- throw new Apg.GeneralException(getString(R.string.error_noKnownEncryptionFound));
+ if (!PGPHelper.hasSymmetricEncryption(this, inStream)) {
+ throw new PGPHelper.GeneralException(
+ getString(R.string.error_noKnownEncryptionFound));
}
mAssumeSymmetricEncryption = true;
}
-
- if (getSecretKeyId() == Id.key.symmetric
- || Apg.getCachedPassPhrase(getSecretKeyId()) == null) {
- showDialog(Id.dialog.pass_phrase);
- } else {
- if (mDecryptTarget == Id.target.file) {
- askForOutputFilename();
- } else {
- decryptStart();
- }
- }
- } catch (FileNotFoundException e) {
- error = getString(R.string.error_fileNotFound);
- } catch (IOException e) {
- error = "" + e;
- } catch (Apg.GeneralException e) {
- error = "" + e;
- }
- if (error != null) {
- Toast.makeText(this, getString(R.string.errorMessage, error), Toast.LENGTH_SHORT)
- .show();
+ } catch (Exception e) {
+ Toast.makeText(this, getString(R.string.errorMessage, e.getMessage()),
+ Toast.LENGTH_SHORT).show();
}
}
private void replyClicked() {
Intent intent = new Intent(this, EncryptActivity.class);
- intent.setAction(Apg.Intent.ENCRYPT);
+ intent.setAction(PGPHelper.Intent.ENCRYPT);
String data = mMessage.getText().toString();
data = data.replaceAll("(?m)^", "> ");
data = "\n\n" + data;
- intent.putExtra(Apg.EXTRA_TEXT, data);
- intent.putExtra(Apg.EXTRA_SUBJECT, "Re: " + mSubject);
- intent.putExtra(Apg.EXTRA_SEND_TO, mReplyTo);
- intent.putExtra(Apg.EXTRA_SIGNATURE_KEY_ID, getSecretKeyId());
- intent.putExtra(Apg.EXTRA_ENCRYPTION_KEY_IDS, new long[] { mSignatureKeyId });
+ intent.putExtra(PGPHelper.EXTRA_TEXT, data);
+ intent.putExtra(PGPHelper.EXTRA_SUBJECT, "Re: " + mSubject);
+ intent.putExtra(PGPHelper.EXTRA_SEND_TO, mReplyTo);
+ intent.putExtra(PGPHelper.EXTRA_SIGNATURE_KEY_ID, getSecretKeyId());
+ intent.putExtra(PGPHelper.EXTRA_ENCRYPTION_KEY_IDS, new long[] { mSignatureKeyId });
startActivity(intent);
}
private void askForOutputFilename() {
- showDialog(Id.dialog.output_filename);
- }
+ // Message is received after passphrase is cached
+ Handler returnHandler = new Handler() {
+ @Override
+ public void handleMessage(Message message) {
+ if (message.what == FileDialogFragment.MESSAGE_OKAY) {
+ Bundle data = message.getData();
+ mOutputFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME);
+ decryptStart();
+ }
+ }
+ };
+
+ // Create a new Messenger for the communication back
+ Messenger messenger = new Messenger(returnHandler);
+
+ mFileDialog = FileDialogFragment.newInstance(messenger,
+ getString(R.string.title_decryptToFile),
+ getString(R.string.specifyFileToDecryptTo), mOutputFilename, null,
+ Id.request.output_filename);
+
+ mFileDialog.show(getSupportFragmentManager(), "fileDialog");
- @Override
- public void passPhraseCallback(long keyId, String passPhrase) {
- super.passPhraseCallback(keyId, passPhrase);
- if (mDecryptTarget == Id.target.file) {
- askForOutputFilename();
- } else {
- decryptStart();
- }
}
private void decryptStart() {
- showDialog(Id.dialog.decrypting);
- startThread();
- }
+ Log.d(Constants.TAG, "decryptStart");
- @Override
- public void run() {
- String error = null;
- Security.addProvider(new BouncyCastleProvider());
+ // Send all information needed to service to edit key in other thread
+ Intent intent = new Intent(this, ApgService.class);
+ // fill values for this action
Bundle data = new Bundle();
- Message msg = new Message();
- fillDataSource();
- fillDataDestination();
- try {
- InputData in = mDataSource.getInputData(this, true);
- OutputStream out = mDataDestination.getOutputStream(this);
- if (mSignedOnly) {
- data = Apg.verifyText(this, in, out, this);
- } else {
- data = Apg.decrypt(this, in, out, Apg.getCachedPassPhrase(getSecretKeyId()), this,
- mAssumeSymmetricEncryption);
- }
+ // choose action based on input: decrypt stream, file or bytes
+ if (mContentUri != null) {
+ intent.putExtra(ApgService.EXTRA_ACTION, ApgService.ACTION_DECRYPT_STREAM);
+ data.putString(ApgService.PROVIDER_URI, mContentUri.toString());
- out.close();
+ } else if (mDecryptTarget == Id.target.file) {
+ intent.putExtra(ApgService.EXTRA_ACTION, ApgService.ACTION_DECRYPT_FILE);
- if (mDataDestination.getStreamFilename() != null) {
- data.putString(Apg.EXTRA_RESULT_URI, "content://" + DataProvider.AUTHORITY
- + "/data/" + mDataDestination.getStreamFilename());
- } else if (mDecryptTarget == Id.target.message) {
- if (mReturnBinary) {
- data.putByteArray(Apg.EXTRA_DECRYPTED_DATA,
- ((ByteArrayOutputStream) out).toByteArray());
- } else {
- data.putString(Apg.EXTRA_DECRYPTED_MESSAGE, new String(
- ((ByteArrayOutputStream) out).toByteArray()));
- }
+ Log.d(Constants.TAG, "mInputFilename=" + mInputFilename + ", mOutputFilename="
+ + mOutputFilename);
+
+ data.putString(ApgService.INPUT_FILE, mInputFilename);
+ data.putString(ApgService.OUTPUT_FILE, mOutputFilename);
+
+ } else {
+ intent.putExtra(ApgService.EXTRA_ACTION, ApgService.ACTION_DECRYPT_BYTES);
+
+ if (mData != null) {
+ data.putByteArray(ApgService.CIPHERTEXT_BYTES, mData);
+ } else {
+ String message = mMessage.getText().toString();
+ data.putByteArray(ApgService.CIPHERTEXT_BYTES, message.getBytes());
}
- } catch (PGPException e) {
- error = "" + e;
- } catch (IOException e) {
- error = "" + e;
- } catch (SignatureException e) {
- error = "" + e;
- } catch (Apg.GeneralException e) {
- error = "" + e;
}
- data.putInt(Constants.extras.STATUS, Id.message.done);
+ data.putLong(ApgService.SECRET_KEY_ID, getSecretKeyId());
- if (error != null) {
- data.putString(Apg.EXTRA_ERROR, error);
- }
+ data.putBoolean(ApgService.SIGNED_ONLY, mSignedOnly);
+ data.putBoolean(ApgService.RETURN_BYTES, mReturnBinary);
+ data.putBoolean(ApgService.ASSUME_SYMMETRIC, mAssumeSymmetricEncryption);
- msg.setData(data);
- sendMessage(msg);
- }
+ intent.putExtra(ApgService.EXTRA_DATA, data);
- @Override
- public void handlerCallback(Message msg) {
- Bundle data = msg.getData();
- if (data == null) {
- return;
- }
+ // create progress dialog
+ mDecryptingDialog = ProgressDialogFragment.newInstance(R.string.progress_decrypting,
+ ProgressDialog.STYLE_HORIZONTAL);
- if (data.getInt(Constants.extras.STATUS) == Id.message.unknown_signature_key) {
- mUnknownSignatureKeyId = data.getLong(Constants.extras.KEY_ID);
- showDialog(Id.dialog.lookup_unknown_key);
- return;
- }
+ // Message is received after encrypting is done in ApgService
+ ApgHandler saveHandler = new ApgHandler(this, mDecryptingDialog) {
+ public void handleMessage(Message message) {
+ // handle messages by standard ApgHandler first
+ super.handleMessage(message);
- super.handlerCallback(msg);
- }
+ if (message.arg1 == ApgHandler.MESSAGE_OKAY) {
+ // get returned data bundle
+ Bundle data = message.getData();
- @Override
- public void doneCallback(Message msg) {
- super.doneCallback(msg);
+ mSignatureKeyId = 0;
+ mSignatureLayout.setVisibility(View.GONE);
+ mReplyEnabled = false;
- Bundle data = msg.getData();
- removeDialog(Id.dialog.decrypting);
- mSignatureKeyId = 0;
- mSignatureLayout.setVisibility(View.GONE);
- mReplyEnabled = false;
+ // build new action bar
+ invalidateOptionsMenu();
- // build new action bar
- invalidateOptionsMenu();
+ Toast.makeText(DecryptActivity.this, R.string.decryptionSuccessful,
+ Toast.LENGTH_SHORT).show();
+ if (mReturnResult) {
+ Intent intent = new Intent();
+ intent.putExtras(data);
+ setResult(RESULT_OK, intent);
+ finish();
+ return;
+ }
- String error = data.getString(Apg.EXTRA_ERROR);
- if (error != null) {
- Toast.makeText(this, getString(R.string.errorMessage, error), Toast.LENGTH_SHORT)
- .show();
- return;
- }
+ switch (mDecryptTarget) {
+ case Id.target.message: {
+ String decryptedMessage = data
+ .getString(ApgService.RESULT_DECRYPTED_MESSAGE);
+ mMessage.setText(decryptedMessage);
+ mMessage.setHorizontallyScrolling(false);
+ mReplyEnabled = false;
- Toast.makeText(this, R.string.decryptionSuccessful, Toast.LENGTH_SHORT).show();
- if (mReturnResult) {
- Intent intent = new Intent();
- intent.putExtras(data);
- setResult(RESULT_OK, intent);
- finish();
- return;
- }
+ // build new action bar
+ invalidateOptionsMenu();
+ break;
+ }
- switch (mDecryptTarget) {
- case Id.target.message: {
- String decryptedMessage = data.getString(Apg.EXTRA_DECRYPTED_MESSAGE);
- mMessage.setText(decryptedMessage);
- mMessage.setHorizontallyScrolling(false);
- mReplyEnabled = false;
+ case Id.target.file: {
+ if (mDeleteAfter.isChecked()) {
+ // Create and show dialog to delete original file
+ DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment
+ .newInstance(mInputFilename);
+ deleteFileDialog.show(getSupportFragmentManager(), "deleteDialog");
+ }
+ break;
+ }
- // build new action bar
- invalidateOptionsMenu();
- break;
- }
+ default: {
+ // shouldn't happen
+ break;
+ }
+ }
- case Id.target.file: {
- if (mDeleteAfter.isChecked()) {
- setDeleteFile(mInputFilename);
- showDialog(Id.dialog.delete_file);
- }
- break;
- }
+ if (data.getBoolean(ApgService.EXTRA_SIGNATURE)) {
+ String userId = data.getString(ApgService.EXTRA_SIGNATURE_USER_ID);
+ mSignatureKeyId = data.getLong(ApgService.EXTRA_SIGNATURE_KEY_ID);
+ mUserIdRest
+ .setText("id: " + PGPHelper.getSmallFingerPrint(mSignatureKeyId));
+ if (userId == null) {
+ userId = getResources().getString(R.string.unknownUserId);
+ }
+ String chunks[] = userId.split(" <", 2);
+ userId = chunks[0];
+ if (chunks.length > 1) {
+ mUserIdRest.setText("<" + chunks[1]);
+ }
+ mUserId.setText(userId);
+
+ if (data.getBoolean(ApgService.EXTRA_SIGNATURE_SUCCESS)) {
+ mSignatureStatusImage.setImageResource(R.drawable.overlay_ok);
+ } else if (data.getBoolean(ApgService.EXTRA_SIGNATURE_UNKNOWN)) {
+ mSignatureStatusImage.setImageResource(R.drawable.overlay_error);
+ Toast.makeText(DecryptActivity.this,
+ R.string.unknownSignatureKeyTouchToLookUp, Toast.LENGTH_LONG)
+ .show();
+ } else {
+ mSignatureStatusImage.setImageResource(R.drawable.overlay_error);
+ }
+ mSignatureLayout.setVisibility(View.VISIBLE);
+ }
+ }
+ };
+ };
- default: {
- // shouldn't happen
- break;
- }
- }
+ // Create a new Messenger for the communication back
+ Messenger messenger = new Messenger(saveHandler);
+ intent.putExtra(ApgService.EXTRA_MESSENGER, messenger);
- if (data.getBoolean(Apg.EXTRA_SIGNATURE)) {
- String userId = data.getString(Apg.EXTRA_SIGNATURE_USER_ID);
- mSignatureKeyId = data.getLong(Apg.EXTRA_SIGNATURE_KEY_ID);
- mUserIdRest.setText("id: " + Apg.getSmallFingerPrint(mSignatureKeyId));
- if (userId == null) {
- userId = getResources().getString(R.string.unknownUserId);
- }
- String chunks[] = userId.split(" <", 2);
- userId = chunks[0];
- if (chunks.length > 1) {
- mUserIdRest.setText("<" + chunks[1]);
- }
- mUserId.setText(userId);
-
- if (data.getBoolean(Apg.EXTRA_SIGNATURE_SUCCESS)) {
- mSignatureStatusImage.setImageResource(R.drawable.overlay_ok);
- } else if (data.getBoolean(Apg.EXTRA_SIGNATURE_UNKNOWN)) {
- mSignatureStatusImage.setImageResource(R.drawable.overlay_error);
- Toast.makeText(this, R.string.unknownSignatureKeyTouchToLookUp, Toast.LENGTH_LONG)
- .show();
- } else {
- mSignatureStatusImage.setImageResource(R.drawable.overlay_error);
- }
- mSignatureLayout.setVisibility(View.VISIBLE);
- }
+ // show progress dialog
+ mDecryptingDialog.show(getSupportFragmentManager(), "decryptingDialog");
+
+ // start service with intent
+ startService(intent);
}
+ // @Override
+ // public void run() {
+ // String error = null;
+ // Security.addProvider(new BouncyCastleProvider());
+ //
+ // Bundle data = new Bundle();
+ // Message msg = new Message();
+ // fillDataSource();
+ // fillDataDestination();
+ // try {
+ // InputData in = mDataSource.getInputData(this, true);
+ // OutputStream out = mDataDestination.getOutputStream(this);
+ //
+ // if (mSignedOnly) {
+ // data = Apg.verifyText(this, in, out, this);
+ // } else {
+ // data = Apg.decrypt(this, in, out, Apg.getCachedPassPhrase(getSecretKeyId()), this,
+ // mAssumeSymmetricEncryption);
+ // }
+ //
+ // out.close();
+ //
+ // if (mDataDestination.getStreamFilename() != null) {
+ // data.putString(Apg.EXTRA_RESULT_URI, "content://" + DataProvider.AUTHORITY
+ // + "/data/" + mDataDestination.getStreamFilename());
+ // } else if (mDecryptTarget == Id.target.message) {
+ // if (mReturnBinary) {
+ // data.putByteArray(Apg.EXTRA_DECRYPTED_DATA,
+ // ((ByteArrayOutputStream) out).toByteArray());
+ // } else {
+ // data.putString(Apg.EXTRA_DECRYPTED_MESSAGE, new String(
+ // ((ByteArrayOutputStream) out).toByteArray()));
+ // }
+ // }
+ // } catch (PGPException e) {
+ // error = "" + e;
+ // } catch (IOException e) {
+ // error = "" + e;
+ // } catch (SignatureException e) {
+ // error = "" + e;
+ // } catch (Apg.GeneralException e) {
+ // error = "" + e;
+ // }
+ //
+ // data.putInt(Constants.extras.STATUS, Id.message.done);
+ //
+ // if (error != null) {
+ // data.putString(Apg.EXTRA_ERROR, error);
+ // }
+ //
+ // msg.setData(data);
+ // sendMessage(msg);
+ // }
+ //
+ // @Override
+ // public void handlerCallback(Message msg) {
+ // Bundle data = msg.getData();
+ // if (data == null) {
+ // return;
+ // }
+ //
+ // if (data.getInt(Constants.extras.STATUS) == Id.message.unknown_signature_key) {
+ // mUnknownSignatureKeyId = data.getLong(Constants.extras.KEY_ID);
+ // showDialog(Id.dialog.lookup_unknown_key);
+ // return;
+ // }
+ //
+ // super.handlerCallback(msg);
+ // }
+ //
+ // @Override
+ // public void doneCallback(Message msg) {
+ // super.doneCallback(msg);
+ //
+ // Bundle data = msg.getData();
+ // removeDialog(Id.dialog.decrypting);
+ // mSignatureKeyId = 0;
+ // mSignatureLayout.setVisibility(View.GONE);
+ // mReplyEnabled = false;
+ //
+ // // build new action bar
+ // invalidateOptionsMenu();
+ //
+ // String error = data.getString(Apg.EXTRA_ERROR);
+ // if (error != null) {
+ // Toast.makeText(this, getString(R.string.errorMessage, error), Toast.LENGTH_SHORT)
+ // .show();
+ // return;
+ // }
+ //
+ // Toast.makeText(this, R.string.decryptionSuccessful, Toast.LENGTH_SHORT).show();
+ // if (mReturnResult) {
+ // Intent intent = new Intent();
+ // intent.putExtras(data);
+ // setResult(RESULT_OK, intent);
+ // finish();
+ // return;
+ // }
+ //
+ // switch (mDecryptTarget) {
+ // case Id.target.message: {
+ // String decryptedMessage = data.getString(Apg.EXTRA_DECRYPTED_MESSAGE);
+ // mMessage.setText(decryptedMessage);
+ // mMessage.setHorizontallyScrolling(false);
+ // mReplyEnabled = false;
+ //
+ // // build new action bar
+ // invalidateOptionsMenu();
+ // break;
+ // }
+ //
+ // case Id.target.file: {
+ // if (mDeleteAfter.isChecked()) {
+ // //TODO
+ // // setDeleteFile(mInputFilename);
+ // // showDialog(Id.dialog.delete_file);
+ // }
+ // break;
+ // }
+ //
+ // default: {
+ // // shouldn't happen
+ // break;
+ // }
+ // }
+ //
+ // if (data.getBoolean(Apg.EXTRA_SIGNATURE)) {
+ // String userId = data.getString(Apg.EXTRA_SIGNATURE_USER_ID);
+ // mSignatureKeyId = data.getLong(Apg.EXTRA_SIGNATURE_KEY_ID);
+ // mUserIdRest.setText("id: " + Apg.getSmallFingerPrint(mSignatureKeyId));
+ // if (userId == null) {
+ // userId = getResources().getString(R.string.unknownUserId);
+ // }
+ // String chunks[] = userId.split(" <", 2);
+ // userId = chunks[0];
+ // if (chunks.length > 1) {
+ // mUserIdRest.setText("<" + chunks[1]);
+ // }
+ // mUserId.setText(userId);
+ //
+ // if (data.getBoolean(Apg.EXTRA_SIGNATURE_SUCCESS)) {
+ // mSignatureStatusImage.setImageResource(R.drawable.overlay_ok);
+ // } else if (data.getBoolean(Apg.EXTRA_SIGNATURE_UNKNOWN)) {
+ // mSignatureStatusImage.setImageResource(R.drawable.overlay_error);
+ // Toast.makeText(this, R.string.unknownSignatureKeyTouchToLookUp, Toast.LENGTH_LONG)
+ // .show();
+ // } else {
+ // mSignatureStatusImage.setImageResource(R.drawable.overlay_error);
+ // }
+ // mSignatureLayout.setVisibility(View.VISIBLE);
+ // }
+ // }
+
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case Id.request.filename: {
if (resultCode == RESULT_OK && data != null) {
- String filename = data.getDataString();
- if (filename != null) {
- // Get rid of URI prefix:
- if (filename.startsWith("file://")) {
- filename = filename.substring(7);
- }
- // replace %20 and so on
- filename = Uri.decode(filename);
+ try {
+ String path = data.getData().getPath();
+ Log.d(Constants.TAG, "path=" + path);
- mFilename.setText(filename);
+ mFilename.setText(path);
+ } catch (NullPointerException e) {
+ Log.e(Constants.TAG, "Nullpointer while retrieving path!");
}
}
return;
@@ -742,26 +986,24 @@ public class DecryptActivity extends BaseActivity {
case Id.request.output_filename: {
if (resultCode == RESULT_OK && data != null) {
- String filename = data.getDataString();
- if (filename != null) {
- // Get rid of URI prefix:
- if (filename.startsWith("file://")) {
- filename = filename.substring(7);
- }
- // replace %20 and so on
- filename = Uri.decode(filename);
+ try {
+ String path = data.getData().getPath();
+ Log.d(Constants.TAG, "path=" + path);
- FileDialog.setFilename(filename);
+ mFileDialog.setFilename(path);
+ } catch (NullPointerException e) {
+ Log.e(Constants.TAG, "Nullpointer while retrieving path!");
}
}
return;
}
case Id.request.look_up_key_id: {
- PausableThread thread = getRunningThread();
- if (thread != null && thread.isPaused()) {
- thread.unpause();
- }
+ // TODO
+ // PausableThread thread = getRunningThread();
+ // if (thread != null && thread.isPaused()) {
+ // thread.unpause();
+ // }
return;
}
@@ -776,22 +1018,22 @@ public class DecryptActivity extends BaseActivity {
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
- case Id.dialog.output_filename: {
- return FileDialog.build(this, getString(R.string.title_decryptToFile),
- getString(R.string.specifyFileToDecryptTo), mOutputFilename,
- new FileDialog.OnClickListener() {
- public void onOkClick(String filename, boolean checked) {
- removeDialog(Id.dialog.output_filename);
- mOutputFilename = filename;
- decryptStart();
- }
-
- public void onCancelClick() {
- removeDialog(Id.dialog.output_filename);
- }
- }, getString(R.string.filemanager_titleSave),
- getString(R.string.filemanager_btnSave), null, Id.request.output_filename);
- }
+ // case Id.dialog.output_filename: {
+ // return FileDialog.build(this, getString(R.string.title_decryptToFile),
+ // getString(R.string.specifyFileToDecryptTo), mOutputFilename,
+ // new FileDialog.OnClickListener() {
+ // public void onOkClick(String filename, boolean checked) {
+ // removeDialog(Id.dialog.output_filename);
+ // mOutputFilename = filename;
+ // decryptStart();
+ // }
+ //
+ // public void onCancelClick() {
+ // removeDialog(Id.dialog.output_filename);
+ // }
+ // }, getString(R.string.filemanager_titleSave),
+ // getString(R.string.filemanager_btnSave), null, Id.request.output_filename);
+ // }
case Id.dialog.lookup_unknown_key: {
AlertDialog.Builder alert = new AlertDialog.Builder(this);
@@ -799,24 +1041,25 @@ public class DecryptActivity extends BaseActivity {
alert.setIcon(android.R.drawable.ic_dialog_alert);
alert.setTitle(R.string.title_unknownSignatureKey);
alert.setMessage(getString(R.string.lookupUnknownKey,
- Apg.getSmallFingerPrint(mUnknownSignatureKeyId)));
+ PGPHelper.getSmallFingerPrint(mUnknownSignatureKeyId)));
alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
removeDialog(Id.dialog.lookup_unknown_key);
Intent intent = new Intent(DecryptActivity.this, KeyServerQueryActivity.class);
- intent.setAction(Apg.Intent.LOOK_UP_KEY_ID);
- intent.putExtra(Apg.EXTRA_KEY_ID, mUnknownSignatureKeyId);
+ intent.setAction(PGPHelper.Intent.LOOK_UP_KEY_ID);
+ intent.putExtra(PGPHelper.EXTRA_KEY_ID, mUnknownSignatureKeyId);
startActivityForResult(intent, Id.request.look_up_key_id);
}
});
alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
removeDialog(Id.dialog.lookup_unknown_key);
- PausableThread thread = getRunningThread();
- if (thread != null && thread.isPaused()) {
- thread.unpause();
- }
+ // TODO
+ // PausableThread thread = getRunningThread();
+ // if (thread != null && thread.isPaused()) {
+ // thread.unpause();
+ // }
}
});
alert.setCancelable(true);
@@ -831,31 +1074,4 @@ public class DecryptActivity extends BaseActivity {
return super.onCreateDialog(id);
}
-
- protected void fillDataSource() {
- mDataSource = new DataSource();
- if (mContentUri != null) {
- mDataSource.setUri(mContentUri);
- } else if (mDecryptTarget == Id.target.file) {
- mDataSource.setUri(mInputFilename);
- } else {
- if (mData != null) {
- mDataSource.setData(mData);
- } else {
- mDataSource.setText(mMessage.getText().toString());
- }
- }
- }
-
- protected void fillDataDestination() {
- mDataDestination = new DataDestination();
- if (mContentUri != null) {
- mDataDestination.setMode(Id.mode.stream);
- } else if (mDecryptTarget == Id.target.file) {
- mDataDestination.setFilename(mOutputFilename);
- mDataDestination.setMode(Id.mode.file);
- } else {
- mDataDestination.setMode(Id.mode.byte_array);
- }
- }
}
diff --git a/org_apg/src/org/thialfihar/android/apg/ui/EditKeyActivity.java b/org_apg/src/org/thialfihar/android/apg/ui/EditKeyActivity.java
index ab3956abc..7870a80c3 100644
--- a/org_apg/src/org/thialfihar/android/apg/ui/EditKeyActivity.java
+++ b/org_apg/src/org/thialfihar/android/apg/ui/EditKeyActivity.java
@@ -19,9 +19,11 @@ package org.thialfihar.android.apg.ui;
import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing;
-import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Constants;
import org.thialfihar.android.apg.Id;
+import org.thialfihar.android.apg.helper.PGPHelper;
+import org.thialfihar.android.apg.helper.OtherHelper;
+import org.thialfihar.android.apg.helper.PGPConversionHelper;
import org.thialfihar.android.apg.service.ApgHandler;
import org.thialfihar.android.apg.service.ApgService;
import org.thialfihar.android.apg.ui.dialog.ProgressDialogFragment;
@@ -29,7 +31,6 @@ import org.thialfihar.android.apg.ui.widget.KeyEditor;
import org.thialfihar.android.apg.ui.widget.SectionView;
import org.thialfihar.android.apg.ui.widget.UserIdEditor;
import org.thialfihar.android.apg.util.IterableIterator;
-import org.thialfihar.android.apg.util.Utils;
import org.thialfihar.android.apg.R;
import com.actionbarsherlock.app.ActionBar;
@@ -132,7 +133,7 @@ public class EditKeyActivity extends SherlockFragmentActivity {
mActionBar.setDisplayShowTitleEnabled(true);
// set actionbar without home button if called from another app
- if (getCallingPackage() != null && getCallingPackage().equals(Apg.PACKAGE_NAME)) {
+ if (getCallingPackage() != null && getCallingPackage().equals(PGPHelper.PACKAGE_NAME)) {
mActionBar.setDisplayHomeAsUpEnabled(true);
mActionBar.setHomeButtonEnabled(true);
} else {
@@ -153,7 +154,7 @@ public class EditKeyActivity extends SherlockFragmentActivity {
// Handle intents
Bundle extras = mIntent.getExtras();
- if (Apg.Intent.CREATE_KEY.equals(mIntent.getAction())) {
+ if (PGPHelper.Intent.CREATE_KEY.equals(mIntent.getAction())) {
mActionBar.setTitle(R.string.title_createKey);
@@ -161,14 +162,14 @@ public class EditKeyActivity extends SherlockFragmentActivity {
if (extras != null) {
// if userId is given, prefill the fields
- if (extras.containsKey(Apg.EXTRA_USER_IDS)) {
+ if (extras.containsKey(PGPHelper.EXTRA_USER_IDS)) {
Log.d(Constants.TAG, "UserIds are given!");
- mUserIds.add(extras.getString(Apg.EXTRA_USER_IDS));
+ mUserIds.add(extras.getString(PGPHelper.EXTRA_USER_IDS));
}
// if no passphrase is given
- if (extras.containsKey(Apg.EXTRA_NO_PASSPHRASE)) {
- boolean noPassphrase = extras.getBoolean(Apg.EXTRA_NO_PASSPHRASE);
+ if (extras.containsKey(PGPHelper.EXTRA_NO_PASSPHRASE)) {
+ boolean noPassphrase = extras.getBoolean(PGPHelper.EXTRA_NO_PASSPHRASE);
if (noPassphrase) {
// check "no passphrase" checkbox and remove button
mNoPassphrase.setChecked(true);
@@ -177,9 +178,9 @@ public class EditKeyActivity extends SherlockFragmentActivity {
}
// generate key
- if (extras.containsKey(Apg.EXTRA_GENERATE_DEFAULT_KEYS)) {
+ if (extras.containsKey(PGPHelper.EXTRA_GENERATE_DEFAULT_KEYS)) {
boolean generateDefaultKeys = extras
- .getBoolean(Apg.EXTRA_GENERATE_DEFAULT_KEYS);
+ .getBoolean(PGPHelper.EXTRA_GENERATE_DEFAULT_KEYS);
if (generateDefaultKeys) {
// build layout in handler after generating keys not directly in onCreate
@@ -209,10 +210,10 @@ public class EditKeyActivity extends SherlockFragmentActivity {
if (message.arg1 == ApgHandler.MESSAGE_OKAY) {
// get new key from data bundle returned from service
Bundle data = message.getData();
- PGPSecretKeyRing masterKeyRing = Utils
+ PGPSecretKeyRing masterKeyRing = PGPConversionHelper
.BytesToPGPSecretKeyRing(data
.getByteArray(ApgService.RESULT_NEW_KEY));
- PGPSecretKeyRing subKeyRing = Utils
+ PGPSecretKeyRing subKeyRing = PGPConversionHelper
.BytesToPGPSecretKeyRing(data
.getByteArray(ApgService.RESULT_NEW_KEY2));
@@ -243,11 +244,11 @@ public class EditKeyActivity extends SherlockFragmentActivity {
}
}
}
- } else if (Apg.Intent.EDIT_KEY.equals(mIntent.getAction())) {
+ } else if (PGPHelper.Intent.EDIT_KEY.equals(mIntent.getAction())) {
mActionBar.setTitle(R.string.title_editKey);
- mCurrentPassPhrase = Apg.getEditPassPhrase();
+ mCurrentPassPhrase = PGPHelper.getEditPassPhrase();
if (mCurrentPassPhrase == null) {
mCurrentPassPhrase = "";
}
@@ -260,14 +261,14 @@ public class EditKeyActivity extends SherlockFragmentActivity {
if (extras != null) {
- if (extras.containsKey(Apg.EXTRA_KEY_ID)) {
- long keyId = mIntent.getExtras().getLong(Apg.EXTRA_KEY_ID);
+ if (extras.containsKey(PGPHelper.EXTRA_KEY_ID)) {
+ long keyId = mIntent.getExtras().getLong(PGPHelper.EXTRA_KEY_ID);
if (keyId != 0) {
PGPSecretKey masterKey = null;
- mKeyRing = Apg.getSecretKeyRing(keyId);
+ mKeyRing = PGPHelper.getSecretKeyRing(keyId);
if (mKeyRing != null) {
- masterKey = Apg.getMasterKey(mKeyRing);
+ masterKey = PGPHelper.getMasterKey(mKeyRing);
for (PGPSecretKey key : new IterableIterator(
mKeyRing.getSecretKeys())) {
mKeys.add(key);
@@ -411,7 +412,7 @@ public class EditKeyActivity extends SherlockFragmentActivity {
try {
if (!isPassphraseSet()) {
- throw new Apg.GeneralException(this.getString(R.string.setAPassPhrase));
+ throw new PGPHelper.GeneralException(this.getString(R.string.setAPassPhrase));
}
// Send all information needed to service to edit key in other thread
@@ -425,7 +426,7 @@ public class EditKeyActivity extends SherlockFragmentActivity {
data.putString(ApgService.NEW_PASSPHRASE, mNewPassPhrase);
data.putSerializable(ApgService.USER_IDS, getUserIds(mUserIdsView));
Vector keys = getKeys(mKeysView);
- data.putByteArray(ApgService.KEYS, Utils.PGPSecretKeyListToBytes(keys));
+ data.putByteArray(ApgService.KEYS, PGPConversionHelper.PGPSecretKeyListToBytes(keys));
data.putSerializable(ApgService.KEYS_USAGES, getKeysUsages(mKeysView));
data.putLong(ApgService.MASTER_KEY_ID, getMasterKeyId());
@@ -455,7 +456,7 @@ public class EditKeyActivity extends SherlockFragmentActivity {
// start service with intent
startService(intent);
- } catch (Apg.GeneralException e) {
+ } catch (PGPHelper.GeneralException e) {
Toast.makeText(this, getString(R.string.errorMessage, e.getMessage()),
Toast.LENGTH_SHORT).show();
}
@@ -467,7 +468,8 @@ public class EditKeyActivity extends SherlockFragmentActivity {
* @param userIdsView
* @return
*/
- private Vector getUserIds(SectionView userIdsView) throws Apg.GeneralException {
+ private Vector getUserIds(SectionView userIdsView)
+ throws PGPHelper.GeneralException {
Vector userIds = new Vector();
ViewGroup userIdEditors = userIdsView.getEditors();
@@ -479,12 +481,13 @@ public class EditKeyActivity extends SherlockFragmentActivity {
try {
userId = editor.getValue();
} catch (UserIdEditor.NoNameException e) {
- throw new Apg.GeneralException(this.getString(R.string.error_userIdNeedsAName));
+ throw new PGPHelper.GeneralException(
+ this.getString(R.string.error_userIdNeedsAName));
} catch (UserIdEditor.NoEmailException e) {
- throw new Apg.GeneralException(
+ throw new PGPHelper.GeneralException(
this.getString(R.string.error_userIdNeedsAnEmailAddress));
} catch (UserIdEditor.InvalidEmailException e) {
- throw new Apg.GeneralException(e.getMessage());
+ throw new PGPHelper.GeneralException(e.getMessage());
}
if (userId.equals("")) {
@@ -500,11 +503,12 @@ public class EditKeyActivity extends SherlockFragmentActivity {
}
if (userIds.size() == 0) {
- throw new Apg.GeneralException(getString(R.string.error_keyNeedsAUserId));
+ throw new PGPHelper.GeneralException(getString(R.string.error_keyNeedsAUserId));
}
if (!gotMainUserId) {
- throw new Apg.GeneralException(getString(R.string.error_mainUserIdMustNotBeEmpty));
+ throw new PGPHelper.GeneralException(
+ getString(R.string.error_mainUserIdMustNotBeEmpty));
}
return userIds;
@@ -516,13 +520,14 @@ public class EditKeyActivity extends SherlockFragmentActivity {
* @param keysView
* @return
*/
- private Vector getKeys(SectionView keysView) throws Apg.GeneralException {
+ private Vector getKeys(SectionView keysView)
+ throws PGPHelper.GeneralException {
Vector keys = new Vector();
ViewGroup keyEditors = keysView.getEditors();
if (keyEditors.getChildCount() == 0) {
- throw new Apg.GeneralException(getString(R.string.error_keyNeedsMasterKey));
+ throw new PGPHelper.GeneralException(getString(R.string.error_keyNeedsMasterKey));
}
for (int i = 0; i < keyEditors.getChildCount(); ++i) {
@@ -539,13 +544,14 @@ public class EditKeyActivity extends SherlockFragmentActivity {
* @param keysView
* @return
*/
- private Vector getKeysUsages(SectionView keysView) throws Apg.GeneralException {
+ private Vector getKeysUsages(SectionView keysView)
+ throws PGPHelper.GeneralException {
Vector getKeysUsages = new Vector();
ViewGroup keyEditors = keysView.getEditors();
if (keyEditors.getChildCount() == 0) {
- throw new Apg.GeneralException(getString(R.string.error_keyNeedsMasterKey));
+ throw new PGPHelper.GeneralException(getString(R.string.error_keyNeedsMasterKey));
}
for (int i = 0; i < keyEditors.getChildCount(); ++i) {
diff --git a/org_apg/src/org/thialfihar/android/apg/ui/EncryptActivity.java b/org_apg/src/org/thialfihar/android/apg/ui/EncryptActivity.java
index 05dd17b8e..2d365f926 100644
--- a/org_apg/src/org/thialfihar/android/apg/ui/EncryptActivity.java
+++ b/org_apg/src/org/thialfihar/android/apg/ui/EncryptActivity.java
@@ -21,10 +21,11 @@ import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPPublicKeyRing;
import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing;
-import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Constants;
import org.thialfihar.android.apg.Id;
import org.thialfihar.android.apg.Preferences;
+import org.thialfihar.android.apg.helper.FileHelper;
+import org.thialfihar.android.apg.helper.PGPHelper;
import org.thialfihar.android.apg.service.ApgHandler;
import org.thialfihar.android.apg.service.ApgService;
import org.thialfihar.android.apg.ui.dialog.DeleteFileDialogFragment;
@@ -33,7 +34,6 @@ import org.thialfihar.android.apg.ui.dialog.PassphraseDialogFragment;
import org.thialfihar.android.apg.ui.dialog.ProgressDialogFragment;
import org.thialfihar.android.apg.util.Choice;
import org.thialfihar.android.apg.util.Compatibility;
-import org.thialfihar.android.apg.util.Utils;
import org.thialfihar.android.apg.R;
import com.actionbarsherlock.app.ActionBar;
@@ -181,6 +181,18 @@ public class EncryptActivity extends SherlockFragmentActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.encrypt);
+ // set actionbar without home button if called from another app
+ final ActionBar actionBar = getSupportActionBar();
+ Log.d(Constants.TAG, "calling package (only set when using startActivityForResult)="
+ + getCallingPackage());
+ if (getCallingPackage() != null && getCallingPackage().equals(PGPHelper.PACKAGE_NAME)) {
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setHomeButtonEnabled(true);
+ } else {
+ actionBar.setDisplayHomeAsUpEnabled(false);
+ actionBar.setHomeButtonEnabled(false);
+ }
+
mGenerateSignature = false;
mSource = (ViewFlipper) findViewById(R.id.source);
@@ -268,7 +280,7 @@ public class EncryptActivity extends SherlockFragmentActivity {
mBrowse = (ImageButton) findViewById(R.id.btn_browse);
mBrowse.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
- Utils.openFile(EncryptActivity.this, mFilename.getText().toString(), "*/*",
+ FileHelper.openFile(EncryptActivity.this, mFilename.getText().toString(), "*/*",
Id.request.filename);
}
});
@@ -323,61 +335,49 @@ public class EncryptActivity extends SherlockFragmentActivity {
});
mIntent = getIntent();
- if (Apg.Intent.ENCRYPT.equals(mIntent.getAction())
- || Apg.Intent.ENCRYPT_FILE.equals(mIntent.getAction())
- || Apg.Intent.ENCRYPT_AND_RETURN.equals(mIntent.getAction())
- || Apg.Intent.GENERATE_SIGNATURE.equals(mIntent.getAction())) {
+ if (PGPHelper.Intent.ENCRYPT.equals(mIntent.getAction())
+ || PGPHelper.Intent.ENCRYPT_FILE.equals(mIntent.getAction())
+ || PGPHelper.Intent.ENCRYPT_AND_RETURN.equals(mIntent.getAction())
+ || PGPHelper.Intent.GENERATE_SIGNATURE.equals(mIntent.getAction())) {
mContentUri = mIntent.getData();
Bundle extras = mIntent.getExtras();
if (extras == null) {
extras = new Bundle();
}
- // set actionbar without home button if called from another app
- final ActionBar actionBar = getSupportActionBar();
- Log.d(Constants.TAG, "calling package (only set when using startActivityForResult)="
- + getCallingPackage());
- if (getCallingPackage() != null && getCallingPackage().equals(Apg.PACKAGE_NAME)) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setHomeButtonEnabled(true);
- } else {
- actionBar.setDisplayHomeAsUpEnabled(false);
- actionBar.setHomeButtonEnabled(false);
- }
-
- if (Apg.Intent.ENCRYPT_AND_RETURN.equals(mIntent.getAction())
- || Apg.Intent.GENERATE_SIGNATURE.equals(mIntent.getAction())) {
+ if (PGPHelper.Intent.ENCRYPT_AND_RETURN.equals(mIntent.getAction())
+ || PGPHelper.Intent.GENERATE_SIGNATURE.equals(mIntent.getAction())) {
mReturnResult = true;
}
- if (Apg.Intent.GENERATE_SIGNATURE.equals(mIntent.getAction())) {
+ if (PGPHelper.Intent.GENERATE_SIGNATURE.equals(mIntent.getAction())) {
mGenerateSignature = true;
mOverrideAsciiArmour = true;
mAsciiArmourDemand = false;
}
- if (extras.containsKey(Apg.EXTRA_ASCII_ARMOUR)) {
- mAsciiArmourDemand = extras.getBoolean(Apg.EXTRA_ASCII_ARMOUR, true);
+ if (extras.containsKey(PGPHelper.EXTRA_ASCII_ARMOUR)) {
+ mAsciiArmourDemand = extras.getBoolean(PGPHelper.EXTRA_ASCII_ARMOUR, true);
mOverrideAsciiArmour = true;
mAsciiArmour.setChecked(mAsciiArmourDemand);
}
- mData = extras.getByteArray(Apg.EXTRA_DATA);
+ mData = extras.getByteArray(PGPHelper.EXTRA_DATA);
String textData = null;
if (mData == null) {
- textData = extras.getString(Apg.EXTRA_TEXT);
+ textData = extras.getString(PGPHelper.EXTRA_TEXT);
}
- mSendTo = extras.getString(Apg.EXTRA_SEND_TO);
- mSubject = extras.getString(Apg.EXTRA_SUBJECT);
- long signatureKeyId = extras.getLong(Apg.EXTRA_SIGNATURE_KEY_ID);
- long encryptionKeyIds[] = extras.getLongArray(Apg.EXTRA_ENCRYPTION_KEY_IDS);
+ mSendTo = extras.getString(PGPHelper.EXTRA_SEND_TO);
+ mSubject = extras.getString(PGPHelper.EXTRA_SUBJECT);
+ long signatureKeyId = extras.getLong(PGPHelper.EXTRA_SIGNATURE_KEY_ID);
+ long encryptionKeyIds[] = extras.getLongArray(PGPHelper.EXTRA_ENCRYPTION_KEY_IDS);
if (signatureKeyId != 0) {
- PGPSecretKeyRing keyRing = Apg.getSecretKeyRing(signatureKeyId);
+ PGPSecretKeyRing keyRing = PGPHelper.getSecretKeyRing(signatureKeyId);
PGPSecretKey masterKey = null;
if (keyRing != null) {
- masterKey = Apg.getMasterKey(keyRing);
+ masterKey = PGPHelper.getMasterKey(keyRing);
if (masterKey != null) {
- Vector signKeys = Apg.getUsableSigningKeys(keyRing);
+ Vector signKeys = PGPHelper.getUsableSigningKeys(keyRing);
if (signKeys.size() > 0) {
setSecretKeyId(masterKey.getKeyID());
}
@@ -388,16 +388,16 @@ public class EncryptActivity extends SherlockFragmentActivity {
if (encryptionKeyIds != null) {
Vector goodIds = new Vector();
for (int i = 0; i < encryptionKeyIds.length; ++i) {
- PGPPublicKeyRing keyRing = Apg.getPublicKeyRing(encryptionKeyIds[i]);
+ PGPPublicKeyRing keyRing = PGPHelper.getPublicKeyRing(encryptionKeyIds[i]);
PGPPublicKey masterKey = null;
if (keyRing == null) {
continue;
}
- masterKey = Apg.getMasterKey(keyRing);
+ masterKey = PGPHelper.getMasterKey(keyRing);
if (masterKey == null) {
continue;
}
- Vector encryptKeys = Apg.getUsableEncryptKeys(keyRing);
+ Vector encryptKeys = PGPHelper.getUsableEncryptKeys(keyRing);
if (encryptKeys.size() == 0) {
continue;
}
@@ -411,9 +411,9 @@ public class EncryptActivity extends SherlockFragmentActivity {
}
}
- if (Apg.Intent.ENCRYPT.equals(mIntent.getAction())
- || Apg.Intent.ENCRYPT_AND_RETURN.equals(mIntent.getAction())
- || Apg.Intent.GENERATE_SIGNATURE.equals(mIntent.getAction())) {
+ if (PGPHelper.Intent.ENCRYPT.equals(mIntent.getAction())
+ || PGPHelper.Intent.ENCRYPT_AND_RETURN.equals(mIntent.getAction())
+ || PGPHelper.Intent.GENERATE_SIGNATURE.equals(mIntent.getAction())) {
if (textData != null) {
mMessage.setText(textData);
}
@@ -422,7 +422,7 @@ public class EncryptActivity extends SherlockFragmentActivity {
while (mSource.getCurrentView().getId() != R.id.sourceMessage) {
mSource.showNext();
}
- } else if (Apg.Intent.ENCRYPT_FILE.equals(mIntent.getAction())) {
+ } else if (PGPHelper.Intent.ENCRYPT_FILE.equals(mIntent.getAction())) {
if ("file".equals(mIntent.getScheme())) {
mInputFilename = Uri.decode(mIntent.getDataString().replace("file://", ""));
mFilename.setText(mInputFilename);
@@ -651,7 +651,7 @@ public class EncryptActivity extends SherlockFragmentActivity {
return;
}
- if (getSecretKeyId() != 0 && Apg.getCachedPassPhrase(getSecretKeyId()) == null) {
+ if (getSecretKeyId() != 0 && PGPHelper.getCachedPassPhrase(getSecretKeyId()) == null) {
showPassphraseDialog();
return;
@@ -659,7 +659,7 @@ public class EncryptActivity extends SherlockFragmentActivity {
}
if (mEncryptTarget == Id.target.file) {
- askForOutputFilename();
+ showOutputFileDialog();
} else {
encryptStart();
}
@@ -676,7 +676,7 @@ public class EncryptActivity extends SherlockFragmentActivity {
public void handleMessage(Message message) {
if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
if (mEncryptTarget == Id.target.file) {
- askForOutputFilename();
+ showOutputFileDialog();
} else {
encryptStart();
}
@@ -692,15 +692,15 @@ public class EncryptActivity extends SherlockFragmentActivity {
messenger, mSecretKeyId);
passphraseDialog.show(getSupportFragmentManager(), "passphraseDialog");
- } catch (Apg.GeneralException e) {
+ } catch (PGPHelper.GeneralException e) {
Log.d(Constants.TAG, "No passphrase for this secret key, encrypt directly!");
// send message to handler to start encryption directly
returnHandler.sendEmptyMessage(PassphraseDialogFragment.MESSAGE_OKAY);
}
}
- private void askForOutputFilename() {
- // Message is received after passphrase is cached
+ private void showOutputFileDialog() {
+ // Message is received after file is selected
Handler returnHandler = new Handler() {
@Override
public void handleMessage(Message message) {
@@ -721,7 +721,6 @@ public class EncryptActivity extends SherlockFragmentActivity {
Id.request.output_filename);
mFileDialog.show(getSupportFragmentManager(), "fileDialog");
-
}
private void encryptStart() {
@@ -743,7 +742,6 @@ public class EncryptActivity extends SherlockFragmentActivity {
if (passPhrase.length() == 0) {
passPhrase = null;
}
- // signatureKeyId = Id.key.symmetric;
data.putString(ApgService.SYMMETRIC_PASSPHRASE, passPhrase);
} else {
@@ -776,13 +774,13 @@ public class EncryptActivity extends SherlockFragmentActivity {
intent.putExtra(ApgService.EXTRA_ACTION, ApgService.ACTION_ENCRYPT_SIGN_BYTES);
if (mData != null) {
- data.putByteArray(ApgService.BYTES, mData);
+ data.putByteArray(ApgService.MESSAGE_BYTES, mData);
} else {
String message = mMessage.getText().toString();
if (signOnly && !mReturnResult) {
fixBadCharactersForGmail(message);
}
- data.putByteArray(ApgService.BYTES, message.getBytes());
+ data.putByteArray(ApgService.MESSAGE_BYTES, message.getBytes());
}
}
@@ -919,11 +917,11 @@ public class EncryptActivity extends SherlockFragmentActivity {
} else {
String uid = getResources().getString(R.string.unknownUserId);
String uidExtra = "";
- PGPSecretKeyRing keyRing = Apg.getSecretKeyRing(getSecretKeyId());
+ PGPSecretKeyRing keyRing = PGPHelper.getSecretKeyRing(getSecretKeyId());
if (keyRing != null) {
- PGPSecretKey key = Apg.getMasterKey(keyRing);
+ PGPSecretKey key = PGPHelper.getMasterKey(keyRing);
if (key != null) {
- String userId = Apg.getMainUserIdSafe(this, key);
+ String userId = PGPHelper.getMainUserIdSafe(this, key);
String chunks[] = userId.split(" <", 2);
uid = chunks[0];
if (chunks.length > 1) {
@@ -957,7 +955,7 @@ public class EncryptActivity extends SherlockFragmentActivity {
initialKeyIds[i] = keyIds.get(i);
}
}
- intent.putExtra(Apg.EXTRA_SELECTION, initialKeyIds);
+ intent.putExtra(PGPHelper.EXTRA_SELECTION, initialKeyIds);
startActivityForResult(intent, Id.request.public_keys);
}
@@ -1000,7 +998,7 @@ public class EncryptActivity extends SherlockFragmentActivity {
case Id.request.public_keys: {
if (resultCode == RESULT_OK) {
Bundle bundle = data.getExtras();
- mEncryptionKeyIds = bundle.getLongArray(Apg.EXTRA_SELECTION);
+ mEncryptionKeyIds = bundle.getLongArray(PGPHelper.EXTRA_SELECTION);
}
updateView();
break;
@@ -1009,7 +1007,7 @@ public class EncryptActivity extends SherlockFragmentActivity {
case Id.request.secret_keys: {
if (resultCode == RESULT_OK) {
Bundle bundle = data.getExtras();
- setSecretKeyId(bundle.getLong(Apg.EXTRA_KEY_ID));
+ setSecretKeyId(bundle.getLong(PGPHelper.EXTRA_KEY_ID));
} else {
setSecretKeyId(Id.key.none);
}
diff --git a/org_apg/src/org/thialfihar/android/apg/ui/GeneralActivity.java b/org_apg/src/org/thialfihar/android/apg/ui/GeneralActivity.java
index 76a5dc92c..dde247bdf 100644
--- a/org_apg/src/org/thialfihar/android/apg/ui/GeneralActivity.java
+++ b/org_apg/src/org/thialfihar/android/apg/ui/GeneralActivity.java
@@ -21,8 +21,8 @@ import java.io.InputStream;
import java.util.Vector;
import org.thialfihar.android.apg.R;
-import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Id;
+import org.thialfihar.android.apg.helper.PGPHelper;
import org.thialfihar.android.apg.util.Choice;
import android.content.Intent;
@@ -83,7 +83,7 @@ public class GeneralActivity extends BaseActivity {
int contentType = Id.content.unknown;
try {
- contentType = Apg.getStreamContent(this, inStream);
+ contentType = PGPHelper.getStreamContent(this, inStream);
inStream.close();
} catch (IOException e) {
// just means that there's no PGP data in there
@@ -134,10 +134,10 @@ public class GeneralActivity extends BaseActivity {
case Id.choice.action.encrypt: {
intent.setClass(this, EncryptActivity.class);
if (mDataString != null) {
- intent.setAction(Apg.Intent.ENCRYPT);
- intent.putExtra(Apg.EXTRA_TEXT, mDataString);
+ intent.setAction(PGPHelper.Intent.ENCRYPT);
+ intent.putExtra(PGPHelper.EXTRA_TEXT, mDataString);
} else if (mDataUri != null) {
- intent.setAction(Apg.Intent.ENCRYPT_FILE);
+ intent.setAction(PGPHelper.Intent.ENCRYPT_FILE);
intent.setDataAndType(mDataUri, mIntent.getType());
}
@@ -147,10 +147,10 @@ public class GeneralActivity extends BaseActivity {
case Id.choice.action.decrypt: {
intent.setClass(this, DecryptActivity.class);
if (mDataString != null) {
- intent.setAction(Apg.Intent.DECRYPT);
- intent.putExtra(Apg.EXTRA_TEXT, mDataString);
+ intent.setAction(PGPHelper.Intent.DECRYPT);
+ intent.putExtra(PGPHelper.EXTRA_TEXT, mDataString);
} else if (mDataUri != null) {
- intent.setAction(Apg.Intent.DECRYPT_FILE);
+ intent.setAction(PGPHelper.Intent.DECRYPT_FILE);
intent.setDataAndType(mDataUri, mIntent.getType());
}
@@ -159,9 +159,9 @@ public class GeneralActivity extends BaseActivity {
case Id.choice.action.import_public: {
intent.setClass(this, PublicKeyListActivity.class);
- intent.setAction(Apg.Intent.IMPORT);
+ intent.setAction(PGPHelper.Intent.IMPORT);
if (mDataString != null) {
- intent.putExtra(Apg.EXTRA_TEXT, mDataString);
+ intent.putExtra(PGPHelper.EXTRA_TEXT, mDataString);
} else if (mDataUri != null) {
intent.setDataAndType(mDataUri, mIntent.getType());
}
@@ -170,9 +170,9 @@ public class GeneralActivity extends BaseActivity {
case Id.choice.action.import_secret: {
intent.setClass(this, SecretKeyListActivity.class);
- intent.setAction(Apg.Intent.IMPORT);
+ intent.setAction(PGPHelper.Intent.IMPORT);
if (mDataString != null) {
- intent.putExtra(Apg.EXTRA_TEXT, mDataString);
+ intent.putExtra(PGPHelper.EXTRA_TEXT, mDataString);
} else if (mDataUri != null) {
intent.setDataAndType(mDataUri, mIntent.getType());
}
diff --git a/org_apg/src/org/thialfihar/android/apg/ui/HelpFragmentAbout.java b/org_apg/src/org/thialfihar/android/apg/ui/HelpFragmentAbout.java
index 3dec32446..bb42aa20c 100644
--- a/org_apg/src/org/thialfihar/android/apg/ui/HelpFragmentAbout.java
+++ b/org_apg/src/org/thialfihar/android/apg/ui/HelpFragmentAbout.java
@@ -18,7 +18,7 @@ package org.thialfihar.android.apg.ui;
import org.thialfihar.android.apg.Constants;
import org.thialfihar.android.apg.R;
-import org.thialfihar.android.apg.util.Utils;
+import org.thialfihar.android.apg.helper.OtherHelper;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -52,7 +52,7 @@ public class HelpFragmentAbout extends SherlockFragment {
View view = inflater.inflate(R.layout.help_fragment_about, container, false);
// load html from html file from /res/raw
- String aboutText = Utils.readContentFromResource(this.getActivity(), R.raw.help_about);
+ String aboutText = OtherHelper.readContentFromResource(this.getActivity(), R.raw.help_about);
TextView versionText = (TextView) view.findViewById(R.id.help_about_version);
versionText.setText(getString(R.string.help_about_version) + " " + getVersion());
diff --git a/org_apg/src/org/thialfihar/android/apg/ui/HelpFragmentHtml.java b/org_apg/src/org/thialfihar/android/apg/ui/HelpFragmentHtml.java
index 35f6fb3e6..ea90d6855 100644
--- a/org_apg/src/org/thialfihar/android/apg/ui/HelpFragmentHtml.java
+++ b/org_apg/src/org/thialfihar/android/apg/ui/HelpFragmentHtml.java
@@ -16,7 +16,7 @@
package org.thialfihar.android.apg.ui;
-import org.thialfihar.android.apg.util.Utils;
+import org.thialfihar.android.apg.helper.OtherHelper;
import android.app.Activity;
import android.os.Bundle;
@@ -68,7 +68,7 @@ public class HelpFragmentHtml extends SherlockFragment {
htmlFile = getArguments().getInt(ARG_HTML_FILE);
// load html from html file from /res/raw
- String helpText = Utils.readContentFromResource(this.getActivity(), htmlFile);
+ String helpText = OtherHelper.readContentFromResource(this.getActivity(), htmlFile);
mActivity = getActivity();
diff --git a/org_apg/src/org/thialfihar/android/apg/ui/ImportFromQRCodeActivity.java b/org_apg/src/org/thialfihar/android/apg/ui/ImportFromQRCodeActivity.java
index 6f1043467..c9fb89cc7 100644
--- a/org_apg/src/org/thialfihar/android/apg/ui/ImportFromQRCodeActivity.java
+++ b/org_apg/src/org/thialfihar/android/apg/ui/ImportFromQRCodeActivity.java
@@ -1,4 +1,6 @@
/*
+ * Copyright (C) 2011 Senecaso
+ *
* 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
@@ -19,11 +21,11 @@ import java.io.IOException;
import org.spongycastle.openpgp.PGPKeyRing;
import org.spongycastle.openpgp.PGPPublicKeyRing;
-import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Constants;
import org.thialfihar.android.apg.HkpKeyServer;
import org.thialfihar.android.apg.Id;
import org.thialfihar.android.apg.KeyServer.QueryException;
+import org.thialfihar.android.apg.helper.PGPHelper;
import org.thialfihar.android.apg.R;
import android.content.Intent;
@@ -60,33 +62,33 @@ public class ImportFromQRCodeActivity extends BaseActivity {
HkpKeyServer server = new HkpKeyServer(mPreferences.getKeyServers()[0]); // TODO: there should be only 1
String encodedKey = server.get(keyId);
- PGPKeyRing keyring = Apg.decodeKeyRing(new ByteArrayInputStream(encodedKey.getBytes()));
+ PGPKeyRing keyring = PGPHelper.decodeKeyRing(new ByteArrayInputStream(encodedKey.getBytes()));
if (keyring != null && keyring instanceof PGPPublicKeyRing) {
PGPPublicKeyRing publicKeyRing = (PGPPublicKeyRing) keyring;
// make sure the fingerprints match before we cache this thing
- String actualFingerprint = Apg.convertToHex(publicKeyRing.getPublicKey().getFingerprint());
+ String actualFingerprint = PGPHelper.convertToHex(publicKeyRing.getPublicKey().getFingerprint());
if (expectedFingerprint.equals(actualFingerprint)) {
// store the signed key in our local cache
- int retval = Apg.storeKeyRingInCache(publicKeyRing);
+ int retval = PGPHelper.storeKeyRingInCache(publicKeyRing);
if (retval != Id.return_value.ok && retval != Id.return_value.updated) {
- status.putString(Apg.EXTRA_ERROR, "Failed to store signed key in local cache");
+ status.putString(PGPHelper.EXTRA_ERROR, "Failed to store signed key in local cache");
} else {
Intent intent = new Intent(ImportFromQRCodeActivity.this, SignKeyActivity.class);
- intent.putExtra(Apg.EXTRA_KEY_ID, keyId);
+ intent.putExtra(PGPHelper.EXTRA_KEY_ID, keyId);
startActivityForResult(intent, Id.request.sign_key);
}
} else {
- status.putString(Apg.EXTRA_ERROR, "Scanned fingerprint does NOT match the fingerprint of the received key. You shouldnt trust this key.");
+ status.putString(PGPHelper.EXTRA_ERROR, "Scanned fingerprint does NOT match the fingerprint of the received key. You shouldnt trust this key.");
}
}
} catch (QueryException e) {
Log.e(TAG, "Failed to query KeyServer", e);
- status.putString(Apg.EXTRA_ERROR, "Failed to query KeyServer");
+ status.putString(PGPHelper.EXTRA_ERROR, "Failed to query KeyServer");
status.putInt(Constants.extras.STATUS, Id.message.done);
} catch (IOException e) {
Log.e(TAG, "Failed to query KeyServer", e);
- status.putString(Apg.EXTRA_ERROR, "Failed to query KeyServer");
+ status.putString(PGPHelper.EXTRA_ERROR, "Failed to query KeyServer");
status.putInt(Constants.extras.STATUS, Id.message.done);
}
}
@@ -140,7 +142,7 @@ public class ImportFromQRCodeActivity extends BaseActivity {
super.doneCallback(msg);
Bundle data = msg.getData();
- String error = data.getString(Apg.EXTRA_ERROR);
+ String error = data.getString(PGPHelper.EXTRA_ERROR);
if (error != null) {
Toast.makeText(this, getString(R.string.errorMessage, error), Toast.LENGTH_SHORT).show();
return;
diff --git a/org_apg/src/org/thialfihar/android/apg/ui/KeyListActivity.java b/org_apg/src/org/thialfihar/android/apg/ui/KeyListActivity.java
index 787afd431..8e2bcaecb 100644
--- a/org_apg/src/org/thialfihar/android/apg/ui/KeyListActivity.java
+++ b/org_apg/src/org/thialfihar/android/apg/ui/KeyListActivity.java
@@ -19,14 +19,14 @@ package org.thialfihar.android.apg.ui;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPPublicKeyRing;
import org.spongycastle.openpgp.PGPSecretKeyRing;
-import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Constants;
-import org.thialfihar.android.apg.FileDialog;
import org.thialfihar.android.apg.Id;
-import org.thialfihar.android.apg.InputData;
+import org.thialfihar.android.apg.helper.PGPHelper;
import org.thialfihar.android.apg.provider.KeyRings;
import org.thialfihar.android.apg.provider.Keys;
import org.thialfihar.android.apg.provider.UserIds;
+import org.thialfihar.android.apg.ui.dialog.FileDialogFragment;
+import org.thialfihar.android.apg.util.InputData;
import org.thialfihar.android.apg.R;
import com.actionbarsherlock.view.MenuItem;
@@ -42,7 +42,10 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Handler;
import android.os.Message;
+import android.os.Messenger;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
@@ -83,6 +86,8 @@ public class KeyListActivity extends BaseActivity {
protected int mKeyType = Id.type.public_key;
+ FileDialogFragment mFileDialog;
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -134,11 +139,11 @@ public class KeyListActivity extends BaseActivity {
mListAdapter = new KeyListAdapter(this, searchString);
mList.setAdapter(mListAdapter);
- if (Apg.Intent.IMPORT.equals(intent.getAction())) {
+ if (PGPHelper.Intent.IMPORT.equals(intent.getAction())) {
if ("file".equals(intent.getScheme()) && intent.getDataString() != null) {
mImportFilename = Uri.decode(intent.getDataString().replace("file://", ""));
} else {
- mImportData = intent.getStringExtra(Apg.EXTRA_TEXT);
+ mImportData = intent.getStringExtra(PGPHelper.EXTRA_TEXT);
}
importKeys();
}
@@ -148,12 +153,14 @@ public class KeyListActivity extends BaseActivity {
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case Id.menu.option.import_keys: {
- showDialog(Id.dialog.import_keys);
+ // showDialog(Id.dialog.import_keys);
+ showImportKeysDialog();
return true;
}
case Id.menu.option.export_keys: {
- showDialog(Id.dialog.export_keys);
+ // showDialog(Id.dialog.export_keys);
+ showExportKeysDialog(false);
return true;
}
@@ -163,6 +170,59 @@ public class KeyListActivity extends BaseActivity {
}
}
+ private void showImportKeysDialog() {
+ // Message is received after file is selected
+ Handler returnHandler = new Handler() {
+ @Override
+ public void handleMessage(Message message) {
+ if (message.what == FileDialogFragment.MESSAGE_OKAY) {
+ Bundle data = message.getData();
+ mImportFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME);
+
+ mDeleteAfterImport = data.getBoolean(FileDialogFragment.MESSAGE_DATA_CHECKED);
+ importKeys();
+ }
+ }
+ };
+
+ // Create a new Messenger for the communication back
+ Messenger messenger = new Messenger(returnHandler);
+
+ mFileDialog = FileDialogFragment.newInstance(messenger,
+ getString(R.string.title_importKeys), getString(R.string.specifyFileToImportFrom),
+ mImportFilename, null, Id.request.filename);
+
+ mFileDialog.show(getSupportFragmentManager(), "fileDialog");
+ }
+
+ private void showExportKeysDialog(boolean singleKeyExport) {
+ String title = (singleKeyExport ? getString(R.string.title_exportKey)
+ : getString(R.string.title_exportKeys));
+ String message = getString(mKeyType == Id.type.public_key ? R.string.specifyFileToExportTo
+ : R.string.specifyFileToExportSecretKeysTo);
+
+ // Message is received after file is selected
+ Handler returnHandler = new Handler() {
+ @Override
+ public void handleMessage(Message message) {
+ if (message.what == FileDialogFragment.MESSAGE_OKAY) {
+ Bundle data = message.getData();
+ mExportFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME);
+
+ exportKeys();
+ }
+ }
+ };
+
+ // Create a new Messenger for the communication back
+ Messenger messenger = new Messenger(returnHandler);
+
+ mFileDialog = FileDialogFragment.newInstance(messenger, title, message, mExportFilename,
+ null, Id.request.filename);
+
+ mFileDialog.show(getSupportFragmentManager(), "fileDialog");
+ }
+
@Override
public boolean onContextItemSelected(android.view.MenuItem menuItem) {
ExpandableListContextMenuInfo info = (ExpandableListContextMenuInfo) menuItem.getMenuInfo();
@@ -176,7 +236,7 @@ public class KeyListActivity extends BaseActivity {
switch (menuItem.getItemId()) {
case Id.menu.export: {
mSelectedItem = groupPosition;
- showDialog(Id.dialog.export_key);
+ showExportKeysDialog(true);
return true;
}
@@ -194,7 +254,6 @@ public class KeyListActivity extends BaseActivity {
@Override
protected Dialog onCreateDialog(int id) {
- boolean singleKeyExport = false;
switch (id) {
case Id.dialog.delete_key: {
@@ -202,14 +261,14 @@ public class KeyListActivity extends BaseActivity {
mSelectedItem = -1;
// TODO: better way to do this?
String userId = "";
- Object keyRing = Apg.getKeyRing(keyRingId);
+ Object keyRing = PGPHelper.getKeyRing(keyRingId);
if (keyRing != null) {
if (keyRing instanceof PGPPublicKeyRing) {
- userId = Apg.getMainUserIdSafe(this,
- Apg.getMasterKey((PGPPublicKeyRing) keyRing));
+ userId = PGPHelper.getMainUserIdSafe(this,
+ PGPHelper.getMasterKey((PGPPublicKeyRing) keyRing));
} else {
- userId = Apg.getMainUserIdSafe(this,
- Apg.getMasterKey((PGPSecretKeyRing) keyRing));
+ userId = PGPHelper.getMainUserIdSafe(this,
+ PGPHelper.getMasterKey((PGPSecretKeyRing) keyRing));
}
}
@@ -234,54 +293,6 @@ public class KeyListActivity extends BaseActivity {
return builder.create();
}
- case Id.dialog.import_keys: {
- return FileDialog.build(this, getString(R.string.title_importKeys),
- getString(R.string.specifyFileToImportFrom), mImportFilename,
- new FileDialog.OnClickListener() {
- public void onOkClick(String filename, boolean checked) {
- removeDialog(Id.dialog.import_keys);
- mDeleteAfterImport = checked;
- mImportFilename = filename;
- importKeys();
- }
-
- public void onCancelClick() {
- removeDialog(Id.dialog.import_keys);
- }
- }, getString(R.string.filemanager_titleOpen),
- getString(R.string.filemanager_btnOpen),
- getString(R.string.label_deleteAfterImport), Id.request.filename);
- }
-
- case Id.dialog.export_key: {
- singleKeyExport = true;
- // break intentionally omitted, to use the Id.dialog.export_keys dialog
- }
-
- case Id.dialog.export_keys: {
- String title = (singleKeyExport ? getString(R.string.title_exportKey)
- : getString(R.string.title_exportKeys));
-
- final int thisDialogId = (singleKeyExport ? Id.dialog.export_key
- : Id.dialog.export_keys);
-
- return FileDialog.build(this, title,
- getString(mKeyType == Id.type.public_key ? R.string.specifyFileToExportTo
- : R.string.specifyFileToExportSecretKeysTo), mExportFilename,
- new FileDialog.OnClickListener() {
- public void onOkClick(String filename, boolean checked) {
- removeDialog(thisDialogId);
- mExportFilename = filename;
- exportKeys();
- }
-
- public void onCancelClick() {
- removeDialog(thisDialogId);
- }
- }, getString(R.string.filemanager_titleSave),
- getString(R.string.filemanager_btnSave), null, Id.request.filename);
- }
-
default: {
return super.onCreateDialog(id);
}
@@ -325,12 +336,12 @@ public class KeyListActivity extends BaseActivity {
}
if (mTask == Id.task.import_keys) {
- data = Apg.importKeyRings(this, mKeyType, new InputData(importInputStream, size),
- this);
+ data = PGPHelper.importKeyRings(this, mKeyType, new InputData(importInputStream,
+ size), this);
} else {
Vector keyRingIds = new Vector();
if (mSelectedItem == -1) {
- keyRingIds = Apg
+ keyRingIds = PGPHelper
.getKeyRingIds(mKeyType == Id.type.public_key ? Id.database.type_public
: Id.database.type_secret);
} else {
@@ -338,7 +349,7 @@ public class KeyListActivity extends BaseActivity {
keyRingIds.add(keyRingId);
mSelectedItem = -1;
}
- data = Apg.exportKeyRings(this, keyRingIds, exportOutputStream, this);
+ data = PGPHelper.exportKeyRings(this, keyRingIds, exportOutputStream, this);
}
} catch (FileNotFoundException e) {
error = getString(R.string.error_fileNotFound);
@@ -346,7 +357,7 @@ public class KeyListActivity extends BaseActivity {
error = "" + e;
} catch (PGPException e) {
error = "" + e;
- } catch (Apg.GeneralException e) {
+ } catch (PGPHelper.GeneralException e) {
error = "" + e;
}
@@ -359,7 +370,7 @@ public class KeyListActivity extends BaseActivity {
}
if (error != null) {
- data.putString(Apg.EXTRA_ERROR, error);
+ data.putString(PGPHelper.EXTRA_ERROR, error);
}
msg.setData(data);
@@ -367,7 +378,7 @@ public class KeyListActivity extends BaseActivity {
}
protected void deleteKey(int keyRingId) {
- Apg.deleteKey(keyRingId);
+ PGPHelper.deleteKey(keyRingId);
refreshList();
}
@@ -387,7 +398,7 @@ public class KeyListActivity extends BaseActivity {
case Id.message.import_done: {
removeDialog(Id.dialog.importing);
- String error = data.getString(Apg.EXTRA_ERROR);
+ String error = data.getString(PGPHelper.EXTRA_ERROR);
if (error != null) {
Toast.makeText(KeyListActivity.this, getString(R.string.errorMessage, error),
Toast.LENGTH_SHORT).show();
@@ -434,7 +445,7 @@ public class KeyListActivity extends BaseActivity {
case Id.message.export_done: {
removeDialog(Id.dialog.exporting);
- String error = data.getString(Apg.EXTRA_ERROR);
+ String error = data.getString(PGPHelper.EXTRA_ERROR);
if (error != null) {
Toast.makeText(KeyListActivity.this, getString(R.string.errorMessage, error),
Toast.LENGTH_SHORT).show();
@@ -508,7 +519,7 @@ public class KeyListActivity extends BaseActivity {
mSearchString = searchString;
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- mDatabase = Apg.getDatabase().db();
+ mDatabase = PGPHelper.getDatabase().db();
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setTables(KeyRings.TABLE_NAME + " INNER JOIN " + Keys.TABLE_NAME + " ON " + "("
+ KeyRings.TABLE_NAME + "." + KeyRings._ID + " = " + Keys.TABLE_NAME + "."
@@ -600,7 +611,8 @@ public class KeyListActivity extends BaseActivity {
c.close();
if (masterKeyId != -1) {
- children.insertElementAt(new KeyChild(Apg.getFingerPrint(fingerPrintId), true), 0);
+ children.insertElementAt(
+ new KeyChild(PGPHelper.getFingerPrint(fingerPrintId), true), 0);
c = mDatabase.query(UserIds.TABLE_NAME, new String[] { UserIds.USER_ID, // 0
}, UserIds.KEY_ID + " = ? AND " + UserIds.RANK + " > 0", new String[] { ""
+ masterKeyId }, null, null, UserIds.RANK + " ASC");
@@ -703,10 +715,10 @@ public class KeyListActivity extends BaseActivity {
}
TextView keyId = (TextView) view.findViewById(R.id.keyId);
- String keyIdStr = Apg.getSmallFingerPrint(child.keyId);
+ String keyIdStr = PGPHelper.getSmallFingerPrint(child.keyId);
keyId.setText(keyIdStr);
TextView keyDetails = (TextView) view.findViewById(R.id.keyDetails);
- String algorithmStr = Apg.getAlgorithmInfo(child.algorithm, child.keySize);
+ String algorithmStr = PGPHelper.getAlgorithmInfo(child.algorithm, child.keySize);
keyDetails.setText("(" + algorithmStr + ")");
ImageView encryptIcon = (ImageView) view.findViewById(R.id.ic_encryptKey);
@@ -745,16 +757,13 @@ public class KeyListActivity extends BaseActivity {
switch (requestCode) {
case Id.request.filename: {
if (resultCode == RESULT_OK && data != null) {
- String filename = data.getDataString();
- if (filename != null) {
- // Get rid of URI prefix:
- if (filename.startsWith("file://")) {
- filename = filename.substring(7);
- }
- // replace %20 and so on
- filename = Uri.decode(filename);
+ try {
+ String path = data.getData().getPath();
+ Log.d(Constants.TAG, "path=" + path);
- FileDialog.setFilename(filename);
+ mFileDialog.setFilename(path);
+ } catch (NullPointerException e) {
+ Log.e(Constants.TAG, "Nullpointer while retrieving path!");
}
}
return;
diff --git a/org_apg/src/org/thialfihar/android/apg/ui/KeyServerExportActivity.java b/org_apg/src/org/thialfihar/android/apg/ui/KeyServerExportActivity.java
index 877ae0164..17d80296b 100644
--- a/org_apg/src/org/thialfihar/android/apg/ui/KeyServerExportActivity.java
+++ b/org_apg/src/org/thialfihar/android/apg/ui/KeyServerExportActivity.java
@@ -1,4 +1,6 @@
/*
+ * Copyright (C) 2011 Senecaso
+ *
* 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
@@ -16,11 +18,11 @@ package org.thialfihar.android.apg.ui;
import org.spongycastle.openpgp.PGPKeyRing;
import org.spongycastle.openpgp.PGPPublicKeyRing;
-import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Constants;
import org.thialfihar.android.apg.HkpKeyServer;
import org.thialfihar.android.apg.Id;
import org.thialfihar.android.apg.R;
+import org.thialfihar.android.apg.helper.PGPHelper;
import com.actionbarsherlock.view.MenuItem;
@@ -49,7 +51,10 @@ public class KeyServerExportActivity extends BaseActivity {
switch (item.getItemId()) {
case android.R.id.home:
- startActivity(new Intent(this, PublicKeyListActivity.class));
+ // app icon in Action Bar clicked; go home
+ Intent intent = new Intent(this, PublicKeyListActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ startActivity(intent);
return true;
default:
@@ -94,11 +99,11 @@ public class KeyServerExportActivity extends BaseActivity {
HkpKeyServer server = new HkpKeyServer((String) keyServer.getSelectedItem());
- int keyRingId = getIntent().getIntExtra(Apg.EXTRA_KEY_ID, -1);
+ int keyRingId = getIntent().getIntExtra(PGPHelper.EXTRA_KEY_ID, -1);
- PGPKeyRing keyring = Apg.getKeyRing(keyRingId);
+ PGPKeyRing keyring = PGPHelper.getKeyRing(keyRingId);
if (keyring != null && keyring instanceof PGPPublicKeyRing) {
- boolean uploaded = Apg.uploadKeyRingToServer(server, (PGPPublicKeyRing) keyring);
+ boolean uploaded = PGPHelper.uploadKeyRingToServer(server, (PGPPublicKeyRing) keyring);
if (!uploaded) {
error = "Unable to export key to selected server";
}
@@ -107,7 +112,7 @@ public class KeyServerExportActivity extends BaseActivity {
data.putInt(Constants.extras.STATUS, Id.message.export_done);
if (error != null) {
- data.putString(Apg.EXTRA_ERROR, error);
+ data.putString(PGPHelper.EXTRA_ERROR, error);
}
msg.setData(data);
@@ -119,7 +124,7 @@ public class KeyServerExportActivity extends BaseActivity {
super.doneCallback(msg);
Bundle data = msg.getData();
- String error = data.getString(Apg.EXTRA_ERROR);
+ String error = data.getString(PGPHelper.EXTRA_ERROR);
if (error != null) {
Toast.makeText(this, getString(R.string.errorMessage, error), Toast.LENGTH_SHORT)
.show();
diff --git a/org_apg/src/org/thialfihar/android/apg/ui/KeyServerPreferenceActivity.java b/org_apg/src/org/thialfihar/android/apg/ui/KeyServerPreferenceActivity.java
deleted file mode 100644
index e1233661f..000000000
--- a/org_apg/src/org/thialfihar/android/apg/ui/KeyServerPreferenceActivity.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2010 Thialfihar
- *
- * 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.thialfihar.android.apg.ui;
-
-import java.util.Vector;
-
-import org.thialfihar.android.apg.R;
-import org.thialfihar.android.apg.Apg;
-import org.thialfihar.android.apg.ui.widget.Editor;
-import org.thialfihar.android.apg.ui.widget.KeyServerEditor;
-import org.thialfihar.android.apg.ui.widget.Editor.EditorListener;
-
-import com.actionbarsherlock.view.Menu;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.TextView;
-
-public class KeyServerPreferenceActivity extends BaseActivity implements OnClickListener,
- EditorListener {
- private LayoutInflater mInflater;
- private ViewGroup mEditors;
- private View mAdd;
- private TextView mTitle;
- private TextView mSummary;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.key_server_preference);
-
- mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
- mTitle = (TextView) findViewById(R.id.title);
- mSummary = (TextView) findViewById(R.id.summary);
-
- mTitle.setText(R.string.label_keyServers);
-
- mEditors = (ViewGroup) findViewById(R.id.editors);
- mAdd = findViewById(R.id.add);
- mAdd.setOnClickListener(this);
-
- Intent intent = getIntent();
- String servers[] = intent.getStringArrayExtra(Apg.EXTRA_KEY_SERVERS);
- if (servers != null) {
- for (int i = 0; i < servers.length; ++i) {
- KeyServerEditor view = (KeyServerEditor) mInflater.inflate(
- R.layout.key_server_editor, mEditors, false);
- view.setEditorListener(this);
- view.setValue(servers[i]);
- mEditors.addView(view);
- }
- }
-
- Button okButton = (Button) findViewById(R.id.btn_ok);
- okButton.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- okClicked();
- }
- });
-
- Button cancelButton = (Button) findViewById(R.id.btn_cancel);
- cancelButton.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- cancelClicked();
- }
- });
- }
-
- public void onDeleted(Editor editor) {
- // nothing to do
- }
-
- public void onClick(View v) {
- KeyServerEditor view = (KeyServerEditor) mInflater.inflate(R.layout.key_server_editor,
- mEditors, false);
- view.setEditorListener(this);
- mEditors.addView(view);
- }
-
- private void cancelClicked() {
- setResult(RESULT_CANCELED, null);
- finish();
- }
-
- private void okClicked() {
- Intent data = new Intent();
- Vector servers = new Vector();
- for (int i = 0; i < mEditors.getChildCount(); ++i) {
- KeyServerEditor editor = (KeyServerEditor) mEditors.getChildAt(i);
- String tmp = editor.getValue();
- if (tmp.length() > 0) {
- servers.add(tmp);
- }
- }
- String[] dummy = new String[0];
- data.putExtra(Apg.EXTRA_KEY_SERVERS, servers.toArray(dummy));
- setResult(RESULT_OK, data);
- finish();
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- // override this, so no option menu is added (as would be in BaseActivity), since
- // we're still in preferences
- return true;
- }
-}
diff --git a/org_apg/src/org/thialfihar/android/apg/ui/KeyServerQueryActivity.java b/org_apg/src/org/thialfihar/android/apg/ui/KeyServerQueryActivity.java
index 2009441ab..7a1b94335 100644
--- a/org_apg/src/org/thialfihar/android/apg/ui/KeyServerQueryActivity.java
+++ b/org_apg/src/org/thialfihar/android/apg/ui/KeyServerQueryActivity.java
@@ -18,7 +18,6 @@ import java.util.List;
import java.util.Vector;
import org.thialfihar.android.apg.R;
-import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Constants;
import org.thialfihar.android.apg.HkpKeyServer;
import org.thialfihar.android.apg.Id;
@@ -26,6 +25,7 @@ import org.thialfihar.android.apg.KeyServer.InsufficientQuery;
import org.thialfihar.android.apg.KeyServer.KeyInfo;
import org.thialfihar.android.apg.KeyServer.QueryException;
import org.thialfihar.android.apg.KeyServer.TooManyResponses;
+import org.thialfihar.android.apg.helper.PGPHelper;
import com.actionbarsherlock.view.MenuItem;
@@ -71,7 +71,10 @@ public class KeyServerQueryActivity extends BaseActivity {
switch (item.getItemId()) {
case android.R.id.home:
- startActivity(new Intent(this, PublicKeyListActivity.class));
+ // app icon in Action Bar clicked; go home
+ Intent intent = new Intent(this, PublicKeyListActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ startActivity(intent);
return true;
default:
@@ -118,11 +121,11 @@ public class KeyServerQueryActivity extends BaseActivity {
});
Intent intent = getIntent();
- if (Apg.Intent.LOOK_UP_KEY_ID.equals(intent.getAction())
- || Apg.Intent.LOOK_UP_KEY_ID_AND_RETURN.equals(intent.getAction())) {
- long keyId = intent.getLongExtra(Apg.EXTRA_KEY_ID, 0);
+ if (PGPHelper.Intent.LOOK_UP_KEY_ID.equals(intent.getAction())
+ || PGPHelper.Intent.LOOK_UP_KEY_ID_AND_RETURN.equals(intent.getAction())) {
+ long keyId = intent.getLongExtra(PGPHelper.EXTRA_KEY_ID, 0);
if (keyId != 0) {
- String query = "0x" + Apg.keyToHex(keyId);
+ String query = "0x" + PGPHelper.keyToHex(keyId);
mQuery.setText(query);
search(query);
}
@@ -176,7 +179,7 @@ public class KeyServerQueryActivity extends BaseActivity {
data.putInt(Constants.extras.STATUS, Id.message.done);
if (error != null) {
- data.putString(Apg.EXTRA_ERROR, error);
+ data.putString(PGPHelper.EXTRA_ERROR, error);
}
msg.setData(data);
@@ -190,7 +193,7 @@ public class KeyServerQueryActivity extends BaseActivity {
removeDialog(Id.dialog.querying);
Bundle data = msg.getData();
- String error = data.getString(Apg.EXTRA_ERROR);
+ String error = data.getString(PGPHelper.EXTRA_ERROR);
if (error != null) {
Toast.makeText(this, getString(R.string.errorMessage, error), Toast.LENGTH_SHORT)
.show();
@@ -205,10 +208,10 @@ public class KeyServerQueryActivity extends BaseActivity {
}
} else if (mQueryType == Id.keyserver.get) {
Intent orgIntent = getIntent();
- if (Apg.Intent.LOOK_UP_KEY_ID_AND_RETURN.equals(orgIntent.getAction())) {
+ if (PGPHelper.Intent.LOOK_UP_KEY_ID_AND_RETURN.equals(orgIntent.getAction())) {
if (mKeyData != null) {
Intent intent = new Intent();
- intent.putExtra(Apg.EXTRA_TEXT, mKeyData);
+ intent.putExtra(PGPHelper.EXTRA_TEXT, mKeyData);
setResult(RESULT_OK, intent);
} else {
setResult(RESULT_CANCELED);
@@ -217,8 +220,8 @@ public class KeyServerQueryActivity extends BaseActivity {
} else {
if (mKeyData != null) {
Intent intent = new Intent(this, PublicKeyListActivity.class);
- intent.setAction(Apg.Intent.IMPORT);
- intent.putExtra(Apg.EXTRA_TEXT, mKeyData);
+ intent.setAction(PGPHelper.Intent.IMPORT);
+ intent.putExtra(PGPHelper.EXTRA_TEXT, mKeyData);
startActivity(intent);
}
}
@@ -284,7 +287,7 @@ public class KeyServerQueryActivity extends BaseActivity {
mainUserId.setText(userId);
}
- keyId.setText(Apg.getSmallFingerPrint(keyInfo.keyId));
+ keyId.setText(PGPHelper.getSmallFingerPrint(keyInfo.keyId));
if (mainUserIdRest.getText().length() == 0) {
mainUserIdRest.setVisibility(View.GONE);
diff --git a/org_apg/src/org/thialfihar/android/apg/ui/MailListActivity.java b/org_apg/src/org/thialfihar/android/apg/ui/MailListActivity.java
index 639aab6eb..fd8efb530 100644
--- a/org_apg/src/org/thialfihar/android/apg/ui/MailListActivity.java
+++ b/org_apg/src/org/thialfihar/android/apg/ui/MailListActivity.java
@@ -20,8 +20,8 @@ import java.util.Vector;
import java.util.regex.Matcher;
import org.thialfihar.android.apg.R;
-import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Preferences;
+import org.thialfihar.android.apg.helper.PGPHelper;
import android.app.ListActivity;
import android.content.Context;
@@ -121,11 +121,11 @@ public class MailListActivity extends ListActivity {
String data = messageCursor.getString(bodyIndex);
data = Html.fromHtml(data).toString();
boolean signedOnly = false;
- Matcher matcher = Apg.PGP_MESSAGE.matcher(data);
+ Matcher matcher = PGPHelper.PGP_MESSAGE.matcher(data);
if (matcher.matches()) {
data = matcher.group(1);
} else {
- matcher = Apg.PGP_SIGNED_MESSAGE.matcher(data);
+ matcher = PGPHelper.PGP_SIGNED_MESSAGE.matcher(data);
if (matcher.matches()) {
data = matcher.group(1);
signedOnly = true;
@@ -149,11 +149,11 @@ public class MailListActivity extends ListActivity {
getListView().setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView> arg0, View v, int position, long id) {
Intent intent = new Intent(MailListActivity.this, DecryptActivity.class);
- intent.setAction(Apg.Intent.DECRYPT);
+ intent.setAction(PGPHelper.Intent.DECRYPT);
Message message = (Message) ((MailboxAdapter) getListAdapter()).getItem(position);
- intent.putExtra(Apg.EXTRA_TEXT, message.data);
- intent.putExtra(Apg.EXTRA_SUBJECT, message.subject);
- intent.putExtra(Apg.EXTRA_REPLY_TO, message.replyTo);
+ intent.putExtra(PGPHelper.EXTRA_TEXT, message.data);
+ intent.putExtra(PGPHelper.EXTRA_SUBJECT, message.subject);
+ intent.putExtra(PGPHelper.EXTRA_REPLY_TO, message.replyTo);
startActivity(intent);
}
});
diff --git a/org_apg/src/org/thialfihar/android/apg/ui/MainActivity.java b/org_apg/src/org/thialfihar/android/apg/ui/MainActivity.java
index 4bfee0e14..24d636627 100644
--- a/org_apg/src/org/thialfihar/android/apg/ui/MainActivity.java
+++ b/org_apg/src/org/thialfihar/android/apg/ui/MainActivity.java
@@ -20,9 +20,9 @@ package org.thialfihar.android.apg.ui;
import java.security.Security;
import org.spongycastle.jce.provider.BouncyCastleProvider;
-import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Id;
import org.thialfihar.android.apg.R;
+import org.thialfihar.android.apg.helper.PGPHelper;
import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.SherlockActivity;
@@ -48,19 +48,19 @@ public class MainActivity extends SherlockActivity {
public void encryptOnClick(View view) {
Intent intent = new Intent(MainActivity.this, EncryptActivity.class);
- intent.setAction(Apg.Intent.ENCRYPT);
+ intent.setAction(PGPHelper.Intent.ENCRYPT);
startActivityForResult(intent, 0); // used instead of startActivity to get callingPackage
}
public void decryptOnClick(View view) {
Intent intent = new Intent(MainActivity.this, DecryptActivity.class);
- intent.setAction(Apg.Intent.DECRYPT);
+ intent.setAction(PGPHelper.Intent.DECRYPT);
startActivityForResult(intent, 0); // used instead of startActivity to get callingPackage
}
public void scanQrcodeOnClick(View view) {
Intent intent = new Intent(this, ImportFromQRCodeActivity.class);
- intent.setAction(Apg.Intent.IMPORT_FROM_QR_CODE);
+ intent.setAction(PGPHelper.Intent.IMPORT_FROM_QR_CODE);
startActivityForResult(intent, Id.request.import_from_qr_code);
}
diff --git a/org_apg/src/org/thialfihar/android/apg/ui/PreferencesActivity.java b/org_apg/src/org/thialfihar/android/apg/ui/PreferencesActivity.java
index b602e92b8..3cc6155b0 100644
--- a/org_apg/src/org/thialfihar/android/apg/ui/PreferencesActivity.java
+++ b/org_apg/src/org/thialfihar/android/apg/ui/PreferencesActivity.java
@@ -18,10 +18,10 @@ package org.thialfihar.android.apg.ui;
import org.spongycastle.bcpg.HashAlgorithmTags;
import org.spongycastle.openpgp.PGPEncryptedData;
-import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Constants;
import org.thialfihar.android.apg.Id;
import org.thialfihar.android.apg.Preferences;
+import org.thialfihar.android.apg.helper.PGPHelper;
import org.thialfihar.android.apg.passphrase.PassphraseCacheService;
import org.thialfihar.android.apg.ui.widget.IntegerListPreference;
import org.thialfihar.android.apg.R;
@@ -36,7 +36,6 @@ import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.PreferenceScreen;
-
public class PreferencesActivity extends SherlockPreferenceActivity {
private IntegerListPreference mPassPhraseCacheTtl = null;
private IntegerListPreference mEncryptionAlgorithm = null;
@@ -56,6 +55,7 @@ public class PreferencesActivity extends SherlockPreferenceActivity {
final ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setHomeButtonEnabled(true);
addPreferencesFromResource(R.xml.apg_preferences);
@@ -68,7 +68,7 @@ public class PreferencesActivity extends SherlockPreferenceActivity {
mPassPhraseCacheTtl.setValue(newValue.toString());
mPassPhraseCacheTtl.setSummary(mPassPhraseCacheTtl.getEntry());
mPreferences.setPassPhraseCacheTtl(Integer.parseInt(newValue.toString()));
-
+
// restart cache service with new ttl
PassphraseCacheService.startCacheService(PreferencesActivity.this);
return false;
@@ -194,8 +194,8 @@ public class PreferencesActivity extends SherlockPreferenceActivity {
.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
Intent intent = new Intent(PreferencesActivity.this,
- KeyServerPreferenceActivity.class);
- intent.putExtra(Apg.EXTRA_KEY_SERVERS, mPreferences.getKeyServers());
+ PreferencesKeyServerActivity.class);
+ intent.putExtra(PGPHelper.EXTRA_KEY_SERVERS, mPreferences.getKeyServers());
startActivityForResult(intent, Id.request.key_server_preference);
return false;
}
@@ -209,7 +209,7 @@ public class PreferencesActivity extends SherlockPreferenceActivity {
if (resultCode == RESULT_CANCELED || data == null) {
return;
}
- String servers[] = data.getStringArrayExtra(Apg.EXTRA_KEY_SERVERS);
+ String servers[] = data.getStringArrayExtra(PGPHelper.EXTRA_KEY_SERVERS);
mPreferences.setKeyServers(servers);
mKeyServerPreference.setSummary(getResources().getString(R.string.nKeyServers,
servers.length));
@@ -228,7 +228,10 @@ public class PreferencesActivity extends SherlockPreferenceActivity {
switch (item.getItemId()) {
case android.R.id.home:
- startActivity(new Intent(this, MainActivity.class));
+ // app icon in Action Bar clicked; go home
+ Intent intent = new Intent(this, MainActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ startActivity(intent);
return true;
default:
diff --git a/org_apg/src/org/thialfihar/android/apg/ui/PreferencesKeyServerActivity.java b/org_apg/src/org/thialfihar/android/apg/ui/PreferencesKeyServerActivity.java
new file mode 100644
index 000000000..ae2cfa0ea
--- /dev/null
+++ b/org_apg/src/org/thialfihar/android/apg/ui/PreferencesKeyServerActivity.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2010 Thialfihar
+ *
+ * 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.thialfihar.android.apg.ui;
+
+import java.util.Vector;
+
+import org.thialfihar.android.apg.Id;
+import org.thialfihar.android.apg.R;
+import org.thialfihar.android.apg.helper.PGPHelper;
+import org.thialfihar.android.apg.ui.widget.Editor;
+import org.thialfihar.android.apg.ui.widget.KeyServerEditor;
+import org.thialfihar.android.apg.ui.widget.Editor.EditorListener;
+
+import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.app.SherlockActivity;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuItem;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class PreferencesKeyServerActivity extends SherlockActivity implements OnClickListener,
+ EditorListener {
+ private LayoutInflater mInflater;
+ private ViewGroup mEditors;
+ private View mAdd;
+ private TextView mTitle;
+ private TextView mSummary;
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+
+ case android.R.id.home:
+ // app icon in Action Bar clicked; go home
+ Intent intent = new Intent(this, PreferencesActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ startActivity(intent);
+
+ return true;
+
+ case Id.menu.option.okay:
+ okClicked();
+
+ return true;
+
+ case Id.menu.option.cancel:
+ cancelClicked();
+
+ return true;
+
+ default:
+ break;
+
+ }
+ return false;
+ }
+
+ /**
+ * ActionBar menu is created based on class variables to change it at runtime
+ *
+ */
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+
+ menu.add(1, Id.menu.option.cancel, 0, android.R.string.cancel).setShowAsAction(
+ MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+
+ menu.add(1, Id.menu.option.okay, 1, android.R.string.ok).setShowAsAction(
+ MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+
+ return true;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.key_server_preference);
+
+ final ActionBar actionBar = getSupportActionBar();
+ actionBar.setDisplayShowTitleEnabled(true);
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setHomeButtonEnabled(true);
+
+ mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ mTitle = (TextView) findViewById(R.id.title);
+ mSummary = (TextView) findViewById(R.id.summary);
+
+ mTitle.setText(R.string.label_keyServers);
+
+ mEditors = (ViewGroup) findViewById(R.id.editors);
+ mAdd = findViewById(R.id.add);
+ mAdd.setOnClickListener(this);
+
+ Intent intent = getIntent();
+ String servers[] = intent.getStringArrayExtra(PGPHelper.EXTRA_KEY_SERVERS);
+ if (servers != null) {
+ for (int i = 0; i < servers.length; ++i) {
+ KeyServerEditor view = (KeyServerEditor) mInflater.inflate(
+ R.layout.key_server_editor, mEditors, false);
+ view.setEditorListener(this);
+ view.setValue(servers[i]);
+ mEditors.addView(view);
+ }
+ }
+ }
+
+ public void onDeleted(Editor editor) {
+ // nothing to do
+ }
+
+ public void onClick(View v) {
+ KeyServerEditor view = (KeyServerEditor) mInflater.inflate(R.layout.key_server_editor,
+ mEditors, false);
+ view.setEditorListener(this);
+ mEditors.addView(view);
+ }
+
+ private void cancelClicked() {
+ setResult(RESULT_CANCELED, null);
+ finish();
+ }
+
+ private void okClicked() {
+ Intent data = new Intent();
+ Vector servers = new Vector();
+ for (int i = 0; i < mEditors.getChildCount(); ++i) {
+ KeyServerEditor editor = (KeyServerEditor) mEditors.getChildAt(i);
+ String tmp = editor.getValue();
+ if (tmp.length() > 0) {
+ servers.add(tmp);
+ }
+ }
+ String[] dummy = new String[0];
+ data.putExtra(PGPHelper.EXTRA_KEY_SERVERS, servers.toArray(dummy));
+ setResult(RESULT_OK, data);
+ finish();
+ }
+}
diff --git a/org_apg/src/org/thialfihar/android/apg/ui/PublicKeyListActivity.java b/org_apg/src/org/thialfihar/android/apg/ui/PublicKeyListActivity.java
index a2551b769..21a7ddee5 100644
--- a/org_apg/src/org/thialfihar/android/apg/ui/PublicKeyListActivity.java
+++ b/org_apg/src/org/thialfihar/android/apg/ui/PublicKeyListActivity.java
@@ -17,10 +17,10 @@
package org.thialfihar.android.apg.ui;
import org.spongycastle.openpgp.PGPPublicKeyRing;
-import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Constants;
import org.thialfihar.android.apg.Id;
import org.thialfihar.android.apg.R;
+import org.thialfihar.android.apg.helper.PGPHelper;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
@@ -71,7 +71,7 @@ public class PublicKeyListActivity extends KeyListActivity {
}
case Id.menu.option.scanQRCode: {
Intent intent = new Intent(this, ImportFromQRCodeActivity.class);
- intent.setAction(Apg.Intent.IMPORT_FROM_QR_CODE);
+ intent.setAction(PGPHelper.Intent.IMPORT_FROM_QR_CODE);
startActivityForResult(intent, Id.request.import_from_qr_code);
return true;
@@ -114,9 +114,9 @@ public class PublicKeyListActivity extends KeyListActivity {
mSelectedItem = groupPosition;
final int keyRingId = mListAdapter.getKeyRingId(groupPosition);
long keyId = 0;
- Object keyRing = Apg.getKeyRing(keyRingId);
+ Object keyRing = PGPHelper.getKeyRing(keyRingId);
if (keyRing != null && keyRing instanceof PGPPublicKeyRing) {
- keyId = Apg.getMasterKey((PGPPublicKeyRing) keyRing).getKeyID();
+ keyId = PGPHelper.getMasterKey((PGPPublicKeyRing) keyRing).getKeyID();
}
if (keyId == 0) {
// this shouldn't happen
@@ -124,8 +124,8 @@ public class PublicKeyListActivity extends KeyListActivity {
}
Intent intent = new Intent(this, KeyServerQueryActivity.class);
- intent.setAction(Apg.Intent.LOOK_UP_KEY_ID_AND_RETURN);
- intent.putExtra(Apg.EXTRA_KEY_ID, keyId);
+ intent.setAction(PGPHelper.Intent.LOOK_UP_KEY_ID_AND_RETURN);
+ intent.putExtra(PGPHelper.EXTRA_KEY_ID, keyId);
startActivityForResult(intent, Id.request.look_up_key_id);
return true;
@@ -136,8 +136,8 @@ public class PublicKeyListActivity extends KeyListActivity {
final int keyRingId = mListAdapter.getKeyRingId(groupPosition);
Intent intent = new Intent(this, KeyServerExportActivity.class);
- intent.setAction(Apg.Intent.EXPORT_KEY_TO_SERVER);
- intent.putExtra(Apg.EXTRA_KEY_ID, keyRingId);
+ intent.setAction(PGPHelper.Intent.EXPORT_KEY_TO_SERVER);
+ intent.putExtra(PGPHelper.EXTRA_KEY_ID, keyRingId);
startActivityForResult(intent, Id.request.export_to_server);
return true;
@@ -147,9 +147,9 @@ public class PublicKeyListActivity extends KeyListActivity {
mSelectedItem = groupPosition;
final int keyRingId = mListAdapter.getKeyRingId(groupPosition);
long keyId = 0;
- Object keyRing = Apg.getKeyRing(keyRingId);
+ Object keyRing = PGPHelper.getKeyRing(keyRingId);
if (keyRing != null && keyRing instanceof PGPPublicKeyRing) {
- keyId = Apg.getMasterKey((PGPPublicKeyRing) keyRing).getKeyID();
+ keyId = PGPHelper.getMasterKey((PGPPublicKeyRing) keyRing).getKeyID();
}
if (keyId == 0) {
@@ -158,7 +158,7 @@ public class PublicKeyListActivity extends KeyListActivity {
}
Intent intent = new Intent(this, SignKeyActivity.class);
- intent.putExtra(Apg.EXTRA_KEY_ID, keyId);
+ intent.putExtra(PGPHelper.EXTRA_KEY_ID, keyId);
startActivity(intent);
return true;
@@ -175,13 +175,13 @@ public class PublicKeyListActivity extends KeyListActivity {
switch (requestCode) {
case Id.request.look_up_key_id: {
if (resultCode == RESULT_CANCELED || data == null
- || data.getStringExtra(Apg.EXTRA_TEXT) == null) {
+ || data.getStringExtra(PGPHelper.EXTRA_TEXT) == null) {
return;
}
Intent intent = new Intent(this, PublicKeyListActivity.class);
- intent.setAction(Apg.Intent.IMPORT);
- intent.putExtra(Apg.EXTRA_TEXT, data.getStringExtra(Apg.EXTRA_TEXT));
+ intent.setAction(PGPHelper.Intent.IMPORT);
+ intent.putExtra(PGPHelper.EXTRA_TEXT, data.getStringExtra(PGPHelper.EXTRA_TEXT));
handleIntent(intent);
break;
}
diff --git a/org_apg/src/org/thialfihar/android/apg/ui/SecretKeyListActivity.java b/org_apg/src/org/thialfihar/android/apg/ui/SecretKeyListActivity.java
index b0475c147..290fe7479 100644
--- a/org_apg/src/org/thialfihar/android/apg/ui/SecretKeyListActivity.java
+++ b/org_apg/src/org/thialfihar/android/apg/ui/SecretKeyListActivity.java
@@ -17,9 +17,9 @@
package org.thialfihar.android.apg.ui;
import org.thialfihar.android.apg.R;
-import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Constants;
import org.thialfihar.android.apg.Id;
+import org.thialfihar.android.apg.helper.PGPHelper;
import org.thialfihar.android.apg.passphrase.AskForPassphrase;
import com.actionbarsherlock.view.Menu;
@@ -111,7 +111,7 @@ public class SecretKeyListActivity extends KeyListActivity implements OnChildCli
long keyId = ((KeyListAdapter) mList.getExpandableListAdapter())
.getGroupId(mSelectedItem);
- String msg = keyId + "," + Apg.getFingerPrint(keyId);
+ String msg = keyId + "," + PGPHelper.getFingerPrint(keyId);
new IntentIntegrator(this).shareText(msg);
}
@@ -146,11 +146,11 @@ public class SecretKeyListActivity extends KeyListActivity implements OnChildCli
public void checkPassPhraseAndEdit() {
long keyId = ((KeyListAdapter) mList.getExpandableListAdapter()).getGroupId(mSelectedItem);
- String passPhrase = Apg.getCachedPassPhrase(keyId);
+ String passPhrase = PGPHelper.getCachedPassPhrase(keyId);
if (passPhrase == null) {
showDialog(Id.dialog.pass_phrase);
} else {
- Apg.setEditPassPhrase(passPhrase);
+ PGPHelper.setEditPassPhrase(passPhrase);
editKey();
}
}
@@ -158,20 +158,20 @@ public class SecretKeyListActivity extends KeyListActivity implements OnChildCli
@Override
public void passPhraseCallback(long keyId, String passPhrase) {
super.passPhraseCallback(keyId, passPhrase);
- Apg.setEditPassPhrase(passPhrase);
+ PGPHelper.setEditPassPhrase(passPhrase);
editKey();
}
private void createKey() {
- Apg.setEditPassPhrase("");
- Intent intent = new Intent(Apg.Intent.CREATE_KEY);
+ PGPHelper.setEditPassPhrase("");
+ Intent intent = new Intent(PGPHelper.Intent.CREATE_KEY);
startActivityForResult(intent, Id.message.create_key);
}
private void editKey() {
long keyId = ((KeyListAdapter) mList.getExpandableListAdapter()).getGroupId(mSelectedItem);
- Intent intent = new Intent(Apg.Intent.EDIT_KEY);
- intent.putExtra(Apg.EXTRA_KEY_ID, keyId);
+ Intent intent = new Intent(PGPHelper.Intent.EDIT_KEY);
+ intent.putExtra(PGPHelper.EXTRA_KEY_ID, keyId);
startActivityForResult(intent, Id.message.edit_key);
}
diff --git a/org_apg/src/org/thialfihar/android/apg/ui/SelectPublicKeyListActivity.java b/org_apg/src/org/thialfihar/android/apg/ui/SelectPublicKeyListActivity.java
index 07ad60d89..93434912d 100644
--- a/org_apg/src/org/thialfihar/android/apg/ui/SelectPublicKeyListActivity.java
+++ b/org_apg/src/org/thialfihar/android/apg/ui/SelectPublicKeyListActivity.java
@@ -19,8 +19,8 @@ package org.thialfihar.android.apg.ui;
import java.util.Vector;
import org.thialfihar.android.apg.R;
-import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Id;
+import org.thialfihar.android.apg.helper.PGPHelper;
import org.thialfihar.android.apg.ui.widget.SelectPublicKeyListAdapter;
import com.actionbarsherlock.app.ActionBar;
@@ -89,7 +89,7 @@ public class SelectPublicKeyListActivity extends BaseActivity {
}
long selectedKeyIds[] = null;
- selectedKeyIds = intent.getLongArrayExtra(Apg.EXTRA_SELECTION);
+ selectedKeyIds = intent.getLongArrayExtra(PGPHelper.EXTRA_SELECTION);
if (selectedKeyIds == null) {
Vector vector = new Vector();
@@ -151,8 +151,8 @@ public class SelectPublicKeyListActivity extends BaseActivity {
selectedKeyIds[i] = keys.get(i);
}
String userIdArray[] = new String[0];
- data.putExtra(Apg.EXTRA_SELECTION, selectedKeyIds);
- data.putExtra(Apg.EXTRA_USER_IDS, userIds.toArray(userIdArray));
+ data.putExtra(PGPHelper.EXTRA_SELECTION, selectedKeyIds);
+ data.putExtra(PGPHelper.EXTRA_USER_IDS, userIds.toArray(userIdArray));
setResult(RESULT_OK, data);
finish();
}
diff --git a/org_apg/src/org/thialfihar/android/apg/ui/SelectSecretKeyListActivity.java b/org_apg/src/org/thialfihar/android/apg/ui/SelectSecretKeyListActivity.java
index dec88dd7f..1f5607d94 100644
--- a/org_apg/src/org/thialfihar/android/apg/ui/SelectSecretKeyListActivity.java
+++ b/org_apg/src/org/thialfihar/android/apg/ui/SelectSecretKeyListActivity.java
@@ -17,8 +17,8 @@
package org.thialfihar.android.apg.ui;
import org.thialfihar.android.apg.R;
-import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Id;
+import org.thialfihar.android.apg.helper.PGPHelper;
import org.thialfihar.android.apg.ui.widget.SelectSecretKeyListAdapter;
import com.actionbarsherlock.app.ActionBar;
@@ -62,8 +62,8 @@ public class SelectSecretKeyListActivity extends BaseActivity {
mList.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView> adapterView, View view, int position, long id) {
Intent data = new Intent();
- data.putExtra(Apg.EXTRA_KEY_ID, id);
- data.putExtra(Apg.EXTRA_USER_ID, (String) mList.getItemAtPosition(position));
+ data.putExtra(PGPHelper.EXTRA_KEY_ID, id);
+ data.putExtra(PGPHelper.EXTRA_USER_ID, (String) mList.getItemAtPosition(position));
setResult(RESULT_OK, data);
finish();
}
diff --git a/org_apg/src/org/thialfihar/android/apg/ui/SignKeyActivity.java b/org_apg/src/org/thialfihar/android/apg/ui/SignKeyActivity.java
index d853873e1..43c481a74 100644
--- a/org_apg/src/org/thialfihar/android/apg/ui/SignKeyActivity.java
+++ b/org_apg/src/org/thialfihar/android/apg/ui/SignKeyActivity.java
@@ -1,4 +1,6 @@
/*
+ * Copyright (C) 2011 Senecaso
+ *
* 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
@@ -30,11 +32,11 @@ import org.spongycastle.openpgp.PGPSignatureGenerator;
import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator;
import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
import org.spongycastle.openpgp.PGPUtil;
-import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Constants;
import org.thialfihar.android.apg.HkpKeyServer;
import org.thialfihar.android.apg.Id;
import org.thialfihar.android.apg.R;
+import org.thialfihar.android.apg.helper.PGPHelper;
import com.actionbarsherlock.view.MenuItem;
@@ -122,7 +124,7 @@ public class SignKeyActivity extends BaseActivity {
}
});
- pubKeyId = getIntent().getLongExtra(Apg.EXTRA_KEY_ID, 0);
+ pubKeyId = getIntent().getLongExtra(PGPHelper.EXTRA_KEY_ID, 0);
if (pubKeyId == 0) {
finish(); // nothing to do if we dont know what key to sign
} else {
@@ -137,7 +139,7 @@ public class SignKeyActivity extends BaseActivity {
* handles the UI bits of the signing process on the UI thread
*/
private void initiateSigning() {
- PGPPublicKeyRing pubring = Apg.getPublicKeyRing(pubKeyId);
+ PGPPublicKeyRing pubring = PGPHelper.getPublicKeyRing(pubKeyId);
if (pubring != null) {
// if we have already signed this key, dont bother doing it again
boolean alreadySigned = false;
@@ -156,7 +158,7 @@ public class SignKeyActivity extends BaseActivity {
/*
* get the user's passphrase for this key (if required)
*/
- String passphrase = Apg.getCachedPassPhrase(masterKeyId);
+ String passphrase = PGPHelper.getCachedPassPhrase(masterKeyId);
if (passphrase == null) {
showDialog(Id.dialog.pass_phrase);
return; // bail out; need to wait until the user has entered the passphrase
@@ -168,7 +170,7 @@ public class SignKeyActivity extends BaseActivity {
final Bundle status = new Bundle();
Message msg = new Message();
- status.putString(Apg.EXTRA_ERROR, "Key has already been signed");
+ status.putString(PGPHelper.EXTRA_ERROR, "Key has already been signed");
status.putInt(Constants.extras.STATUS, Id.message.done);
@@ -206,16 +208,16 @@ public class SignKeyActivity extends BaseActivity {
Message msg = new Message();
try {
- String passphrase = Apg.getCachedPassPhrase(masterKeyId);
+ String passphrase = PGPHelper.getCachedPassPhrase(masterKeyId);
if (passphrase == null || passphrase.length() <= 0) {
- status.putString(Apg.EXTRA_ERROR, "Unable to obtain passphrase");
+ status.putString(PGPHelper.EXTRA_ERROR, "Unable to obtain passphrase");
} else {
- PGPPublicKeyRing pubring = Apg.getPublicKeyRing(pubKeyId);
+ PGPPublicKeyRing pubring = PGPHelper.getPublicKeyRing(pubKeyId);
/*
* sign the incoming key
*/
- PGPSecretKey secretKey = Apg.getSecretKey(masterKeyId);
+ PGPSecretKey secretKey = PGPHelper.getSecretKey(masterKeyId);
PGPPrivateKey signingKey = secretKey.extractPrivateKey(passphrase.toCharArray(),
BouncyCastleProvider.PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(secretKey.getPublicKey()
@@ -241,33 +243,33 @@ public class SignKeyActivity extends BaseActivity {
* upload the newly signed key to the key server
*/
- Apg.uploadKeyRingToServer(server, pubring);
+ PGPHelper.uploadKeyRingToServer(server, pubring);
}
// store the signed key in our local cache
- int retval = Apg.storeKeyRingInCache(pubring);
+ int retval = PGPHelper.storeKeyRingInCache(pubring);
if (retval != Id.return_value.ok && retval != Id.return_value.updated) {
- status.putString(Apg.EXTRA_ERROR, "Failed to store signed key in local cache");
+ status.putString(PGPHelper.EXTRA_ERROR, "Failed to store signed key in local cache");
}
}
} catch (PGPException e) {
Log.e(TAG, "Failed to sign key", e);
- status.putString(Apg.EXTRA_ERROR, "Failed to sign key");
+ status.putString(PGPHelper.EXTRA_ERROR, "Failed to sign key");
status.putInt(Constants.extras.STATUS, Id.message.done);
return;
} catch (NoSuchAlgorithmException e) {
Log.e(TAG, "Failed to sign key", e);
- status.putString(Apg.EXTRA_ERROR, "Failed to sign key");
+ status.putString(PGPHelper.EXTRA_ERROR, "Failed to sign key");
status.putInt(Constants.extras.STATUS, Id.message.done);
return;
} catch (NoSuchProviderException e) {
Log.e(TAG, "Failed to sign key", e);
- status.putString(Apg.EXTRA_ERROR, "Failed to sign key");
+ status.putString(PGPHelper.EXTRA_ERROR, "Failed to sign key");
status.putInt(Constants.extras.STATUS, Id.message.done);
return;
} catch (SignatureException e) {
Log.e(TAG, "Failed to sign key", e);
- status.putString(Apg.EXTRA_ERROR, "Failed to sign key");
+ status.putString(PGPHelper.EXTRA_ERROR, "Failed to sign key");
status.putInt(Constants.extras.STATUS, Id.message.done);
return;
}
@@ -277,7 +279,7 @@ public class SignKeyActivity extends BaseActivity {
msg.setData(status);
sendMessage(msg);
- if (status.containsKey(Apg.EXTRA_ERROR)) {
+ if (status.containsKey(PGPHelper.EXTRA_ERROR)) {
setResult(Id.return_value.error);
} else {
setResult(Id.return_value.ok);
@@ -291,7 +293,7 @@ public class SignKeyActivity extends BaseActivity {
switch (requestCode) {
case Id.request.secret_keys: {
if (resultCode == RESULT_OK) {
- masterKeyId = data.getLongExtra(Apg.EXTRA_KEY_ID, 0);
+ masterKeyId = data.getLongExtra(PGPHelper.EXTRA_KEY_ID, 0);
// re-enable the sign button so the user can initiate the sign process
Button sign = (Button) findViewById(R.id.sign);
@@ -314,7 +316,7 @@ public class SignKeyActivity extends BaseActivity {
removeDialog(Id.dialog.signing);
Bundle data = msg.getData();
- String error = data.getString(Apg.EXTRA_ERROR);
+ String error = data.getString(PGPHelper.EXTRA_ERROR);
if (error != null) {
Toast.makeText(this, getString(R.string.errorMessage, error), Toast.LENGTH_SHORT)
.show();
diff --git a/org_apg/src/org/thialfihar/android/apg/ui/dialog/FileDialogFragment.java b/org_apg/src/org/thialfihar/android/apg/ui/dialog/FileDialogFragment.java
index 7f1fbf87b..531cddfcf 100644
--- a/org_apg/src/org/thialfihar/android/apg/ui/dialog/FileDialogFragment.java
+++ b/org_apg/src/org/thialfihar/android/apg/ui/dialog/FileDialogFragment.java
@@ -18,7 +18,8 @@ package org.thialfihar.android.apg.ui.dialog;
import org.thialfihar.android.apg.Constants;
import org.thialfihar.android.apg.R;
-import org.thialfihar.android.apg.util.Utils;
+import org.thialfihar.android.apg.helper.FileHelper;
+import org.thialfihar.android.apg.helper.OtherHelper;
import android.app.Activity;
import android.app.AlertDialog;
@@ -51,7 +52,7 @@ public class FileDialogFragment extends DialogFragment {
public static final int MESSAGE_OKAY = 1;
public static final String MESSAGE_DATA_FILENAME = "filename";
- public static final String MESSAGE_CHECKED = "checked";
+ public static final String MESSAGE_DATA_CHECKED = "checked";
/**
* Creates new instance of this file dialog fragment
@@ -107,7 +108,7 @@ public class FileDialogFragment extends DialogFragment {
mBrowse.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// only .asc or .gpg files
- Utils.openFile(activity, mFilename.getText().toString(), "text/plain", requestCode);
+ FileHelper.openFile(activity, mFilename.getText().toString(), "text/plain", requestCode);
}
});
@@ -135,7 +136,7 @@ public class FileDialogFragment extends DialogFragment {
// return resulting data back to activity
Bundle data = new Bundle();
data.putString(MESSAGE_DATA_FILENAME, mFilename.getText().toString());
- data.putBoolean(MESSAGE_CHECKED, checked);
+ data.putBoolean(MESSAGE_DATA_CHECKED, checked);
sendMessageToHandler(MESSAGE_OKAY, data);
diff --git a/org_apg/src/org/thialfihar/android/apg/ui/dialog/PassphraseDialogFragment.java b/org_apg/src/org/thialfihar/android/apg/ui/dialog/PassphraseDialogFragment.java
index 3b83aaaa3..ce08c6c86 100644
--- a/org_apg/src/org/thialfihar/android/apg/ui/dialog/PassphraseDialogFragment.java
+++ b/org_apg/src/org/thialfihar/android/apg/ui/dialog/PassphraseDialogFragment.java
@@ -21,8 +21,8 @@ import org.spongycastle.openpgp.PGPPrivateKey;
import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
-import org.thialfihar.android.apg.Apg;
-import org.thialfihar.android.apg.Apg.GeneralException;
+import org.thialfihar.android.apg.helper.PGPHelper;
+import org.thialfihar.android.apg.helper.PGPHelper.GeneralException;
import org.thialfihar.android.apg.Constants;
import org.thialfihar.android.apg.Id;
import org.thialfihar.android.apg.R;
@@ -68,7 +68,7 @@ public class PassphraseDialogFragment extends DialogFragment {
// check if secret key has a passphrase
if (!(secretKeyId == Id.key.symmetric || secretKeyId == Id.key.none)) {
if (!hasPassphrase(secretKeyId)) {
- throw new Apg.GeneralException("No passphrase! No passphrase dialog needed!");
+ throw new PGPHelper.GeneralException("No passphrase! No passphrase dialog needed!");
}
}
@@ -91,7 +91,7 @@ public class PassphraseDialogFragment extends DialogFragment {
private static boolean hasPassphrase(long secretKeyId) {
// check if the key has no passphrase
try {
- PGPSecretKey secretKey = Apg.getMasterKey(Apg.getSecretKeyRing(secretKeyId));
+ PGPSecretKey secretKey = PGPHelper.getMasterKey(PGPHelper.getSecretKeyRing(secretKeyId));
Log.d(Constants.TAG, "Check if key has no passphrase...");
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
@@ -101,7 +101,7 @@ public class PassphraseDialogFragment extends DialogFragment {
Log.d(Constants.TAG, "Key has no passphrase! Caches empty passphrase!");
// cache empty passphrase
- Apg.setCachedPassPhrase(secretKey.getKeyID(), "");
+ PGPHelper.setCachedPassPhrase(secretKey.getKeyID(), "");
return false;
}
@@ -132,7 +132,7 @@ public class PassphraseDialogFragment extends DialogFragment {
secretKey = null;
alert.setMessage(getString(R.string.passPhraseForSymmetricEncryption));
} else {
- secretKey = Apg.getMasterKey(Apg.getSecretKeyRing(secretKeyId));
+ secretKey = PGPHelper.getMasterKey(PGPHelper.getSecretKeyRing(secretKeyId));
if (secretKey == null) {
alert.setTitle(R.string.title_keyNotFound);
alert.setMessage(getString(R.string.keyNotFound, secretKeyId));
@@ -144,7 +144,7 @@ public class PassphraseDialogFragment extends DialogFragment {
alert.setCancelable(false);
return alert.create();
}
- String userId = Apg.getMainUserIdSafe(activity, secretKey);
+ String userId = PGPHelper.getMainUserIdSafe(activity, secretKey);
alert.setMessage(getString(R.string.passPhraseFor, userId));
}
@@ -189,7 +189,7 @@ public class PassphraseDialogFragment extends DialogFragment {
// cache the new passphrase
Log.d(Constants.TAG, "Everything okay! Caching entered passphrase");
- Apg.setCachedPassPhrase(keyId, passPhrase);
+ PGPHelper.setCachedPassPhrase(keyId, passPhrase);
sendMessageToHandler(MESSAGE_OKAY);
}
diff --git a/org_apg/src/org/thialfihar/android/apg/ui/widget/KeyEditor.java b/org_apg/src/org/thialfihar/android/apg/ui/widget/KeyEditor.java
index 9f7b756eb..87d715fd9 100644
--- a/org_apg/src/org/thialfihar/android/apg/ui/widget/KeyEditor.java
+++ b/org_apg/src/org/thialfihar/android/apg/ui/widget/KeyEditor.java
@@ -18,8 +18,8 @@ package org.thialfihar.android.apg.ui.widget;
import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPSecretKey;
-import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Id;
+import org.thialfihar.android.apg.helper.PGPHelper;
import org.thialfihar.android.apg.util.Choice;
import org.thialfihar.android.apg.R;
@@ -133,9 +133,9 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
mDeleteButton.setVisibility(View.INVISIBLE);
}
- mAlgorithm.setText(Apg.getAlgorithmInfo(key));
- String keyId1Str = Apg.getSmallFingerPrint(key.getKeyID());
- String keyId2Str = Apg.getSmallFingerPrint(key.getKeyID() >> 32);
+ mAlgorithm.setText(PGPHelper.getAlgorithmInfo(key));
+ String keyId1Str = PGPHelper.getSmallFingerPrint(key.getKeyID());
+ String keyId2Str = PGPHelper.getSmallFingerPrint(key.getKeyID() >> 32);
mKeyId.setText(keyId1Str + " " + keyId2Str);
Vector choices = new Vector();
@@ -160,8 +160,8 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
// Set value in choice dropdown to key
int selectId = 0;
- if (Apg.isEncryptionKey(key)) {
- if (Apg.isSigningKey(key)) {
+ if (PGPHelper.isEncryptionKey(key)) {
+ if (PGPHelper.isSigningKey(key)) {
selectId = Id.choice.usage.sign_and_encrypt;
} else {
selectId = Id.choice.usage.encrypt_only;
@@ -184,14 +184,14 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
}
GregorianCalendar cal = new GregorianCalendar();
- cal.setTime(Apg.getCreationDate(key));
+ cal.setTime(PGPHelper.getCreationDate(key));
mCreationDate.setText(DateFormat.getDateInstance().format(cal.getTime()));
cal = new GregorianCalendar();
- Date date = Apg.getExpiryDate(key);
+ Date date = PGPHelper.getExpiryDate(key);
if (date == null) {
setExpiryDate(null);
} else {
- cal.setTime(Apg.getExpiryDate(key));
+ cal.setTime(PGPHelper.getExpiryDate(key));
setExpiryDate(cal);
}
diff --git a/org_apg/src/org/thialfihar/android/apg/ui/widget/SectionView.java b/org_apg/src/org/thialfihar/android/apg/ui/widget/SectionView.java
index 98532a00b..22a2ecb5b 100644
--- a/org_apg/src/org/thialfihar/android/apg/ui/widget/SectionView.java
+++ b/org_apg/src/org/thialfihar/android/apg/ui/widget/SectionView.java
@@ -18,14 +18,14 @@ package org.thialfihar.android.apg.ui.widget;
import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing;
-import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Id;
+import org.thialfihar.android.apg.helper.PGPHelper;
+import org.thialfihar.android.apg.helper.PGPConversionHelper;
import org.thialfihar.android.apg.service.ApgHandler;
import org.thialfihar.android.apg.service.ApgService;
import org.thialfihar.android.apg.ui.dialog.ProgressDialogFragment;
import org.thialfihar.android.apg.ui.widget.Editor.EditorListener;
import org.thialfihar.android.apg.util.Choice;
-import org.thialfihar.android.apg.util.Utils;
import org.thialfihar.android.apg.R;
import com.actionbarsherlock.app.SherlockFragmentActivity;
@@ -259,9 +259,10 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
String passPhrase;
if (mEditors.getChildCount() > 0) {
PGPSecretKey masterKey = ((KeyEditor) mEditors.getChildAt(0)).getValue();
- passPhrase = Apg.getCachedPassPhrase(masterKey.getKeyID());
+ passPhrase = PGPHelper.getCachedPassPhrase(masterKey.getKeyID());
- data.putByteArray(ApgService.MASTER_KEY, Utils.PGPSecretKeyToBytes(masterKey));
+ data.putByteArray(ApgService.MASTER_KEY,
+ PGPConversionHelper.PGPSecretKeyToBytes(masterKey));
} else {
passPhrase = "";
}
@@ -284,7 +285,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
if (message.arg1 == ApgHandler.MESSAGE_OKAY) {
// get new key from data bundle returned from service
Bundle data = message.getData();
- PGPSecretKeyRing newKeyRing = Utils.BytesToPGPSecretKeyRing(data
+ PGPSecretKeyRing newKeyRing = PGPConversionHelper.BytesToPGPSecretKeyRing(data
.getByteArray(ApgService.RESULT_NEW_KEY));
boolean isMasterKey = (mEditors.getChildCount() == 0);
diff --git a/org_apg/src/org/thialfihar/android/apg/ui/widget/SelectPublicKeyListAdapter.java b/org_apg/src/org/thialfihar/android/apg/ui/widget/SelectPublicKeyListAdapter.java
index 39e68fb81..240d6a078 100644
--- a/org_apg/src/org/thialfihar/android/apg/ui/widget/SelectPublicKeyListAdapter.java
+++ b/org_apg/src/org/thialfihar/android/apg/ui/widget/SelectPublicKeyListAdapter.java
@@ -19,8 +19,8 @@ package org.thialfihar.android.apg.ui.widget;
import java.util.Date;
import org.thialfihar.android.apg.R;
-import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Id;
+import org.thialfihar.android.apg.helper.PGPHelper;
import org.thialfihar.android.apg.provider.KeyRings;
import org.thialfihar.android.apg.provider.Keys;
import org.thialfihar.android.apg.provider.UserIds;
@@ -53,7 +53,7 @@ public class SelectPublicKeyListAdapter extends BaseAdapter {
mActivity = activity;
mParent = parent;
- mDatabase = Apg.getDatabase().db();
+ mDatabase = PGPHelper.getDatabase().db();
mInflater = (LayoutInflater) parent.getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
long now = new Date().getTime() / 1000;
@@ -177,7 +177,7 @@ public class SelectPublicKeyListAdapter extends BaseAdapter {
}
long masterKeyId = mCursor.getLong(1); // MASTER_KEY_ID
- keyId.setText(Apg.getSmallFingerPrint(masterKeyId));
+ keyId.setText(PGPHelper.getSmallFingerPrint(masterKeyId));
if (mainUserIdRest.getText().length() == 0) {
mainUserIdRest.setVisibility(View.GONE);
diff --git a/org_apg/src/org/thialfihar/android/apg/ui/widget/SelectSecretKeyListAdapter.java b/org_apg/src/org/thialfihar/android/apg/ui/widget/SelectSecretKeyListAdapter.java
index 0f4c8e6d1..fc8c4e8b0 100644
--- a/org_apg/src/org/thialfihar/android/apg/ui/widget/SelectSecretKeyListAdapter.java
+++ b/org_apg/src/org/thialfihar/android/apg/ui/widget/SelectSecretKeyListAdapter.java
@@ -17,8 +17,8 @@ package org.thialfihar.android.apg.ui.widget;
import java.util.Date;
import org.thialfihar.android.apg.R;
-import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Id;
+import org.thialfihar.android.apg.helper.PGPHelper;
import org.thialfihar.android.apg.provider.KeyRings;
import org.thialfihar.android.apg.provider.Keys;
import org.thialfihar.android.apg.provider.UserIds;
@@ -48,7 +48,7 @@ public class SelectSecretKeyListAdapter extends BaseAdapter {
mActivity = activity;
mParent = parent;
- mDatabase = Apg.getDatabase().db();
+ mDatabase = PGPHelper.getDatabase().db();
mInflater = (LayoutInflater) parent.getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
long now = new Date().getTime() / 1000;
@@ -151,7 +151,7 @@ public class SelectSecretKeyListAdapter extends BaseAdapter {
}
long masterKeyId = mCursor.getLong(1); // MASTER_KEY_ID
- keyId.setText(Apg.getSmallFingerPrint(masterKeyId));
+ keyId.setText(PGPHelper.getSmallFingerPrint(masterKeyId));
if (mainUserIdRest.getText().length() == 0) {
mainUserIdRest.setVisibility(View.GONE);
diff --git a/org_apg/src/org/thialfihar/android/apg/util/ApgCon.java b/org_apg/src/org/thialfihar/android/apg/util/ApgCon.java
deleted file mode 100644
index 7341341d5..000000000
--- a/org_apg/src/org/thialfihar/android/apg/util/ApgCon.java
+++ /dev/null
@@ -1,836 +0,0 @@
-/*
- * Copyright (C) 2011 Markus Doits
- *
- * 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.thialfihar.android.apg.util;
-
-import org.thialfihar.android.apg.service.IApgService2;
-import org.thialfihar.android.apg.util.ApgConInterface.OnCallFinishListener;
-
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
-import android.content.pm.ServiceInfo;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.util.Log;
-
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
-
-/**
- * A APG-AIDL-Wrapper
- *
- *
- * This class can be used by other projects to simplify connecting to the
- * APG-AIDL-Service. Kind of wrapper of for AIDL.
- *
- *
- *
- * It is not used in this project.
- *
- *
- * @author Markus Doits
- * @version 1.1rc1
- *
- */
-public class ApgCon {
- private static final boolean LOCAL_LOGV = true;
- private static final boolean LOCAL_LOGD = true;
-
- private final static String TAG = "ApgCon";
- private final static int API_VERSION = 2; // aidl api-version it expects
- private final static String BLOB_URI = "content://org.thialfihar.android.apg.provider.apgserviceblobprovider";
-
- /**
- * How many seconds to wait for a connection to AGP when connecting.
- * Being unsuccessful for this number of seconds, a connection
- * is assumed to be failed.
- */
- public int secondsToWaitForConnection = 15;
-
- private class CallAsync extends AsyncTask {
-
- @Override
- protected Void doInBackground(String... arg) {
- if( LOCAL_LOGD ) Log.d(TAG, "Async execution starting");
- call(arg[0]);
- return null;
- }
-
- protected void onPostExecute(Void res) {
- if( LOCAL_LOGD ) Log.d(TAG, "Async execution finished");
- mAsyncRunning = false;
-
- }
-
- }
-
- private final Context mContext;
- private final error mConnectionStatus;
- private boolean mAsyncRunning = false;
- private OnCallFinishListener mOnCallFinishListener;
-
- private final Bundle mResult = new Bundle();
- private final Bundle mArgs = new Bundle();
- private final ArrayList mErrorList = new ArrayList();
- private final ArrayList mWarningList = new ArrayList();
-
- /** Remote service for decrypting and encrypting data */
- private IApgService2 mApgService = null;
-
- /** Set apgService accordingly to connection status */
- private ServiceConnection mApgConnection = new ServiceConnection() {
- public void onServiceConnected(ComponentName className, IBinder service) {
- if( LOCAL_LOGD ) Log.d(TAG, "IApgService bound to apgService");
- mApgService = IApgService2.Stub.asInterface(service);
- }
-
- public void onServiceDisconnected(ComponentName className) {
- if( LOCAL_LOGD ) Log.d(TAG, "IApgService disconnected");
- mApgService = null;
- }
- };
-
- /**
- * Different types of local errors
- */
- public static enum error {
- /**
- * no error
- */
- NO_ERROR,
- /**
- * generic error
- */
- GENERIC,
- /**
- * connection to apg service not possible
- */
- CANNOT_BIND_TO_APG,
- /**
- * function to call not provided
- */
- CALL_MISSING,
- /**
- * apg service does not know what to do
- */
- CALL_NOT_KNOWN,
- /**
- * could not find APG being installed
- */
- APG_NOT_FOUND,
- /**
- * found APG but without AIDL interface
- */
- APG_AIDL_MISSING,
- /**
- * found APG but with wrong API
- */
- APG_API_MISSMATCH
- }
-
- private static enum ret {
- ERROR, // returned from AIDL
- RESULT, // returned from AIDL
- WARNINGS, // mixed AIDL and LOCAL
- ERRORS, // mixed AIDL and LOCAL
- }
-
- /**
- * Constructor
- *
- *
- * Creates a new ApgCon object and searches for the right APG version on
- * initialization. If not found, errors are printed to the error log.
- *
- *
- * @param ctx
- * the running context
- */
- public ApgCon(Context ctx) {
- if( LOCAL_LOGV ) Log.v(TAG, "EncryptionService created");
- mContext = ctx;
-
- error tmpError = null;
- try {
- if( LOCAL_LOGV ) Log.v(TAG, "Searching for the right APG version");
- ServiceInfo apgServices[] = ctx.getPackageManager().getPackageInfo("org.thialfihar.android.apg",
- PackageManager.GET_SERVICES | PackageManager.GET_META_DATA).services;
- if (apgServices == null) {
- Log.e(TAG, "Could not fetch services");
- tmpError = error.GENERIC;
- } else {
- boolean apgServiceFound = false;
- for (ServiceInfo inf : apgServices) {
- if( LOCAL_LOGV ) Log.v(TAG, "Found service of APG: " + inf.name);
- if (inf.name.equals("org.thialfihar.android.apg.ApgService")) {
- apgServiceFound = true;
- if (inf.metaData == null) {
- Log.w(TAG, "Could not determine ApgService API");
- Log.w(TAG, "This probably won't work!");
- mWarningList.add("(LOCAL) Could not determine ApgService API");
- tmpError = error.APG_API_MISSMATCH;
- } else if (inf.metaData.getInt("api_version") != API_VERSION) {
- Log.w(TAG, "Found ApgService API version " + inf.metaData.getInt("api_version") + " but exspected " + API_VERSION);
- Log.w(TAG, "This probably won't work!");
- mWarningList.add("(LOCAL) Found ApgService API version " + inf.metaData.getInt("api_version") + " but exspected " + API_VERSION);
- tmpError = error.APG_API_MISSMATCH;
- } else {
- if( LOCAL_LOGV ) Log.v(TAG, "Found api_version " + API_VERSION + ", everything should work");
- tmpError = error.NO_ERROR;
- }
- }
- }
-
- if (!apgServiceFound) {
- Log.e(TAG, "Could not find APG with AIDL interface, this probably won't work");
- mErrorList.add("(LOCAL) Could not find APG with AIDL interface, this probably won't work");
- mResult.putInt(ret.ERROR.name(), error.APG_AIDL_MISSING.ordinal());
- tmpError = error.APG_NOT_FOUND;
- }
- }
- } catch (PackageManager.NameNotFoundException e) {
- Log.e(TAG, "Could not find APG, is it installed?", e);
- mErrorList.add("(LOCAL) Could not find APG, is it installed?");
- mResult.putInt(ret.ERROR.name(), error.APG_NOT_FOUND.ordinal());
- tmpError = error.APG_NOT_FOUND;
- }
-
- mConnectionStatus = tmpError;
-
- }
-
- /** try to connect to the apg service */
- private boolean connect() {
- if( LOCAL_LOGV ) Log.v(TAG, "trying to bind the apgService to context");
-
- if (mApgService != null) {
- if( LOCAL_LOGV ) Log.v(TAG, "allready connected");
- return true;
- }
-
- try {
- mContext.bindService(new Intent(IApgService2.class.getName()), mApgConnection, Context.BIND_AUTO_CREATE);
- } catch (Exception e) {
- Log.e(TAG, "could not bind APG service", e);
- return false;
- }
-
- int waitCount = 0;
- while (mApgService == null && waitCount++ < secondsToWaitForConnection) {
- if( LOCAL_LOGV ) Log.v(TAG, "sleeping 1 second to wait for apg");
- android.os.SystemClock.sleep(1000);
- }
-
- if (waitCount >= secondsToWaitForConnection) {
- if( LOCAL_LOGV ) Log.v(TAG, "slept waiting for nothing!");
- return false;
- }
-
- return true;
- }
-
- /**
- * Disconnects ApgCon from Apg
- *
- *
- * This should be called whenever all work with APG is done (e.g. everything
- * you wanted to encrypt is encrypted), since connections with AIDL should
- * not be upheld indefinitely.
- *
- *
- *
- * Also, if you destroy you end using your ApgCon-instance, this must be
- * called or else the connection to APG is leaked
- *
- */
- public void disconnect() {
- if( LOCAL_LOGV ) Log.v(TAG, "disconnecting apgService");
- if (mApgService != null) {
- mContext.unbindService(mApgConnection);
- mApgService = null;
- }
- }
-
- private boolean initialize() {
- if (mApgService == null) {
- if (!connect()) {
- if( LOCAL_LOGV ) Log.v(TAG, "connection to apg service failed");
- return false;
- }
- }
- return true;
- }
-
- /**
- * Calls a function from APG's AIDL-interface
- *
- *
- * After you have set up everything with {@link #setArg(String, String)}
- * (and variants), you can call a function of the AIDL-interface. This
- * will:
- *
- *
start connection to the remote interface (if not already connected)
- *
call the function passed with all parameters synchronously
- *
set up everything to retrieve the result and/or warnings/errors
- *
call the callback if provided
- *
- *
- *
- *
- * Note your thread will be blocked during execution - if you want to call
- * the function asynchronously, see {@link #callAsync(String)}.
- *
- *
- * @param function
- * a remote function to call
- * @return true, if call successful (= no errors), else false
- *
- * @see #callAsync(String)
- * @see #setArg(String, String)
- * @see #setOnCallFinishListener(OnCallFinishListener)
- */
- public boolean call(String function) {
- boolean success = this.call(function, mArgs, mResult);
- if (mOnCallFinishListener != null) {
- try {
- if( LOCAL_LOGD ) Log.d(TAG, "About to execute callback");
- mOnCallFinishListener.onCallFinish(mResult);
- if( LOCAL_LOGD ) Log.d(TAG, "Callback executed");
- } catch (Exception e) {
- Log.w(TAG, "Exception on callback: (" + e.getClass() + ") " + e.getMessage(), e);
- mWarningList.add("(LOCAL) Could not execute callback (" + e.getClass() + "): " + e.getMessage());
- }
- }
- return success;
- }
-
- /**
- * Calls a function of remote interface asynchronously
- *
- *
- * This does exactly the same as {@link #call(String)}, but asynchronously.
- * While connection to APG and work are done in background, your thread can
- * go on executing.
- *
- *
- *
- * To see whether the task is finished, you have two possibilities:
- *
- *
In your thread, poll {@link #isRunning()}
- *
Supply a callback with {@link #setOnCallFinishListener(OnCallFinishListener)}
- *
- *
- *
- * @param function
- * a remote function to call
- *
- * @see #call(String)
- * @see #isRunning()
- * @see #setOnCallFinishListener(OnCallFinishListener)
- */
- public void callAsync(String function) {
- mAsyncRunning = true;
- new CallAsync().execute(function);
- }
-
- private boolean call(String function, Bundle pArgs, Bundle pReturn) {
-
- if (!initialize()) {
- mErrorList.add("(LOCAL) Cannot bind to ApgService");
- mResult.putInt(ret.ERROR.name(), error.CANNOT_BIND_TO_APG.ordinal());
- return false;
- }
-
- if (function == null || function.length() == 0) {
- mErrorList.add("(LOCAL) Function to call missing");
- mResult.putInt(ret.ERROR.name(), error.CALL_MISSING.ordinal());
- return false;
- }
-
- try {
- Boolean success = (Boolean) IApgService2.class.getMethod(function, Bundle.class, Bundle.class).invoke(mApgService, pArgs, pReturn);
- mErrorList.addAll(pReturn.getStringArrayList(ret.ERRORS.name()));
- mWarningList.addAll(pReturn.getStringArrayList(ret.WARNINGS.name()));
- return success;
- } catch (NoSuchMethodException e) {
- Log.e(TAG, "Remote call not known (" + function + "): " + e.getMessage(), e);
- mErrorList.add("(LOCAL) Remote call not known (" + function + "): " + e.getMessage());
- mResult.putInt(ret.ERROR.name(), error.CALL_NOT_KNOWN.ordinal());
- return false;
- } catch (InvocationTargetException e) {
- Throwable orig = e.getTargetException();
- Log.w(TAG, "Exception of type '" + orig.getClass() + "' on AIDL call '" + function + "': " + orig.getMessage(), orig);
- mErrorList.add("(LOCAL) Exception of type '" + orig.getClass() + "' on AIDL call '" + function + "': " + orig.getMessage());
- return false;
- } catch (Exception e) {
- Log.e(TAG, "Generic error (" + e.getClass() + "): " + e.getMessage(), e);
- mErrorList.add("(LOCAL) Generic error (" + e.getClass() + "): " + e.getMessage());
- mResult.putInt(ret.ERROR.name(), error.GENERIC.ordinal());
- return false;
- }
-
- }
-
- /**
- * Set a string argument for APG
- *
- *
- * This defines a string argument for APG's AIDL-interface.
- *
- *
- *
- * To know what key-value-pairs are possible (or required), take a look into
- * the IApgService.aidl
- *
- *
- *
- * Note that parameters are not reseted after a call, so you have to
- * reset ({@link #clearArgs()}) them manually if you want to.
- *
- *
- *
- * @param key
- * the key
- * @param val
- * the value
- *
- * @see #clearArgs()
- */
- public void setArg(String key, String val) {
- mArgs.putString(key, val);
- }
-
- /**
- * Set a string-array argument for APG
- *
- *
- * If the AIDL-parameter is an {@literal ArrayList}, you have to use
- * this function.
- *
- *
- *
- * @param key
- * the key
- * @param vals
- * the value
- *
- * @see #setArg(String, String)
- */
- public void setArg(String key, String vals[]) {
- ArrayList list = new ArrayList();
- for (String val : vals) {
- list.add(val);
- }
- mArgs.putStringArrayList(key, list);
- }
-
- /**
- * Set up a boolean argument for APG
- *
- * @param key
- * the key
- * @param vals
- * the value
- *
- * @see #setArg(String, String)
- */
- public void setArg(String key, boolean val) {
- mArgs.putBoolean(key, val);
- }
-
- /**
- * Set up a int argument for APG
- *
- * @param key
- * the key
- * @param vals
- * the value
- *
- * @see #setArg(String, String)
- */
- public void setArg(String key, int val) {
- mArgs.putInt(key, val);
- }
-
- /**
- * Set up a int-array argument for APG
- *
- * If the AIDL-parameter is an {@literal ArrayList}, you have to
- * use this function.
- *
- *
- * @param key
- * the key
- * @param vals
- * the value
- *
- * @see #setArg(String, String)
- */
- public void setArg(String key, int vals[]) {
- ArrayList list = new ArrayList();
- for (int val : vals) {
- list.add(val);
- }
- mArgs.putIntegerArrayList(key, list);
- }
-
- /**
- * Set up binary data to en/decrypt
- *
- * @param is
- * InputStream to get the data from
- */
- public void setBlob(InputStream is) {
- if( LOCAL_LOGD ) Log.d(TAG, "setBlob() called");
- // 1. get the new contentUri
- ContentResolver cr = mContext.getContentResolver();
- Uri contentUri = cr.insert(Uri.parse(BLOB_URI), new ContentValues());
-
- // 2. insert binary data
- OutputStream os = null;
- try {
- os = cr.openOutputStream(contentUri, "w");
- } catch( Exception e ) {
- Log.e(TAG, "... exception on setBlob", e);
- }
-
- byte[] buffer = new byte[8];
- int len = 0;
- try {
- while( (len = is.read(buffer)) != -1) {
- os.write(buffer, 0, len);
- }
- if(LOCAL_LOGD) Log.d(TAG, "... write finished, now closing");
- os.close();
- } catch (Exception e) {
- Log.e(TAG, "... error on writing buffer", e);
- }
-
- mArgs.putString("BLOB", contentUri.toString() );
- }
-
- /**
- * Clears all arguments
- *
- *
- * Anything the has been set up with the various
- * {@link #setArg(String, String)} functions is cleared.
- *
- *
- *
- * Note that any warning, error, callback, result, etc. is NOT cleared with
- * this.
- *
- *
- * @see #reset()
- */
- public void clearArgs() {
- mArgs.clear();
- }
-
- /**
- * Return the object associated with the key
- *
- * @param key
- * the object's key you want to return
- * @return an object at position key, or null if not set
- */
- public Object getArg(String key) {
- return mArgs.get(key);
- }
-
- /**
- * Iterates through the errors
- *
- *
- * With this method you can iterate through all errors. The errors are only
- * returned once and deleted immediately afterwards, so you can only return
- * each error once.
- *
- *
- * @return a human readable description of a error that happened, or null if
- * no more errors
- *
- * @see #hasNextError()
- * @see #clearErrors()
- */
- public String getNextError() {
- if (mErrorList.size() != 0)
- return mErrorList.remove(0);
- else
- return null;
- }
-
- /**
- * Check if there are any new errors
- *
- * @return true, if there are unreturned errors, false otherwise
- *
- * @see #getNextError()
- */
- public boolean hasNextError() {
- return mErrorList.size() != 0;
- }
-
- /**
- * Get the numeric representation of the last error
- *
- *
- * Values <100 mean the error happened locally, values >=100 mean the error
- * happened at the remote side (APG). See the IApgService.aidl (or get the
- * human readable description with {@link #getNextError()}) for what
- * errors >=100 mean.
- *
- *
- * @return the id of the error that happened
- */
- public int getError() {
- if (mResult.containsKey(ret.ERROR.name()))
- return mResult.getInt(ret.ERROR.name());
- else
- return -1;
- }
-
- /**
- * Iterates through the warnings
- *
- *
- * With this method you can iterate through all warnings. Warnings are
- * only returned once and deleted immediately afterwards, so you can only
- * return each warning once.
- *
- *
- * @return a human readable description of a warning that happened, or null
- * if no more warnings
- *
- * @see #hasNextWarning()
- * @see #clearWarnings()
- */
- public String getNextWarning() {
- if (mWarningList.size() != 0)
- return mWarningList.remove(0);
- else
- return null;
- }
-
- /**
- * Check if there are any new warnings
- *
- * @return true, if there are unreturned warnings, false otherwise
- *
- * @see #getNextWarning()
- */
- public boolean hasNextWarning() {
- return mWarningList.size() != 0;
- }
-
- /**
- * Get the result
- *
- *
- * This gets your result. After doing an encryption or decryption with APG,
- * you get the output with this function.
- *
- *
- *
- * Note when your last remote call is unsuccessful, the result will
- * still have the same value like the last successful call (or null, if no
- * call was successful). To ensure you do not work with old call's results,
- * either be sure to {@link #reset()} (or at least {@link #clearResult()})
- * your instance before each new call or always check that
- * {@link #hasNextError()} is false.
- *
- *
- *
- * Note: When handling binary data with {@link #setBlob(InputStream)}, you
- * get your result with {@link #getBlobResult()}.
- *
- *
- * @return the mResult of the last {@link #call(String)} or
- * {@link #callAsync(String)}.
- *
- * @see #reset()
- * @see #clearResult()
- * @see #getResultBundle()
- * @see #getBlobResult()
- */
- public String getResult() {
- return mResult.getString(ret.RESULT.name());
- }
-
- /**
- * Get the binary result
- *
- *
- * This gets your binary result. It only works if you called {@link #setBlob(InputStream)} before.
- *
- * If you did not call encrypt nor decrypt, this will be the same data as you inputed.
- *
- *
- * @return InputStream of the binary data which was en/decrypted
- *
- * @see #setBlob(InputStream)
- * @see #getResult()
- */
- public InputStream getBlobResult() {
- if(mArgs.containsKey("BLOB")) {
- ContentResolver cr = mContext.getContentResolver();
- InputStream in = null;
- try {
- in = cr.openInputStream(Uri.parse(mArgs.getString("BLOB")));
- } catch( Exception e ) {
- Log.e(TAG, "Could not return blob in result", e);
- }
- return in;
- } else {
- return null;
- }
- }
-
- /**
- * Get the result bundle
- *
- *
- * Unlike {@link #getResult()}, which only returns any en-/decrypted
- * message, this function returns the complete information that was returned
- * by Apg. This also includes the "RESULT", but additionally the warnings,
- * errors and any other information.
- *
- *
- * For warnings and errors it is suggested to use the functions that are
- * provided here, namely {@link #getError()}, {@link #getNextError()},
- * {@link #get_next_Warning()} etc.), but if any call returns something non
- * standard, you have access to the complete result bundle to extract the
- * information.
- *
- *
- * @return the complete result bundle of the last call to apg
- */
- public Bundle getResultBundle() {
- return mResult;
- }
-
- public error getConnectionStatus() {
- return mConnectionStatus;
- }
-
- /**
- * Clears all unfetched errors
- *
- * @see #getNextError()
- * @see #hasNextError()
- */
- public void clearErrors() {
- mErrorList.clear();
- mResult.remove(ret.ERROR.name());
- }
-
- /**
- * Clears all unfetched warnings
- *
- * @see #getNextWarning()
- * @see #hasNextWarning()
- */
- public void clearWarnings() {
- mWarningList.clear();
- }
-
- /**
- * Clears the last mResult
- *
- * @see #getResult()
- */
- public void clearResult() {
- mResult.remove(ret.RESULT.name());
- }
-
- /**
- * Set a callback listener when call to AIDL finishes
- *
- * @param obj
- * a object to call back after async execution
- * @see ApgConInterface
- */
- public void setOnCallFinishListener(OnCallFinishListener lis) {
- mOnCallFinishListener = lis;
- }
-
- /**
- * Clears any callback object
- *
- * @see #setOnCallFinishListener(OnCallFinishListener)
- */
- public void clearOnCallFinishListener() {
- mOnCallFinishListener = null;
- }
-
- /**
- * Checks if an async execution is running
- *
- *
- * If you started something with {@link #callAsync(String)}, this will
- * return true if the task is still running
- *
- *
- * @return true, if an async task is still running, false otherwise
- *
- * @see #callAsync(String)
- *
- */
- public boolean isRunning() {
- return mAsyncRunning;
- }
-
- /**
- * Completely resets your instance
- *
- *
- * This currently resets everything in this instance. Errors, warnings,
- * results, callbacks, ... are removed. Any connection to the remote
- * interface is upheld, though.
- *
- *
- *
- * Note when an async execution ({@link #callAsync(String)}) is
- * running, it's result, warnings etc. will still be evaluated (which might
- * be not what you want). Also mind that any callback you set is also
- * reseted, so when finishing the execution any before defined callback will
- * NOT BE TRIGGERED.
- *
- */
- public void reset() {
- clearErrors();
- clearWarnings();
- clearArgs();
- clearOnCallFinishListener();
- mResult.clear();
- }
-
-}
diff --git a/org_apg/src/org/thialfihar/android/apg/util/ApgConInterface.java b/org_apg/src/org/thialfihar/android/apg/util/ApgConInterface.java
deleted file mode 100644
index 406427231..000000000
--- a/org_apg/src/org/thialfihar/android/apg/util/ApgConInterface.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * 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.thialfihar.android.apg.util;
-
-public interface ApgConInterface {
- public static interface OnCallFinishListener {
- public abstract void onCallFinish(android.os.Bundle result);
- }
-}
diff --git a/org_apg/src/org/thialfihar/android/apg/util/Constants.java b/org_apg/src/org/thialfihar/android/apg/util/Constants.java
deleted file mode 100644
index fac9be649..000000000
--- a/org_apg/src/org/thialfihar/android/apg/util/Constants.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package org.thialfihar.android.apg.util;
-
-public class Constants {
- public static final String TAG = "APG";
-
-}
diff --git a/org_apg/src/org/thialfihar/android/apg/util/InputData.java b/org_apg/src/org/thialfihar/android/apg/util/InputData.java
new file mode 100644
index 000000000..6b357e6de
--- /dev/null
+++ b/org_apg/src/org/thialfihar/android/apg/util/InputData.java
@@ -0,0 +1,40 @@
+/*
+ * 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.thialfihar.android.apg.util;
+
+import java.io.InputStream;
+
+
+public class InputData {
+ private PositionAwareInputStream mInputStream;
+ private long mSize;
+
+ public InputData(InputStream inputStream, long size) {
+ mInputStream = new PositionAwareInputStream(inputStream);
+ mSize = size;
+ }
+
+ public InputStream getInputStream() {
+ return mInputStream;
+ }
+
+ public long getSize() {
+ return mSize;
+ }
+
+ public long getStreamPosition() {
+ return mInputStream.position();
+ }
+}
diff --git a/org_apg/src/org/thialfihar/android/apg/util/PositionAwareInputStream.java b/org_apg/src/org/thialfihar/android/apg/util/PositionAwareInputStream.java
new file mode 100644
index 000000000..7850e2513
--- /dev/null
+++ b/org_apg/src/org/thialfihar/android/apg/util/PositionAwareInputStream.java
@@ -0,0 +1,81 @@
+/*
+ * 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.thialfihar.android.apg.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class PositionAwareInputStream extends InputStream {
+ private InputStream mStream;
+ private long mPosition;
+
+ public PositionAwareInputStream(InputStream in) {
+ mStream = in;
+ mPosition = 0;
+ }
+
+ @Override
+ public int read() throws IOException {
+ int ch = mStream.read();
+ ++mPosition;
+ return ch;
+ }
+
+ @Override
+ public int available() throws IOException {
+ return mStream.available();
+ }
+
+ @Override
+ public void close() throws IOException {
+ mStream.close();
+ }
+
+ @Override
+ public boolean markSupported() {
+ return false;
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ int result = mStream.read(b);
+ mPosition += result;
+ return result;
+ }
+
+ @Override
+ public int read(byte[] b, int offset, int length) throws IOException {
+ int result = mStream.read(b, offset, length);
+ mPosition += result;
+ return result;
+ }
+
+ @Override
+ public synchronized void reset() throws IOException {
+ mStream.reset();
+ mPosition = 0;
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+ long result = mStream.skip(n);
+ mPosition += result;
+ return result;
+ }
+
+ public long position() {
+ return mPosition;
+ }
+}
diff --git a/org_apg/src/org/thialfihar/android/apg/util/Primes.java b/org_apg/src/org/thialfihar/android/apg/util/Primes.java
new file mode 100644
index 000000000..071673c13
--- /dev/null
+++ b/org_apg/src/org/thialfihar/android/apg/util/Primes.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2010 Thialfihar
+ *
+ * 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.thialfihar.android.apg.util;
+
+import java.math.BigInteger;
+
+public final class Primes {
+ // taken from http://www.ietf.org/rfc/rfc3526.txt
+ public static final String P1536 =
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
+ "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
+ "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
+ "670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF";
+
+ public static final String P2048 =
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
+ "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
+ "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
+ "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
+ "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
+ "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
+ "15728E5A 8AACAA68 FFFFFFFF FFFFFFFF";
+
+ public static final String P3072 =
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
+ "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
+ "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
+ "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
+ "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
+ "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
+ "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
+ "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
+ "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
+ "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
+ "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
+ "43DB5BFC E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF";
+
+ public static final String P4096 =
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
+ "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
+ "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
+ "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
+ "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
+ "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
+ "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
+ "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
+ "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
+ "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
+ "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
+ "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
+ "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
+ "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
+ "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
+ "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
+ "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199" +
+ "FFFFFFFF FFFFFFFF";
+
+ public static final String P6144 =
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
+ "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
+ "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
+ "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
+ "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
+ "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
+ "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
+ "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
+ "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
+ "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
+ "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
+ "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
+ "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
+ "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
+ "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
+ "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
+ "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" +
+ "36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" +
+ "F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" +
+ "179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" +
+ "DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" +
+ "5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" +
+ "D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" +
+ "23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" +
+ "CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" +
+ "06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" +
+ "DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" +
+ "12BF2D5B 0B7474D6 E694F91E 6DCC4024 FFFFFFFF FFFFFFFF";
+
+ public static final String P8192 =
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
+ "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
+ "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
+ "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
+ "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
+ "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
+ "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
+ "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
+ "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
+ "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
+ "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
+ "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
+ "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
+ "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
+ "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
+ "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
+ "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" +
+ "36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" +
+ "F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" +
+ "179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" +
+ "DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" +
+ "5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" +
+ "D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" +
+ "23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" +
+ "CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" +
+ "06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" +
+ "DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" +
+ "12BF2D5B 0B7474D6 E694F91E 6DBE1159 74A3926F 12FEE5E4" +
+ "38777CB6 A932DF8C D8BEC4D0 73B931BA 3BC832B6 8D9DD300" +
+ "741FA7BF 8AFC47ED 2576F693 6BA42466 3AAB639C 5AE4F568" +
+ "3423B474 2BF1C978 238F16CB E39D652D E3FDB8BE FC848AD9" +
+ "22222E04 A4037C07 13EB57A8 1A23F0C7 3473FC64 6CEA306B" +
+ "4BCBC886 2F8385DD FA9D4B7F A2C087E8 79683303 ED5BDD3A" +
+ "062B3CF5 B3A278A6 6D2A13F8 3F44F82D DF310EE0 74AB6A36" +
+ "4597E899 A0255DC1 64F31CC5 0846851D F9AB4819 5DED7EA1" +
+ "B1D510BD 7EE74D73 FAF36BC3 1ECFA268 359046F4 EB879F92" +
+ "4009438B 481C6CD7 889A002E D5EE382B C9190DA6 FC026E47" +
+ "9558E447 5677E9AA 9E3050E2 765694DF C81F56E8 80B96E71" +
+ "60C980DD 98EDD3DF FFFFFFFF FFFFFFFF";
+
+ public static BigInteger getBestPrime(int keySize) {
+ String primeString;
+ if (keySize >= (8192 + 6144) / 2) {
+ primeString = P8192;
+ } else if (keySize >= (6144 + 4096) / 2) {
+ primeString = P6144;
+ } else if (keySize >= (4096 + 3072) / 2) {
+ primeString = P4096;
+ } else if (keySize >= (3072 + 2048) / 2) {
+ primeString = P3072;
+ } else if (keySize >= (2048 + 1536) / 2) {
+ primeString = P2048;
+ } else {
+ primeString = P1536;
+ }
+
+ return new BigInteger(primeString.replaceAll(" ", ""), 16);
+ }
+}
diff --git a/org_apg/src/org/thialfihar/android/apg/util/Utils.java b/org_apg/src/org/thialfihar/android/apg/util/Utils.java
deleted file mode 100644
index d8b76ad33..000000000
--- a/org_apg/src/org/thialfihar/android/apg/util/Utils.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2012 Dominik Schürmann
- *
- * 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.thialfihar.android.apg.util;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.GregorianCalendar;
-import java.util.Iterator;
-import java.util.Vector;
-
-import org.spongycastle.openpgp.PGPObjectFactory;
-import org.spongycastle.openpgp.PGPSecretKey;
-import org.spongycastle.openpgp.PGPSecretKeyRing;
-import org.thialfihar.android.apg.Constants;
-import org.thialfihar.android.apg.R;
-
-import android.app.Activity;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.util.Log;
-import android.widget.Toast;
-
-public class Utils {
-
- /**
- * Opens the file manager to select a file to open.
- */
- public static void openFile(Activity activity, String filename, String type, int requestCode) {
- Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
- intent.addCategory(Intent.CATEGORY_OPENABLE);
-
- intent.setData(Uri.parse("file://" + filename));
- intent.setType(type);
-
- try {
- activity.startActivityForResult(intent, requestCode);
- } catch (ActivityNotFoundException e) {
- // No compatible file manager was found.
- Toast.makeText(activity, R.string.noFilemanagerInstalled, Toast.LENGTH_SHORT).show();
- }
- }
-
- /**
- * Reads html files from /res/raw/example.html to output them as string. See
- * http://www.monocube.com/2011/02/08/android-tutorial-html-file-in-webview/
- *
- * @param context
- * current context
- * @param resourceID
- * of html file to read
- * @return content of html file with formatting
- */
- public static String readContentFromResource(Context context, int resourceID) {
- InputStream raw = context.getResources().openRawResource(resourceID);
- ByteArrayOutputStream stream = new ByteArrayOutputStream();
- int i;
- try {
- i = raw.read();
- while (i != -1) {
- stream.write(i);
- i = raw.read();
- }
- raw.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- return stream.toString();
- }
-
- /**
- * Return the number if days between two dates
- *
- * @param first
- * @param second
- * @return number of days
- */
- public static long getNumDaysBetween(GregorianCalendar first, GregorianCalendar second) {
- GregorianCalendar tmp = new GregorianCalendar();
- tmp.setTime(first.getTime());
- long numDays = (second.getTimeInMillis() - first.getTimeInMillis()) / 1000 / 86400;
- tmp.add(Calendar.DAY_OF_MONTH, (int) numDays);
- while (tmp.before(second)) {
- tmp.add(Calendar.DAY_OF_MONTH, 1);
- ++numDays;
- }
- return numDays;
- }
-
- /**
- * Converts Vector to a byte[] array to send it by intent to service
- *
- * @param keys
- * @return
- */
- public static byte[] PGPSecretKeyListToBytes(Vector keys) {
- ByteArrayOutputStream os = new ByteArrayOutputStream();
- for (PGPSecretKey key : keys) {
- try {
- key.encode(os);
- } catch (IOException e) {
- Log.e(Constants.TAG,
- "Error while converting PGPSecretKey to byte[]: " + e.getMessage());
- e.printStackTrace();
- }
- }
-
- byte[] keysBytes = os.toByteArray();
-
- return keysBytes;
- }
-
- /**
- * Convert from byte[] to ArrayList
- *
- * @param keysBytes
- * @return
- */
- public static PGPSecretKeyRing BytesToPGPSecretKeyRing(byte[] keysBytes) {
- PGPObjectFactory factory = new PGPObjectFactory(keysBytes);
- PGPSecretKeyRing keyRing = null;
- try {
- if ((keyRing = (PGPSecretKeyRing) factory.nextObject()) == null) {
- Log.e(Constants.TAG, "No keys given!");
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- return keyRing;
- }
-
- public static ArrayList BytesToPGPSecretKeyList(byte[] keysBytes) {
- PGPSecretKeyRing keyRing = BytesToPGPSecretKeyRing(keysBytes);
- ArrayList keys = new ArrayList();
-
- Iterator itr = keyRing.getSecretKeys();
- while (itr.hasNext()) {
- keys.add(itr.next());
- }
-
- return keys;
- }
-
- public static PGPSecretKey BytesToPGPSecretKey(byte[] keyBytes) {
- PGPSecretKey key = BytesToPGPSecretKeyList(keyBytes).get(0);
-
- return key;
- }
-
- public static byte[] PGPSecretKeyToBytes(PGPSecretKey key) {
- try {
- return key.getEncoded();
- } catch (IOException e) {
- Log.e(Constants.TAG, "Encoding failed: ", e);
-
- return null;
- }
- }
-
- public static byte[] PGPSecretKeyRingToBytes(PGPSecretKeyRing keyRing) {
- try {
- return keyRing.getEncoded();
- } catch (IOException e) {
- Log.e(Constants.TAG, "Encoding failed: ", e);
-
- return null;
- }
- }
-
-}
--
cgit v1.2.3