From bb4c255314e0beb1713050cc231f317894997f53 Mon Sep 17 00:00:00 2001 From: Christian Schneppe Date: Mon, 8 Aug 2016 22:04:57 +0200 Subject: reworked backup service * automatically save database encrypted to local storage at 4 am each day * run backup import in new thread --- src/main/java/de/pixart/messenger/Config.java | 6 +- .../pixart/messenger/services/AlarmReceiver.java | 21 +++ .../messenger/services/ExportLogsService.java | 66 +++++--- .../messenger/services/XmppConnectionService.java | 32 ++++ .../de/pixart/messenger/ui/UpdaterActivity.java | 45 +---- .../de/pixart/messenger/ui/WelcomeActivity.java | 184 ++++++++++++++++----- .../pixart/messenger/utils/EncryptDecryptFile.java | 73 ++++++++ 7 files changed, 317 insertions(+), 110 deletions(-) create mode 100644 src/main/java/de/pixart/messenger/services/AlarmReceiver.java create mode 100644 src/main/java/de/pixart/messenger/utils/EncryptDecryptFile.java (limited to 'src/main/java') diff --git a/src/main/java/de/pixart/messenger/Config.java b/src/main/java/de/pixart/messenger/Config.java index 822da1000..262123784 100644 --- a/src/main/java/de/pixart/messenger/Config.java +++ b/src/main/java/de/pixart/messenger/Config.java @@ -42,7 +42,7 @@ public final class Config { public static final String BUG_REPORTS = "bugs@pix-art.de"; - public static String inviteUserURL = "https://jabber.pix-art.de/i/"; + public static final String inviteUserURL = "https://jabber.pix-art.de/i/"; public static final String DOMAIN_LOCK = "pix-art.de"; //only allow account creation for this domain public static final String MAGIC_CREATE_DOMAIN = "pix-art.de"; @@ -92,6 +92,10 @@ public final class Config { public static final int MAX_DISPLAY_MESSAGE_CHARS = 4096; + public static final boolean ExportLogs = true; // automatically export logs + public static final int ExportLogs_Hour = 4; //valid values from 0 to 23 + public static final int ExportLogs_Minute = 0; //valid values from 0 to 59 + public static final boolean DISABLE_PROXY_LOOKUP = false; //useful to debug ibb public static final boolean DISABLE_HTTP_UPLOAD = false; public static final boolean DISABLE_STRING_PREP = false; // setting to true might increase startup performance diff --git a/src/main/java/de/pixart/messenger/services/AlarmReceiver.java b/src/main/java/de/pixart/messenger/services/AlarmReceiver.java new file mode 100644 index 000000000..0fd3ba049 --- /dev/null +++ b/src/main/java/de/pixart/messenger/services/AlarmReceiver.java @@ -0,0 +1,21 @@ +package de.pixart.messenger.services; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +import de.pixart.messenger.Config; + +public class AlarmReceiver extends BroadcastReceiver{ + public static final int SCHEDULE_ALARM_REQUEST_CODE = 523976483; + + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().contains("exportlogs")) { + Log.d(Config.LOGTAG, "Received alarm broadcast to export logs"); + Intent i = new Intent(context, ExportLogsService.class); + context.startService(i); + } + } +} diff --git a/src/main/java/de/pixart/messenger/services/ExportLogsService.java b/src/main/java/de/pixart/messenger/services/ExportLogsService.java index 331321ffe..bc385b1e5 100644 --- a/src/main/java/de/pixart/messenger/services/ExportLogsService.java +++ b/src/main/java/de/pixart/messenger/services/ExportLogsService.java @@ -6,6 +6,7 @@ import android.content.Context; import android.content.Intent; import android.os.IBinder; import android.support.v4.app.NotificationCompat; +import android.util.Log; import java.io.BufferedWriter; import java.io.File; @@ -13,19 +14,23 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; +import javax.crypto.NoSuchPaddingException; + +import de.pixart.messenger.Config; import de.pixart.messenger.R; import de.pixart.messenger.entities.Account; import de.pixart.messenger.entities.Conversation; import de.pixart.messenger.entities.Message; import de.pixart.messenger.persistance.DatabaseBackend; import de.pixart.messenger.persistance.FileBackend; +import de.pixart.messenger.utils.EncryptDecryptFile; import de.pixart.messenger.xmpp.jid.Jid; public class ExportLogsService extends Service { @@ -50,10 +55,12 @@ public class ExportLogsService extends Service { new Thread(new Runnable() { @Override public void run() { - try { - ExportDatabase(); - } catch (IOException e) { - e.printStackTrace(); + if (mAccounts.size() == 1) { + try { + ExportDatabase(); + } catch (IOException e) { + e.printStackTrace(); + } } export(); stopForeground(true); @@ -150,36 +157,47 @@ public class ExportLogsService extends Service { } public void ExportDatabase() throws IOException { - + Account mAccount = mAccounts.get(0); // Get hold of the db: - InputStream myInput = new FileInputStream(this.getDatabasePath(DatabaseBackend.DATABASE_NAME)); - + FileInputStream InputFile = new FileInputStream(this.getDatabasePath(DatabaseBackend.DATABASE_NAME)); // Set the output folder on the SDcard - File directory = new File(FileBackend.getConversationsDirectory() + "/.Database/"); - + File directory = new File(FileBackend.getConversationsDirectory() + "/database/"); // Create the folder if it doesn't exist: if (!directory.exists()) { directory.mkdirs(); } - + //Delete old database export file + File temp_db_file = new File(directory + "/database.bak"); + if (temp_db_file.exists()) { + Log.d(Config.LOGTAG, "Delete temp database backup file from " + temp_db_file.toString()); + temp_db_file.delete(); + } // Set the output file stream up: - OutputStream myOutput = new FileOutputStream(directory.getPath() + "/Database.bak"); + FileOutputStream OutputFile = new FileOutputStream(directory.getPath() + "/database.db.crypt"); - // Transfer bytes from the input file to the output file - byte[] buffer = new byte[1024]; - int length; - while ((length = myInput.read(buffer)) > 0) { - myOutput.write(buffer, 0, length); - } + String EncryptionKey = mAccount.getPassword(); //get account password - // Close and clear the streams - myOutput.flush(); - myOutput.close(); - myInput.close(); + Log.d(Config.LOGTAG,"Password for " + mAccount.getJid().toString() + " is " + EncryptionKey); + // encrypt database from the input file to the output file + try { + EncryptDecryptFile.encrypt(InputFile, OutputFile, EncryptionKey); + } catch (NoSuchAlgorithmException e) { + Log.d(Config.LOGTAG,"Database exporter: encryption failed with " + e); + e.printStackTrace(); + } catch (NoSuchPaddingException e) { + Log.d(Config.LOGTAG,"Database exporter: encryption failed with " + e); + e.printStackTrace(); + } catch (InvalidKeyException e) { + Log.d(Config.LOGTAG,"Database exporter: encryption failed (invalid key) with " + e); + e.printStackTrace(); + } catch (IOException e) { + Log.d(Config.LOGTAG,"Database exporter: encryption failed (IO) with " + e); + e.printStackTrace(); + } } @Override public IBinder onBind(Intent intent) { return null; } -} \ No newline at end of file +} diff --git a/src/main/java/de/pixart/messenger/services/XmppConnectionService.java b/src/main/java/de/pixart/messenger/services/XmppConnectionService.java index 4f12500d9..9209c399c 100644 --- a/src/main/java/de/pixart/messenger/services/XmppConnectionService.java +++ b/src/main/java/de/pixart/messenger/services/XmppConnectionService.java @@ -48,6 +48,7 @@ import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Arrays; +import java.util.Calendar; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -794,6 +795,9 @@ public class XmppConnectionService extends Service { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { scheduleNextIdlePing(); } + + //start export log service every day at given time + ScheduleAutomaticExport(); } @Override @@ -814,6 +818,8 @@ public class XmppConnectionService extends Service { } fileObserver.stopWatching(); super.onDestroy(); + // cancel scheduled exporter + CancelAutomaticExport(); } public void toggleScreenEventReceiver() { @@ -3507,4 +3513,30 @@ public class XmppConnectionService extends Service { return XmppConnectionService.this; } } + + public void ScheduleAutomaticExport() { + //start export log service every day at given time + if (Config.ExportLogs) { + if (Config.ExportLogs_Hour >= 0 && Config.ExportLogs_Hour <= 23 && Config.ExportLogs_Minute >= 0 && Config.ExportLogs_Minute <= 59) { + Log.d(Config.LOGTAG, "Schedule automatic export logs at " + Config.ExportLogs_Hour + ":" + Config.ExportLogs_Minute); + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(System.currentTimeMillis()); + calendar.set(Calendar.HOUR_OF_DAY, Config.ExportLogs_Hour); + calendar.set(Calendar.MINUTE, Config.ExportLogs_Minute); + Intent intent = new Intent(this, AlarmReceiver.class); + intent.setAction("exportlogs"); + final PendingIntent pendingIntent = PendingIntent.getBroadcast(this, AlarmReceiver.SCHEDULE_ALARM_REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT); + ((AlarmManager) getSystemService(ALARM_SERVICE)).setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent); + } + } + } + + public void CancelAutomaticExport() { + if (Config.ExportLogs) { + Log.d(Config.LOGTAG, "Cancel scheduled automatic export"); + Intent intent = new Intent(this, AlarmReceiver.class); + final PendingIntent pendingIntent = PendingIntent.getBroadcast(this, AlarmReceiver.SCHEDULE_ALARM_REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT); + ((AlarmManager) this.getSystemService(ALARM_SERVICE)).cancel(pendingIntent); + } + } } diff --git a/src/main/java/de/pixart/messenger/ui/UpdaterActivity.java b/src/main/java/de/pixart/messenger/ui/UpdaterActivity.java index 0a35288d7..fcd4275a4 100644 --- a/src/main/java/de/pixart/messenger/ui/UpdaterActivity.java +++ b/src/main/java/de/pixart/messenger/ui/UpdaterActivity.java @@ -26,15 +26,10 @@ import org.json.JSONException; import org.json.JSONObject; import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import de.pixart.messenger.Config; import de.pixart.messenger.R; -import de.pixart.messenger.persistance.DatabaseBackend; +import de.pixart.messenger.services.ExportLogsService; import de.pixart.messenger.services.UpdaterWebService; public class UpdaterActivity extends Activity { @@ -62,7 +57,6 @@ public class UpdaterActivity extends Activity { installIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true); installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(installIntent); - UpdaterActivity.this.finish(); } } @@ -99,36 +93,6 @@ public class UpdaterActivity extends Activity { } } - private void ExportDatabase() throws IOException { - - // Get hold of the db: - InputStream myInput = new FileInputStream(this.getDatabasePath(DatabaseBackend.DATABASE_NAME)); - - // Set the output folder on the SDcard - File directory = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pix-Art Messenger/.Database/"); - - // Create the folder if it doesn't exist: - if (!directory.exists()) { - directory.mkdirs(); - } - - // Set the output file stream up: - OutputStream myOutput = new FileOutputStream(directory.getPath() + "/Database.bak"); - - // Transfer bytes from the input file to the output file - byte[] buffer = new byte[1024]; - int length; - while ((length = myInput.read(buffer)) > 0) { - myOutput.write(buffer, 0, length); - } - - // Close and clear the streams - myOutput.flush(); - myOutput.close(); - myInput.close(); - } - - @Override public void onDestroy() { //unregister your receivers @@ -230,11 +194,8 @@ public class UpdaterActivity extends Activity { if (success) { if (isStoragePermissionGranted()) { //start backing up database - try { - ExportDatabase(); - } catch (IOException e) { - e.printStackTrace(); - } + final Intent startIntent = new Intent(getBaseContext(), ExportLogsService.class); + getBaseContext().startService(startIntent); } //Overall information about the contents of a package //This corresponds to all of the information collected from AndroidManifest.xml. diff --git a/src/main/java/de/pixart/messenger/ui/WelcomeActivity.java b/src/main/java/de/pixart/messenger/ui/WelcomeActivity.java index c92bb8cd4..b97dcbcfd 100644 --- a/src/main/java/de/pixart/messenger/ui/WelcomeActivity.java +++ b/src/main/java/de/pixart/messenger/ui/WelcomeActivity.java @@ -3,6 +3,7 @@ package de.pixart.messenger.ui; import android.Manifest; import android.app.Activity; import android.app.AlertDialog; +import android.app.ProgressDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.ApplicationInfo; @@ -12,29 +13,33 @@ import android.database.sqlite.SQLiteException; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.os.Environment; import android.util.Log; +import android.view.LayoutInflater; import android.view.View; import android.widget.Button; +import android.widget.EditText; import android.widget.TextView; +import android.widget.Toast; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; import java.util.List; +import javax.crypto.NoSuchPaddingException; + import de.pixart.messenger.Config; import de.pixart.messenger.R; import de.pixart.messenger.persistance.DatabaseBackend; +import de.pixart.messenger.persistance.FileBackend; +import de.pixart.messenger.utils.EncryptDecryptFile; public class WelcomeActivity extends Activity { private static final int REQUEST_READ_EXTERNAL_STORAGE = 0XD737; - boolean dbExist = false; - boolean backup_existing = false; @Override protected void onCreate(final Bundle savedInstanceState) { @@ -43,18 +48,14 @@ public class WelcomeActivity extends Activity { //check if there is a backed up database -- if (hasStoragePermission(REQUEST_READ_EXTERNAL_STORAGE)) { - dbExist = checkDatabase(); - } - - if (dbExist) { - backup_existing = true; + BackupAvailable(); } final Button ImportDatabase = (Button) findViewById(R.id.import_database); final TextView ImportText = (TextView) findViewById(R.id.import_text); - if (backup_existing) { + if (BackupAvailable()) { ImportDatabase.setVisibility(View.VISIBLE); ImportText.setVisibility(View.VISIBLE); } @@ -62,11 +63,7 @@ public class WelcomeActivity extends Activity { ImportDatabase.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - try { - ImportDatabase(); - } catch (IOException e) { - e.printStackTrace(); - } + enterPasswordDialog(); } }); @@ -89,16 +86,109 @@ public class WelcomeActivity extends Activity { } - private boolean checkDatabase() { + public void enterPasswordDialog() { + LayoutInflater li = LayoutInflater.from(WelcomeActivity.this); + View promptsView = li.inflate(R.layout.password, null); + final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(WelcomeActivity.this); + alertDialogBuilder.setView(promptsView); + final EditText userInput = (EditText) promptsView + .findViewById(R.id.password); + alertDialogBuilder.setTitle(R.string.enter_password); + alertDialogBuilder.setMessage(R.string.enter_account_password); + alertDialogBuilder + .setCancelable(false) + .setPositiveButton(R.string.ok, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog,int id) { + final String password = userInput.getText().toString(); + final ProgressDialog pd = ProgressDialog.show(WelcomeActivity.this, getString(R.string.please_wait), getString(R.string.databaseimport_started), true); + if (!password.isEmpty()) { + new Thread(new Runnable() { + @Override + public void run() { + try { + checkDatabase(password); + } catch (IOException e) { + e.printStackTrace(); + } + pd.dismiss(); + } + }).start(); + } else { + AlertDialog.Builder builder = new AlertDialog.Builder(WelcomeActivity.this); + builder.setTitle(R.string.error); + builder.setMessage(R.string.password_should_not_be_empty); + builder.setNegativeButton(R.string.cancel, null); + builder.setPositiveButton(R.string.try_again, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + enterPasswordDialog(); + } + }); + builder.create().show(); + } + } + }) + .setNegativeButton(R.string.cancel, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog,int id) { + Toast.makeText(WelcomeActivity.this, R.string.import_canceled, Toast.LENGTH_LONG).show(); + dialog.dismiss(); + } + } + ); + // create alert dialog + AlertDialog alertDialog = alertDialogBuilder.create(); + + // show it + alertDialog.show(); + } + + private boolean BackupAvailable() { + // Set the folder on the SDcard + File filePath = new File(FileBackend.getConversationsDirectory() + "/database/database.db.crypt"); + Log.d(Config.LOGTAG,"DB Path: " + filePath.toString()); + if(filePath.exists()) { + Log.d(Config.LOGTAG,"DB Path existing"); + return true; + } else { + Log.d(Config.LOGTAG,"DB Path not existing"); + return false; + } + } + + private void checkDatabase(String DecryptionKey) throws IOException { + // Set the folder on the SDcard + File directory = new File(FileBackend.getConversationsDirectory() + "/database/"); + // Set the input file stream up: + FileInputStream InputFile = new FileInputStream(directory.getPath() + "/database.db.crypt"); + // Temp output for DB checks + File TempFile = new File(directory.getPath() + "/database.bak"); + FileOutputStream OutputTemp = new FileOutputStream(TempFile); + + try { + Log.d(Config.LOGTAG,"Try decryption to temp with password: " + DecryptionKey); + EncryptDecryptFile.decrypt(InputFile, OutputTemp, DecryptionKey); + } catch (NoSuchAlgorithmException e) { + Log.d(Config.LOGTAG,"Database importer: decryption failed with " + e); + e.printStackTrace(); + } catch (NoSuchPaddingException e) { + Log.d(Config.LOGTAG,"Database importer: decryption failed with " + e); + e.printStackTrace(); + } catch (InvalidKeyException e) { + Log.d(Config.LOGTAG,"Database importer: decryption failed (invalid key) with " + e); + e.printStackTrace(); + } catch (IOException e) { + Log.d(Config.LOGTAG,"Database importer: decryption failed (IO) with " + e); + e.printStackTrace(); + } SQLiteDatabase checkDB = null; - String DB_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pix-Art Messenger/.Database/"; - String DB_NAME = "Database.bak"; int DB_Version = DatabaseBackend.DATABASE_VERSION; int Backup_DB_Version = 0; try { - String dbPath = DB_PATH + DB_NAME; + String dbPath = TempFile.toString(); checkDB = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READONLY); Backup_DB_Version = checkDB.getVersion(); Log.d(Config.LOGTAG, "Backup found: " + checkDB + " Version: " + checkDB.getVersion()); @@ -111,36 +201,45 @@ public class WelcomeActivity extends Activity { if (checkDB != null) { checkDB.close(); } - if (checkDB != null && Backup_DB_Version <= DB_Version) { - return true; + Log.d(Config.LOGTAG, "checkDB = " + checkDB.toString() + ", Backup DB = " + Backup_DB_Version + ", DB = " + DB_Version); + if (checkDB != null && Backup_DB_Version != 0 && Backup_DB_Version <= DB_Version) { + Log.d(Config.LOGTAG,"Try decryption with password: " + DecryptionKey); + if (TempFile.exists()) { + Log.d(Config.LOGTAG, "Delete temp file from " + TempFile.toString()); + TempFile.delete(); + } + ImportDatabase(DecryptionKey); + } else if (checkDB != null && Backup_DB_Version == 0) { + Toast.makeText(WelcomeActivity.this, R.string.Password_wrong, Toast.LENGTH_LONG).show(); + enterPasswordDialog(); } else { - return false; + Toast.makeText(WelcomeActivity.this, R.string.Import_failed, Toast.LENGTH_LONG).show(); } } - private void ImportDatabase() throws IOException { - + private void ImportDatabase(final String DecryptionKey) throws IOException { // Set location for the db: - OutputStream myOutput = new FileOutputStream(this.getDatabasePath(DatabaseBackend.DATABASE_NAME)); - + final FileOutputStream OutputFile = new FileOutputStream(this.getDatabasePath(DatabaseBackend.DATABASE_NAME)); // Set the folder on the SDcard - File directory = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pix-Art Messenger/.Database/"); - + File directory = new File(FileBackend.getConversationsDirectory() + "/database/"); // Set the input file stream up: - InputStream myInput = new FileInputStream(directory.getPath() + "/Database.bak"); - - // Transfer bytes from the input file to the output file - byte[] buffer = new byte[1024]; - int length; - while ((length = myInput.read(buffer)) > 0) { - myOutput.write(buffer, 0, length); + final FileInputStream InputFile = new FileInputStream(directory.getPath() + "/database.db.crypt"); + Log.d(Config.LOGTAG,"Starting decryption and import of backup with password: " + DecryptionKey); + try { + EncryptDecryptFile.decrypt(InputFile, OutputFile, DecryptionKey); + } catch (NoSuchAlgorithmException e) { + Log.d(Config.LOGTAG, "Database importer: decryption failed with " + e); + e.printStackTrace(); + } catch (NoSuchPaddingException e) { + Log.d(Config.LOGTAG, "Database importer: decryption failed with " + e); + e.printStackTrace(); + } catch (InvalidKeyException e) { + Log.d(Config.LOGTAG, "Database importer: decryption failed (invalid key) with " + e); + e.printStackTrace(); + } catch (IOException e) { + Log.d(Config.LOGTAG, "Database importer: decryption failed (IO) with " + e); + e.printStackTrace(); } - Log.d(Config.LOGTAG,"Starting import of backup"); - - // Close and clear the streams - myOutput.flush(); - myOutput.close(); - myInput.close(); Log.d(Config.LOGTAG, "New Features - Uninstall old version of Pix-Art Messenger"); if (isPackageInstalled("eu.siacs.conversations")) { @@ -168,7 +267,6 @@ public class WelcomeActivity extends Activity { } else { restart(); } - } private void restart() { diff --git a/src/main/java/de/pixart/messenger/utils/EncryptDecryptFile.java b/src/main/java/de/pixart/messenger/utils/EncryptDecryptFile.java new file mode 100644 index 000000000..fd9392132 --- /dev/null +++ b/src/main/java/de/pixart/messenger/utils/EncryptDecryptFile.java @@ -0,0 +1,73 @@ +package de.pixart.messenger.utils; + +import android.util.Log; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.CipherOutputStream; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.SecretKeySpec; + +import de.pixart.messenger.Config; + +public class EncryptDecryptFile { + private static String cipher_mode = "AES/ECB/PKCS5Padding"; + + public static void encrypt(FileInputStream iFile, FileOutputStream oFile, String iKey) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException { + byte[] key = iKey.getBytes("UTF-8"); + Log.d(Config.LOGTAG, "Cipher key: " + Arrays.toString(key)); + MessageDigest sha = MessageDigest.getInstance("SHA-1"); + Log.d(Config.LOGTAG, "Cipher sha: " + sha.toString()); + key = sha.digest(key); + Log.d(Config.LOGTAG, "Cipher sha key: " + Arrays.toString(key)); + key = Arrays.copyOf(key, 16); // use only first 128 bit + Log.d(Config.LOGTAG, "Cipher sha key 16 bytes: " + Arrays.toString(key)); + SecretKeySpec sks = new SecretKeySpec(key, "AES"); + Cipher cipher = Cipher.getInstance(cipher_mode); + cipher.init(Cipher.ENCRYPT_MODE, sks); + Log.d(Config.LOGTAG, "Cipher IV: " + Arrays.toString(cipher.getIV())); + CipherOutputStream cos = new CipherOutputStream(oFile, cipher); + Log.d(Config.LOGTAG, "Encryption with: " + cos.toString()); + int b; + byte[] d = new byte[8]; + while ((b = iFile.read(d)) != -1) { + cos.write(d, 0, b); + } + cos.flush(); + cos.close(); + iFile.close(); + } + + public static void decrypt(FileInputStream iFile, FileOutputStream oFile, String iKey) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException { + byte[] key = iKey.getBytes("UTF-8"); + Log.d(Config.LOGTAG, "Cipher key: " + Arrays.toString(key)); + MessageDigest sha = MessageDigest.getInstance("SHA-1"); + Log.d(Config.LOGTAG, "Cipher sha: " + sha.toString()); + key = sha.digest(key); + Log.d(Config.LOGTAG, "Cipher sha key: " + Arrays.toString(key)); + key = Arrays.copyOf(key, 16); // use only first 128 bit + Log.d(Config.LOGTAG, "Cipher sha key 16 bytes: " + Arrays.toString(key)); + SecretKeySpec sks = new SecretKeySpec(key, "AES"); + Cipher cipher = Cipher.getInstance(cipher_mode); + cipher.init(Cipher.DECRYPT_MODE, sks); + Log.d(Config.LOGTAG, "Cipher IV: " + Arrays.toString(cipher.getIV())); + CipherInputStream cis = new CipherInputStream(iFile, cipher); + Log.d(Config.LOGTAG, "Decryption with: " + cis.toString()); + int b; + byte[] d = new byte[8]; + while ((b = cis.read(d)) != -1) { + oFile.write(d, 0, b); + } + oFile.flush(); + oFile.close(); + cis.close(); + } +} -- cgit v1.2.3