SQLite
 sql >> Base de données >  >> RDS >> SQLite

Comment puis-je lire des données à partir d'une base de données chiffrée à l'aide de SQLiteAssetHelper ?

Je crois que vous devez :-

a) Copiez le fichier du fichier d'actifs vers un emplacement temporaire ou vers la destination finale (data/data/package_name/databases).

  • Où sera package_name selon le package.
    • getDatabasePath(databasename).getPath() récupérera le chemin sous forme de chaîne, par ex. mDBPath = context.getDatabasePath(database).getPath(); vous n'avez donc même pas besoin de coder le nom du package.

b) Demander et récupérer la phrase de passe.

c) Décryptez le fichier (en le copiant dans la destination finale copiée dans un emplacement temporaire).

d) Accédez ensuite à la base de données.

Noter! La base de données ne serait plus cryptée, donc si vous vouliez le cryptage, vous deviez alors introduire le cryptage.

Code pouvant être adapté

Vous pouvez adapter le code suivant, c'est-à-dire ajouter le code de déchiffrement (comme indiqué).

  • Notez que ce code n'est pas destiné à la production, mais est un code qui a été créé pour l'expérimentation/l'exploration des ressources d'ouverture. En tant que tel, il est exagéré de consigner pratiquement tout.

  • Il a également été conçu pour prendre en charge jusqu'à 10 bases de données (selon MAXIMUM_HELPERS et helper_index ). L'exemple d'utilisation utilise 3 bases de données (la 4ème commentée était pour tester une non-base de données fichier).

Le code (notez que le code de déchiffrement serait placé) :-

public class OpenAssetDBHelper extends SQLiteOpenHelper {

    private static final String LOGTAG = "OADB-HLPR";
    public static final int MAXIMUM_HELPERS = 10;
    private String mDBPath, mAssetPath;
    private static OpenAssetDBHelper mInstance[] = new OpenAssetDBHelper[MAXIMUM_HELPERS];
    private SQLiteDatabase mDB;

    /**
     * OpenAssetDBHelper Class that will copy a predefined database
     * from the assets folder and then open it is the database;
     *
     * The copy will only be done if the database does not exist;
     *
     * Note this code is intended to be used for development and/or
     * experimentation, hence the extensive logging.
     */

    /**
     * get an OpenAssetDBHelper instance as a singleton;
     * Note! caters for up to 10 OpenAssetDBHelpers for up to 10 databases
     * as specified by the helper_index
     *
     * @param helper_index  Index to this instance/database
     *                      (0-MAXIMUM_HELPERS less 1)
     * @param context       Context for the database
     * @param database      Database name (i.e. file name)
     * @param dbversion     Database version (user_version)
     * @param assetfile     Name of the asset file to be copied to the database
     * @param asset_sub_directories String Array of the sub-directories where
     *                              the asset file is located;
     *                              MUST be in order
     * @return              The resultant OpenAssetDBHelper
     */
    public static synchronized OpenAssetDBHelper getInstance(
            int helper_index,
            Context context,
            String database,
            int dbversion,
            String assetfile,
            String[] asset_sub_directories) {
        // Checck that helper_index is within bounds
        if (helper_index > (MAXIMUM_HELPERS -1)) {
            throw new RuntimeException(
                    "Helper Index greater than " +
                            MAXIMUM_HELPERS
            );
        }
        if (helper_index < 0) {
            throw new RuntimeException(
                    "Helper Index cannot be negative, must be 0-" +
                            MAXIMUM_HELPERS
            );
        }
        // Create the respective OpenAssetDBHelper instance
        if(mInstance[helper_index] == null) {
            mInstance[helper_index] = new OpenAssetDBHelper(context,
                    database,
                    dbversion,
                    assetfile,
                    asset_sub_directories);
        }
        return mInstance[helper_index];
    }

