From c4599798f9807c0cc692e1b08355892136ab317c Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sun, 15 Nov 2015 05:41:14 +0100 Subject: fix delete file securely method and use for delete original file --- .../sufficientlysecure/keychain/pgp/PgpHelper.java | 45 ++--------------- .../keychain/ui/DecryptListFragment.java | 27 +++-------- .../keychain/util/FileHelper.java | 56 ++++++++++++++++++---- 3 files changed, 58 insertions(+), 70 deletions(-) (limited to 'OpenKeychain/src/main') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java index fbda90775..016651c3b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java @@ -18,23 +18,15 @@ package org.sufficientlysecure.keychain.pgp; -import android.content.Context; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager.NameNotFoundException; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import android.support.annotation.NonNull; import android.text.TextUtils; import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.util.Preferences; - -import java.io.File; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.security.SecureRandom; -import java.util.regex.Matcher; -import java.util.regex.Pattern; public class PgpHelper { @@ -50,35 +42,6 @@ public class PgpHelper { ".*?(-----BEGIN PGP PUBLIC KEY BLOCK-----.*?-----END PGP PUBLIC KEY BLOCK-----).*", Pattern.DOTALL); - /** - * Deletes file securely by overwriting it with random data before deleting it. - *

- * TODO: Does this really help on flash storage? - * - * @throws IOException - */ - public static void deleteFileSecurely(Context context, Progressable progressable, File file) - throws 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_deleting_securely, file.getName()); - while (pos < length) { - if (progressable != null) { - progressable.setProgress(msg, (int) (100 * pos / length), 100); - } - random.nextBytes(data); - raf.write(data); - pos += data.length; - } - raf.close(); - file.delete(); - } - /** * Fixing broken PGP MESSAGE Strings coming from GMail/AOSP Mail */ diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java index c45a641e0..000de6e40 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java @@ -800,33 +800,18 @@ public class DecryptListFragment // we can only ever delete a file once, if we got this far either it's gone or it will never work mCanDelete = false; - if ("file".equals(uri.getScheme())) { - File file = new File(uri.getPath()); - if (file.delete()) { + try { + int deleted = FileHelper.deleteFileSecurely(activity, uri); + if (deleted > 0) { Notify.create(activity, R.string.file_delete_ok, Style.OK).show(); } else { Notify.create(activity, R.string.file_delete_none, Style.WARN).show(); } - return; + } catch (Exception e) { + Log.e(Constants.TAG, "exception deleting file", e); + Notify.create(activity, R.string.file_delete_exception, Style.ERROR).show(); } - if ("content".equals(uri.getScheme())) { - try { - int deleted = activity.getContentResolver().delete(uri, null, null); - if (deleted > 0) { - Notify.create(activity, R.string.file_delete_ok, Style.OK).show(); - } else { - Notify.create(activity, R.string.file_delete_none, Style.WARN).show(); - } - } catch (Exception e) { - Log.e(Constants.TAG, "exception deleting file", e); - Notify.create(activity, R.string.file_delete_exception, Style.ERROR).show(); - } - return; - } - - Notify.create(activity, R.string.file_delete_exception, Style.ERROR).show(); - } public class DecryptFilesAdapter extends RecyclerView.Adapter { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileHelper.java index 7345faad9..bae119700 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileHelper.java @@ -25,7 +25,9 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.io.UnsupportedEncodingException; +import java.security.SecureRandom; import java.text.DecimalFormat; import android.annotation.TargetApi; @@ -33,7 +35,6 @@ import android.content.ActivityNotFoundException; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; -import android.content.res.AssetFileDescriptor; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.Point; @@ -41,20 +42,13 @@ import android.net.Uri; import android.os.Build; import android.os.Build.VERSION_CODES; import android.os.Environment; -import android.os.ParcelFileDescriptor; import android.provider.DocumentsContract; import android.provider.OpenableColumns; import android.support.v4.app.Fragment; -import android.system.ErrnoException; -import android.system.Os; -import android.system.StructStat; import android.widget.Toast; -import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import static android.system.OsConstants.S_IROTH; - /** This class offers a number of helper functions for saving documents. * * There are three entry points here: openDocument, saveDocument and @@ -167,6 +161,14 @@ public class FileHelper { } public static long getFileSize(Context context, Uri uri, long def) { + if ("file".equals(uri.getScheme())) { + long size = new File(uri.getPath()).length(); + if (size == 0) { + size = def; + } + return size; + } + long size = def; try { Cursor cursor = context.getContentResolver().query(uri, new String[]{OpenableColumns.SIZE}, null, null, null); @@ -261,6 +263,44 @@ public class FileHelper { } } + /** + * Deletes data at a URI securely by overwriting it with random data + * before deleting it. This method is fail-fast - if we can't securely + * delete the file, we don't delete it at all. + */ + public static int deleteFileSecurely(Context context, Uri uri) + throws IOException { + + ContentResolver resolver = context.getContentResolver(); + long lengthLeft = FileHelper.getFileSize(context, uri); + + if (lengthLeft == -1) { + throw new IOException("Error opening file!"); + } + + SecureRandom random = new SecureRandom(); + byte[] randomData = new byte[1024]; + + OutputStream out = resolver.openOutputStream(uri, "w"); + if (out == null) { + throw new IOException("Error opening file!"); + } + out = new BufferedOutputStream(out); + while (lengthLeft > 0) { + random.nextBytes(randomData); + out.write(randomData, 0, lengthLeft > randomData.length ? randomData.length : (int) lengthLeft); + lengthLeft -= randomData.length; + } + out.close(); + + if ("file".equals(uri.getScheme())) { + return new File(uri.getPath()).delete() ? 1 : 0; + } else { + return resolver.delete(uri, null, null); + } + + } + /** Checks if external storage is mounted if file is located on external storage. */ public static boolean isStorageMounted(String file) { if (file.startsWith(Environment.getExternalStorageDirectory().getAbsolutePath())) { -- cgit v1.2.3