Web サーバーから暗号化されていないデータベースを正常にダウンロードし、そのデータベースを目的に使用できるアプリケーションがあります。ただし、これは安全ではなく、デバイスがルート化されている場合、サードパーティのアプリケーションがこのデータベースを参照できることはわかっています。そこで、SQLCipher を使用して暗号化することにしました。
私のアプリケーションは、独自の SQLCipher データベースを問題なく作成および読み取ることができます。次に、同じアプリケーションをエミュレーターで実行し、adb を使用してデータベースをプルし、このガイドを使用してダンプ ファイルを作成し、圧縮しました。また、アプリケーションが Web サーバーから zip ファイルをダウンロードして使用できるようにするサンプル コードに従いました。
ただし、データベースがダウンロードされ、アプリケーションによって抽出された後に問題が発生します。アプリケーションが正しくダウンロードできなかったか、データベースが復号化されていなかったようです。
しかし、データベースが .db ファイルから .dmp から .zip に変換された方法を確認する$ sqlite3 sampleDB.dp .dump > DBDump.dmp
と、sqlite3 コマンドでデータベースがすでに暗号化されていました (Mac OSX 用の SQLite Database Browser 2.0 では、db が暗号化されているか、データベース ファイルではないことが示されています)。したがって、sqlite3 データベースではないため、ダンプ ファイルが適切に作成されず、アプリケーションはダンプ ファイルを適切に解凍および実行できません。
私が試した別の解決策は、単純に .db ファイルをアップロードしてダウンロードすることでした。しかし、私は成功していません。
SQLCipher データベース ファイルをダウンロードして解読する方法を知っている人はいますか?
これまでのところ、これらは私のコードです(すべてのインポートはnet.sqlcipherであり、android.database.sqliteではないことに注意してください):
onCreate メソッドで呼び出される AsyncTask は、ダウンロードを開始するものです。
private class Connection extends AsyncTask<String, Void, String> {
@Override
protected void onPreExecute() {
super.onPreExecute();
Log.d("Hi", "Download Commencing");
}
@Override
protected String doInBackground(String... params) {
myDroidSQLDatabase = new MyDroidSQLDatabase(LogInPage.this);
myDroidSQLDatabase.open();
Log.d("Hi", "Downloading");
return "Executed!";
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
Log.d("Hi", "Done Downloading.");
}
}
MyDroidSQLDatabase クラス:
public class MyDroidSQLDatabase {
private SQLiteOpenHelper sqlLiteOpenHelper;
private SQLiteDatabase sqlLiteDatabase;
public MyDroidSQLDatabase(Context context) {
sqlLiteOpenHelper = new MyDroidSQLiteOpenHelper(context);
}
public void open() {
sqlLiteDatabase = sqlLiteOpenHelper.getWritableDatabase(DBAdapter.key);
}
public void close() {
sqlLiteDatabase.close();
}
public SQLiteDatabase getSqlLiteDatabase() {
return sqlLiteDatabase;
}
}
ここに私の MyDroidSQLiteOpenHelper クラスがあります
public class MyDroidSQLiteOpenHelper extends SQLiteOpenHelper {
private Context context;
private static final String __DB_NAME = "system.db";
private static final int __DB_VERSION = 1;
public MyDroidSQLiteOpenHelper(Context context) {
super(context, __DB_NAME, null, __DB_VERSION);
this.context=context;
}
@Override
public void onCreate(SQLiteDatabase sqlLiteDb) {
try {
SQLiteDBDeploy.deploy(sqlLiteDb,"http://192.168.1.4/dbtest/system.db");
} catch (IOException e) {
//Log.e(MyDBAppActivity.TAG,e.getMessage(),e);
throw new Error(e.getMessage());
}
}
@Override
public void onUpgrade(SQLiteDatabase sqlLiteDb, int oldVersion, int newVersion) {
}
}
そして、ここに SQLiteDBDeploy クラスがあります:
public class SQLiteDBDeploy {
private static final String TAG = "SQLiteDBDeploy";
private static List<String> ignoreSQLs;
static {
ignoreSQLs = new LinkedList<String>();
ignoreSQLs.add("--");
ignoreSQLs.add("begin transaction;");
ignoreSQLs.add("commit;");
ignoreSQLs.add("create table android_metadata (locale text);");
ignoreSQLs.add("create table \"android_metadata\" (locale text);");
ignoreSQLs.add("insert into android_metadata values('en_us');");
ignoreSQLs.add("insert into \"android_metadata\" values('en_us');");
}
/**
* Deploys given zip file in SQLiteDatabase
*
* @param sqlLiteDb
* the database
* @param context
* to use to open or create the database
* @param dbName
* dump zip file
* @throws IOException
*/
public static void deploy(SQLiteDatabase sqlLiteDb, Context context, String dbName) throws IOException {
Log.i(TAG, "reading zip file: " + dbName);
InputStream dbStream = context.getAssets().open(dbName);
deploy(sqlLiteDb, dbStream);
dbStream.close();
}
/**
* Deploys given zip file url in SQLiteDatabase
*
* @param sqlLiteDb
* the database
* @param dbUrl
* dump zip file url
* @throws IOException
*/
public static void deploy(SQLiteDatabase sqlLiteDb, String dbUrl) throws IOException {
Log.i(TAG, "reading url: " + dbUrl);
HttpURLConnection c = (HttpURLConnection) new URL(dbUrl).openConnection();
c.setRequestMethod("GET");
c.setDoOutput(true);
c.connect();
InputStream dbStream = c.getInputStream();
deploy(sqlLiteDb, dbStream);
dbStream.close();
c.disconnect();
}
/**
* Deploys given dump file stream in SQLiteDatabase
*
* @param sqlLiteDb the database
* @param dbStream stream to read dump data
* @throws IOException
*/
private static void deploy(SQLiteDatabase sqlLiteDb, InputStream dbStream) throws IOException {
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(dbStream));
ZipEntry entry = null;
while ((entry = zis.getNextEntry()) != null) {
Log.i(TAG, "deploying zip entry: " + entry);
InputStreamReader dbReader = new InputStreamReader(zis);
deploy(sqlLiteDb, dbReader);
}
}
/**
* Deploys given stream in SQLiteDatabase
*
* @param sqlLiteDb
* the database
* @param dbReader
* stream to read dump SQL statements
* @throws IOException
* @throws SQLException
*/
private static void deploy(SQLiteDatabase sqlLiteDb, InputStreamReader dbReader) throws IOException {
String sqlLine = null;
StringBuffer sqlBuffer = new StringBuffer();
BufferedReader bufferedReader = new BufferedReader(dbReader);
sqlLiteDb.beginTransaction();
try {
while ((sqlLine = bufferedReader.readLine()) != null) {
String sql = sqlLine.trim();
if (!isIgnoreSQL(sql)) {
if (sql.endsWith(";")) {
sqlBuffer.append(sql);
String execSQL = sqlBuffer.toString();
Log.d(TAG, "running sql=>" + execSQL);
sqlLiteDb.execSQL(execSQL);
sqlBuffer.delete(0, sqlBuffer.length());
} else {
if (sqlBuffer.length() > 0) {
sqlBuffer.append(' ');
}
sqlBuffer.append(sql);
}
}
}
sqlLiteDb.setTransactionSuccessful();
} finally {
sqlLiteDb.endTransaction();
}
}
/**
* Returns true if the given SQL statement is to be ignored
* @param sql SQL statement
* @return
*/
private static boolean isIgnoreSQL(String sql) {
if (sql.length() == 0) {
return true;
}
String lowerSQL = sql.toLowerCase();
for (String ignoreSQL : ignoreSQLs) {
if (lowerSQL.startsWith(ignoreSQL)) {
return true;
}
}
return false;
}
}
現在、私が考えているのは、データベースを実行する前にまずデータベースを復号化する関数を作成することです。ただし、どこに配置/呼び出すか、および復号化関数の記述方法がわかりません。
アイデアはありますか?
また、シェル コマンドを実行するために sqlcipher のコミュニティ エディションをダウンロードすることは、料金がかかるため、実行可能なソリューションではありません。