    /**
     * Construct an OpenAssetDBHelper instance;
     * Note! can only be called within class
     *
     * @param context       the context to be used
     * @param database      the database name (equates to filename)
     * @param dbversion     the databaae version (user_version)
     * @param assetfile     The name of the asset file i.e. the pre-defined db
     * @param directories   The hierarchy of directories within the assets folder
     *                      where the asset file is located
     *                      (null or zero elements = in the assets folder)
     */
    private OpenAssetDBHelper(Context context,
                              String database,
                              int dbversion,
                              String assetfile,
                              String[] directories) {
        super(context, database, null, dbversion);
        Log.d(LOGTAG,"OpenAssetDBHelper being constructed.");

        mDBPath = context.getDatabasePath(database).getPath();
        if (assetfile == null || assetfile.length() < 1) {
            assetfile = database;
        }
        mAssetPath = buildAssetPath(directories,assetfile);

        if (!ifDatabaseExists(mDBPath)) {
            Log.d(LOGTAG,"Database " + database + " not found at " + mDBPath + " so attempting to copy from assets.");
            if (copyDatabaseFromAssets(context,mDBPath, database, mAssetPath)) {
                Log.d(LOGTAG, "Successfully Copied Database from Assets.");
            } else {
                throw new RuntimeException("No Database Available.");
            }
        }
        // Force Database open and store it
        this.mDB = this.getWritableDatabase();
        logDatabaseTableInformation(mDB);
        Log.d(LOGTAG,"OpenAssetDBHelper constructed.");
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        Log.d(LOGTAG,new Object(){}.getClass().getEnclosingMethod().getName() + " initiated.");
        // As Database is copied from assets nothing to do in onCreate!
        Log.d(LOGTAG,new Object(){}.getClass().getEnclosingMethod().getName() + " completed.");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        Log.d(LOGTAG,new Object(){}.getClass().getEnclosingMethod().getName() + " initiated.");
        // Nothing to do as it's early days in the Database's lifetime.
        Log.d(LOGTAG,new Object(){}.getClass().getEnclosingMethod().getName() + " completed.");
    }

    /**
     * Check to see if the Database exists,
     * if it doesn't exists then check to see if
     * the database directory exists,
     * if the directory(ies) does(do) not exist then make the directory(ies);
     *
     *
     * @param dbpath        The path to the database
     * @return              true if the database exists, else false
     */
    private boolean ifDatabaseExists(String dbpath) {
        Log.d(LOGTAG,new Object(){}.getClass().getEnclosingMethod().getName() + " initiated.");
        File db = new File(dbpath);
        if(db.exists()) return true;
        File dir = new File(db.getParent());
        if (!dir.exists()) {
            dir.mkdirs();
        }
        return false;
    }

