|
5 | 5 | import android.content.Context; |
6 | 6 | import android.database.Cursor; |
7 | 7 | import android.database.sqlite.SQLiteDatabase; |
| 8 | +import android.graphics.Bitmap; |
| 9 | +import android.graphics.BitmapFactory; |
8 | 10 |
|
| 11 | +import androidx.security.crypto.EncryptedFile; |
| 12 | +import androidx.security.crypto.MasterKey; |
| 13 | + |
| 14 | +import java.io.ByteArrayOutputStream; |
9 | 15 | import java.io.File; |
10 | 16 | import java.io.FileInputStream; |
11 | 17 | import java.io.FileOutputStream; |
12 | 18 | import java.io.IOException; |
| 19 | +import java.io.InputStream; |
| 20 | +import java.io.OutputStream; |
13 | 21 | import java.nio.channels.FileChannel; |
| 22 | +import java.security.GeneralSecurityException; |
14 | 23 | import java.util.ArrayList; |
15 | 24 | import java.util.List; |
16 | 25 | import java.util.UUID; |
@@ -65,6 +74,70 @@ public void moveFile(File src, File dst) throws IOException { |
65 | 74 | src.delete(); |
66 | 75 | } |
67 | 76 |
|
| 77 | + private void encrypt(File src, File dst) throws GeneralSecurityException, IOException { |
| 78 | + if (!dst.getParentFile().exists()) { |
| 79 | + dst.getParentFile().mkdirs(); |
| 80 | + } |
| 81 | + |
| 82 | + if (dst.exists()) { |
| 83 | + // If the destination file already exists, rename it with a postfix |
| 84 | + dst = getUniqueDestination(dst); |
| 85 | + } |
| 86 | + |
| 87 | + MasterKey mainKey = new MasterKey.Builder(context) |
| 88 | + .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) |
| 89 | + .build(); |
| 90 | + |
| 91 | + EncryptedFile encryptedFile = new EncryptedFile.Builder(context, |
| 92 | + dst, |
| 93 | + mainKey, |
| 94 | + EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB |
| 95 | + ).build(); |
| 96 | + |
| 97 | + InputStream inputStream = new FileInputStream(src); |
| 98 | + OutputStream outputStream = encryptedFile.openFileOutput(); |
| 99 | + // Write data from source file to encrypted output stream |
| 100 | + byte[] buffer = new byte[4096]; |
| 101 | + int bytesRead; |
| 102 | + while ((bytesRead = inputStream.read(buffer)) != -1) { |
| 103 | + outputStream.write(buffer, 0, bytesRead); |
| 104 | + } |
| 105 | + |
| 106 | + inputStream.close(); |
| 107 | + outputStream.flush(); |
| 108 | + outputStream.close(); |
| 109 | + |
| 110 | + } |
| 111 | + |
| 112 | + private void decrypt(final File src, File dst) throws GeneralSecurityException, IOException { |
| 113 | + dst = getUniqueDestination(dst); |
| 114 | + |
| 115 | + MasterKey mainKey = new MasterKey.Builder(context) |
| 116 | + .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) |
| 117 | + .build(); |
| 118 | + |
| 119 | + EncryptedFile encryptedFile = new EncryptedFile.Builder(context, |
| 120 | + src, |
| 121 | + mainKey, |
| 122 | + EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB |
| 123 | + ).build(); |
| 124 | + |
| 125 | + InputStream inputStream = encryptedFile.openFileInput(); |
| 126 | + OutputStream outputStream = new FileOutputStream(dst); |
| 127 | + |
| 128 | + // Write data from encrypted source file to output stream |
| 129 | + byte[] buffer = new byte[4096]; |
| 130 | + int bytesRead; |
| 131 | + while ((bytesRead = inputStream.read(buffer)) != -1) { |
| 132 | + outputStream.write(buffer, 0, bytesRead); |
| 133 | + } |
| 134 | + |
| 135 | + inputStream.close(); |
| 136 | + outputStream.flush(); |
| 137 | + outputStream.close(); |
| 138 | + |
| 139 | + } |
| 140 | + |
68 | 141 | public void copyFile(File src, File dst) throws IOException { |
69 | 142 | if (!dst.getParentFile().exists()) { |
70 | 143 | dst.getParentFile().mkdirs(); |
@@ -146,7 +219,14 @@ public void moveToTrash(File photo) throws IOException { |
146 | 219 | values.put("DELETE_DATE", System.currentTimeMillis()); |
147 | 220 | db.insert(TRASH_BIN_TABLE_NAME, null, values); |
148 | 221 |
|
149 | | - moveFile(photo, trash); |
| 222 | + //moveFile(photo, trash); |
| 223 | + try { |
| 224 | + encrypt(photo, trash); |
| 225 | + photo.delete(); |
| 226 | + } catch (GeneralSecurityException e) { |
| 227 | + throw new RuntimeException(e); |
| 228 | + } |
| 229 | + |
150 | 230 | } |
151 | 231 |
|
152 | 232 | public void permanentDelete(File trash) { |
@@ -185,7 +265,12 @@ public String restorePhoto(File trash) throws IOException { |
185 | 265 |
|
186 | 266 | if (originalPath != null) { |
187 | 267 | File original = new File(originalPath); |
188 | | - moveFile(trash, original); |
| 268 | + try { |
| 269 | + decrypt(trash, original); |
| 270 | + trash.delete(); |
| 271 | + } catch (GeneralSecurityException e) { |
| 272 | + throw new RuntimeException(e); |
| 273 | + } |
189 | 274 | } else {} |
190 | 275 |
|
191 | 276 | return originalPath; |
@@ -238,17 +323,52 @@ public int[] getDaysRemain(File[] trashFiles) { |
238 | 323 | } |
239 | 324 |
|
240 | 325 |
|
241 | | - public void checkAndCleanTrashBin() { |
| 326 | + public List<File> checkAndCleanTrashBin() { |
242 | 327 | File[] trashFiles = getTrashFiles(); |
243 | 328 |
|
244 | 329 | int[] daysRemain = getDaysRemain(trashFiles); |
| 330 | + ArrayList returnList = new ArrayList<File>(); |
245 | 331 |
|
246 | 332 | for (int i = 0; i < daysRemain.length; i++) { |
247 | | - if (daysRemain[i] < 0) { |
| 333 | + if (daysRemain[i] < 0 || !trashFiles[i].exists()) { |
248 | 334 | permanentDelete(trashFiles[i]); |
249 | 335 | trashFiles[i] = null; |
| 336 | + } else { |
| 337 | + returnList.add(trashFiles[i]); |
250 | 338 | } |
251 | 339 | } |
| 340 | + return returnList; |
| 341 | + |
| 342 | + } |
| 343 | + |
| 344 | + public Bitmap decryptPhoto(File src) { |
| 345 | + |
| 346 | + Bitmap myBitmap = null; |
| 347 | + MasterKey mainKey = null; |
| 348 | + try { |
| 349 | + mainKey = new MasterKey.Builder(context) |
| 350 | + .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) |
| 351 | + .build(); |
| 352 | + |
| 353 | + EncryptedFile encryptedFile = new EncryptedFile.Builder(context, |
| 354 | + src, |
| 355 | + mainKey, |
| 356 | + EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB |
| 357 | + ).build(); |
| 358 | + |
| 359 | + InputStream inputStream = encryptedFile.openFileInput(); |
| 360 | + // Convert InputStream to Bitmap |
| 361 | + myBitmap = BitmapFactory.decodeStream(inputStream); |
| 362 | + |
| 363 | + } catch (GeneralSecurityException e) { |
| 364 | + throw new RuntimeException(e); |
| 365 | + } catch (IOException e) { |
| 366 | + throw new RuntimeException(e); |
| 367 | + } |
| 368 | + |
252 | 369 |
|
| 370 | + |
| 371 | + return myBitmap; |
253 | 372 | } |
| 373 | + |
254 | 374 | } |
0 commit comments