2

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 のコミュニティ エディションをダウンロードすることは、料金がかかるため、実行可能なソリューションではありません。

4

1 に答える 1

-1

ネットワークを介したデータベースの配置は、それが要件である場合のオプションです。暗号化されたデータベースの状態を SQLCipher コマンド シェルで確認することをお勧めします。Linux または OS X でビルドするための手順はこちらで確認できます。これにより、プロセス中に無効なダウンロードを除外できます。

于 2013-09-09T19:54:52.467 に答える