    /**
     * Copy the Database from the assets folder
     * @param context
     * @param dbpath
     * @return
     */
    private boolean copyDatabaseFromAssets(Context context,String dbpath, String dbname, String asset) {
        String thisclass = new Object(){}.getClass().getEnclosingMethod().getName();
        Log.d(LOGTAG,thisclass + " initiated");
        InputStream assetsdb;
        OutputStream database;
        File db = new File(dbpath);
        int filesize;
        // Get the asset file
        try {
            Log.d(LOGTAG,thisclass + " attempting to find asset " + asset);
            assetsdb = context.getAssets().open(asset);
            filesize = assetsdb.available();
            Log.d(LOGTAG,thisclass + " asset " + asset +
                    " located successfully with a size of " +
                    Integer.toString(filesize)
            );
        } catch (IOException e) {
            Log.d(LOGTAG,thisclass + " Did not locate asset " + asset);
            e.printStackTrace();
            return false;
        }

>>>> Votre décryptage irait ici <<<<

        // Read the first 16 bytes from the asset file
        byte[] dbcheck = new byte[16];
        try {
            assetsdb.read(dbcheck,0,16);
        } catch (IOException e) {
            Log.d(LOGTAG, thisclass + " failed trying to read 16 bytes to check for a valid database. ");
            e.printStackTrace();
            return false;
        }

        // Check that the asset file is an SQLite database
        String chkdb = new String(dbcheck);
        if(!chkdb.equals("SQLite format 3\u0000")) {
            Log.d(LOGTAG,thisclass + " asset " +
                    asset +
                    " is not a valid SQLite Database File (found " +
                    chkdb +
                    " at bytes 1-16 instead of SQLite format 3)");
            try {
                assetsdb.close();
            } catch (IOException e) {
                // Not worth doing anything
            }
            return false;
        }
        // Close the asset file
        try {
            assetsdb.close();
        } catch (IOException e) {
            Log.d(LOGTAG,thisclass +
                    " failed to close assets file after checking for a valid database."
            );
            return false;
        }
        // Re-open the asset file
        try {
            assetsdb = context.getAssets().open(asset);
            filesize = assetsdb.available();
        } catch (IOException e) {
            Log.d(LOGTAG, thisclass +
                    " failed trying to re-open asset " +
                    asset +
                    " after checking for a valid database."
            );
            e.printStackTrace();
            return false;
        }

        // Read the entire asset file into a buffer
        Log.d(LOGTAG, thisclass +
                " copying asset database " +
                dbname +
                " into buffer of size " +
                filesize
        );
        byte[] buffer = new byte[filesize];
        // Close the asset file
        try {
            assetsdb.read(buffer);
            Log.d(LOGTAG,thisclass +
                    " closing asset database " + dbname
            );
            assetsdb.close();
        } catch (IOException e) {
            Log.d(LOGTAG, thisclass +
                    " failed while copying asset database " +
                    dbname +
                    " (or closing asset database)."
            );
            e.printStackTrace();
            return false;
        }
        // Open the new database file
        try {
            Log.d(LOGTAG,thisclass + " attempting to open new database file " + dbpath);
            database = new FileOutputStream(dbpath);
        } catch (IOException e) {
            Log.d(LOGTAG, thisclass + " failed to open new database file.");
            e.printStackTrace();
            return false;
        }
        // Write the new database file
        try {
            Log.d(LOGTAG, thisclass + " writing new database file " + dbpath);
            database.write(buffer);
        } catch (IOException e) {
            Log.d(LOGTAG, thisclass + " failed while writing new database file " + dbpath);
            e.printStackTrace();
            return false;
        }
        // Flush the new database file
        try {
            Log.d(LOGTAG, thisclass + " flushing new database file " + dbpath);
            database.flush();
        } catch (IOException e) {
            Log.d(LOGTAG, thisclass + " failed while flushing new database file " + dbpath);
            e.printStackTrace();
            return false;
        }
        // Close the new database file
        try {
            Log.d(LOGTAG, thisclass + " closing new database file " + dbpath);
            database.close();
        } catch (IOException e) {
            Log.d(LOGTAG, thisclass + " failed while closing new database file " + dbpath);
            e.printStackTrace();
            return  false;
        }
        Log.d(LOGTAG,new Object(){}.getClass().getEnclosingMethod().getName() + " completed.");
        return true;
    }

    /**
     * Log Database table Information
     */
    private void logDatabaseTableInformation(SQLiteDatabase db) {
        Log.d(LOGTAG,new Object(){}.getClass().getEnclosingMethod().getName() + " initiated.");
        String mastertable = "sqlite_master";
        String typecolumn = "type";
        String namecolumn = "name";
        String sqlcolumn = "sql";
        String[] args = new String[]{"table","android_metadata"};
        Cursor csr = db.query(mastertable,
                null,
                typecolumn + "=? AND " + namecolumn + "!=?",
                 args,
                null,null,null
        );
        while (csr.moveToNext()) {
            Log.d(LOGTAG,"Database contains Table " +
                    csr.getString(csr.getColumnIndex(namecolumn)) +
                    " created by SQL " +
                    csr.getString(csr.getColumnIndex(sqlcolumn))
            );
            logTableInformation(db, csr.getString(csr.getColumnIndex(namecolumn)));
        }
        csr.close();
        Log.d(LOGTAG,new Object(){}.getClass().getEnclosingMethod().getName() + " completed.");
    }

    /**
     * Write Table information, Table name, Column Count,
     * Row Count and Column Names to the Log
     * @param table Name of the table to be reported on
     */
    private void logTableInformation(SQLiteDatabase db, String table) {
        Cursor csr = db.query(table,
                null,
                null,
                null,
                null,
                null,
                null
        );
        Log.d(LOGTAG,"Table is " +
                table +
                " Column Count = " +
                Integer.toString(csr.getColumnCount()) +
                " Row Count = " +
                Long.toString(DatabaseUtils.queryNumEntries(mDB,table))
        );
        StringBuilder columns_as_string = new StringBuilder();
        for (String s: csr.getColumnNames()) {
            columns_as_string.append(s).append(" ");
        }
        Log.d(LOGTAG, "\tColumns are :- " + columns_as_string);
        csr.close();
    }

    /**
     * Build the sub-path to the asset, according to the directories specified
     *
     * @param directories   directories underneath the assets folder where
     *                      the asset files is located, null or empty
     *                      array if file is located directly in the
     *                      assets folder;
     *                      directories must be specified in the order
     *                      in which they appear in the path.
     * @param filename      The filename of the asset
     * @return              The fill sub-path to the asset
     */
    private String buildAssetPath(String[] directories, String filename) {
        StringBuilder sb = new StringBuilder();
        final String SEPERATOR = "/";
        if (directories != null && directories.length > 0) {
            for (String s: directories) {
                sb.append(s);
                if (!s.substring(s.length()-1,s.length()).equals(SEPERATOR)) {
                    sb.append(SEPERATOR);
                }
            }
            sb.append(filename);
            return sb.toString();
        } else {
            return filename;
        }
    }
}

Exemple d'utilisation :-

public class MainActivity extends AppCompatActivity {

    public static final int DBVERSION = 1;
    public static final String DBNAME1 = "openassetdb.db";
    public static final int DB1_INDEX = 0;
    public static final String DBNAME2 = "myshopping";
    public static final int DB2_INDEX = 1;
    public static final String DBNAME3 = "rumplestilskin";
    public static final int DB3_INDEX = 2;
    public static final String DBNAME4 = "notadatabase";
    public static final int DB4_INDEX = 3;

    OpenAssetDBHelper mOADBHlpr;
    OpenAssetDBHelper mShoppingHelper;
    OpenAssetDBHelper mShopper;
    OpenAssetDBHelper mNotADatabase;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // Example 1 - Database file located in the assets folder and
        //              database name same as file name
        mOADBHlpr = OpenAssetDBHelper.getInstance(DB1_INDEX,
                this,
                DBNAME1,
                DBVERSION,
                DBNAME1,
                null
        );
        // Example 2 - Database file in databases directory of the assets folder
        //              database name different to the asset filename
        mShoppingHelper = OpenAssetDBHelper.getInstance(DB2_INDEX,
                this,
                DBNAME2,
                DBVERSION,
                "shopper",
                new String[]{"databases"}
                );
        // Example 3 - Databse file in databases directory of the assets folder
        //              database name different to the asset filename
        mShopper = OpenAssetDBHelper.getInstance(DB3_INDEX,
                this,
                DBNAME3,
                DBVERSION,
                "Shopper.sqlite",
                new String[]{"databases"}
                );
        /*
        mNotADatabase = OpenAssetDBHelper.getInstance(DB4_INDEX,
                this,
                DBNAME4,
                DBVERSION,
                "notadatabasefile",
                new String[]{"databases"});
                */
    }
}

Notes explicatives

  • 3 (4ème commenté) Des assistants de base de données sont créés.

  • Le premier crée l'assistant de base de données nommé mOADBHlpr pour la base de données nommée openassetdb.db (s'il n'existe pas) en copiant le fichier openassetdb.db du dossier assets.

    • Le premier paramètre passé à OpenAssetDBHelper est l'index de l'assistant 0-9 (sur les 10 instances d'assistance prises en charge).

    • Le 2ème paramètre est le contexte,

    • Le 3e paramètre est le nom de la base de données résultante (c'est-à-dire qu'il peut être différent du nom du fichier d'actif).
    • Le 4ème paramètre est la DBVERSION (notez qu'aucune expérimentation n'a encore été entreprise en ce qui concerne sa modification).
    • Le 5ème paramètre est le nom du fichier d'asset.
    • Le 6ème paramètre est pour les sous-répertoires (hiérarchiquement) avec le dossier assets, par ex. les derniers exemples ont le fichier d'asset situé dans un dossier nommé databases dans le dossier assets c'est-à-dire assets/databases