Я считаю, что единственным разрешением является использование специально созданного rawExecSQL , метода.
не может использовать.raw или rawExecSQL из-за проблем с безопасностью
Нет проблем с безопасностью при использовании этого, поскольку нет шансов для SQL-инъекций, так как нет ввода пользователя.возможно см. SQL-инъекция .
Я считаю, что проблема заключается в том, что в общем случае exec / execute разрешает ограниченные результаты, rawQuery / query возвращает Cursor.Я полагаю, что преобразование, вероятно, генерирует SQL, модифицируя его путем шифрования данных и последующего выполнения этого результирующего SQL в виде потока операторов (отсюда код ошибки 100 при попытке использовать execute).Требуется специальный метод (следовательно, rawExecSQL ), поскольку большинство встроенных методов допускают выполнение только одного оператора.
Рабочий пример
Вотрабочий пример, с другими попытками, закомментированными с результатом (включая код ошибки 100 при попытке использовать SQLiteStatement ).
В примере создается база данных normal ,загружает некоторые данные, извлекает и выгружает данные (для сравнения / проверки), закрывает их, используя стандартные методы SQLiteDatabase android.
Затем создается база данных зашифрованная с использованием метода openorcreate SQlCipher, а затем немедленнозакрыто (таким образом создается файл).
Затем открывается база данных normal с помощью методов SQLCipher, затем присоединяется вновь созданная пустая база данных зашифрованная , выполняется преобразованиеготово, и зашифрованная база данных отключена.Затем normal закрывается.
Наконец, открывается новая зашифрованная база данных , данные извлекаются и сбрасываются (для сравнения / проверки).
Код: -
public class MainActivity extends AppCompatActivity {
String normaldbname = "mydb";
String encrypteddbname = "myencrypteddb";
String password = "thepassword";
String tablename = "mytable";
String idcolumn = BaseColumns._ID;
String namecolumn = "name";
String[] namelist = new String[]{
"Fred","Anne","Jane","John",
};
SQLiteDatabase normaldb;
net.sqlcipher.database.SQLiteDatabase normal_for_encryption;
net.sqlcipher.database.SQLiteDatabase encrypteddb;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
net.sqlcipher.database.SQLiteDatabase.loadLibs(this);
normaldb = SQLiteDatabase.openOrCreateDatabase(this.getDatabasePath(normaldbname).getPath(),null);
normaldb.execSQL("CREATE TABLE IF NOT EXISTS " + tablename + " (" +
idcolumn +
" INTEGER PRIMARY KEY, " +
namecolumn +
" TEXT)");
ContentValues cv = new ContentValues();
normaldb.beginTransaction();
//for (int i=0; i < 1000; i++) { for larger test
for (String name : namelist) {
cv.clear();
cv.put(namecolumn, name);
normaldb.insert(tablename, null, cv);
}
//}
normaldb.setTransactionSuccessful();
normaldb.endTransaction();
DatabaseUtils.dumpCursor(
normaldb.query(tablename,null,null,null,null,null,null)
);
normaldb.close();
net.sqlcipher.database.SQLiteDatabase.openOrCreateDatabase(this.getDatabasePath(encrypteddbname).getPath(),password,null).close();
normal_for_encryption = net.sqlcipher.database.SQLiteDatabase.openDatabase(
this.getDatabasePath(normaldbname).getPath(),
"",null,
net.sqlcipher.database.SQLiteDatabase.OPEN_READWRITE
);
net.sqlcipher.database.SQLiteStatement stmnt = normal_for_encryption.compileStatement("ATTACH DATABASE ? AS encrypted KEY ?");
stmnt.bindString(1,this.getDatabasePath(encrypteddbname).getPath());
stmnt.bindString(2,password);
stmnt.execute();
/* Ouch net.sqlcipher.database.SQLiteException: error code 100: another row available
net.sqlcipher.database.SQLiteStatement stmnt2 = normal_for_encryption.compileStatement("SELECT sqlcipher_export('encrypted')");
stmnt2.execute();
*/
//normal_for_encryption.rawQuery("SELECT sqlcipher_export('encrypted')",null); //<<<<<<<<< Ouch no such table: mytable: , while compiling: SELECT * FROM mytable
//normal_for_encryption.execSQL("SELECT sqlcipher_export('encrypted')"); //<<<<<<<<< Ouch net.sqlcipher.database.SQLiteException: unknown error: Queries cannot be performed using execSQL(), use query() instead.
normal_for_encryption.rawExecSQL("SELECT sqlcipher_export('encrypted')"); //<<<<<<<<< WORKS >>>>>>>>>>
normal_for_encryption.execSQL("DETACH DATABASE encrypted");
normal_for_encryption.close();
encrypteddb = net.sqlcipher.database.SQLiteDatabase.openDatabase(
this.getDatabasePath(encrypteddbname).getPath(),
password,null,
net.sqlcipher.database.SQLiteDatabase.OPEN_READWRITE
);
net.sqlcipher.DatabaseUtils.dumpCursor(
encrypteddb.query(tablename,null,null,null,null,null,null)
);
encrypteddb.close();
}
}
- Снова обратите внимание на закомментированные строки, которые не работают.
- Единственным недостатком безопасности в приведенном выше является пароль, который не был защищен дляудобство.
Результат: -
Часть 1 - до преобразования / шифрования: -
2019-05-14 21:10:54.032 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@c237ffc
2019-05-14 21:10:54.032 I/System.out: 0 {
2019-05-14 21:10:54.032 I/System.out: _id=1
2019-05-14 21:10:54.032 I/System.out: name=Fred
2019-05-14 21:10:54.032 I/System.out: }
2019-05-14 21:10:54.032 I/System.out: 1 {
2019-05-14 21:10:54.032 I/System.out: _id=2
2019-05-14 21:10:54.033 I/System.out: name=Anne
2019-05-14 21:10:54.033 I/System.out: }
2019-05-14 21:10:54.033 I/System.out: 2 {
2019-05-14 21:10:54.033 I/System.out: _id=3
2019-05-14 21:10:54.033 I/System.out: name=Jane
2019-05-14 21:10:54.033 I/System.out: }
2019-05-14 21:10:54.033 I/System.out: 3 {
2019-05-14 21:10:54.034 I/System.out: _id=4
2019-05-14 21:10:54.034 I/System.out: name=John
2019-05-14 21:10:54.034 I/System.out: }
2019-05-14 21:10:54.034 I/System.out: <<<<<
Часть 2 после шифрования из зашифрованных данных.
2019-05-14 21:10:54.871 I/System.out: >>>>> Dumping cursor net.sqlcipher.CrossProcessCursorWrapper@1bff13d
2019-05-14 21:10:54.872 I/System.out: 0 {
2019-05-14 21:10:54.872 I/System.out: _id=1
2019-05-14 21:10:54.872 I/System.out: name=Fred
2019-05-14 21:10:54.872 I/System.out: }
2019-05-14 21:10:54.872 I/System.out: 1 {
2019-05-14 21:10:54.872 I/System.out: _id=2
2019-05-14 21:10:54.872 I/System.out: name=Anne
2019-05-14 21:10:54.872 I/System.out: }
2019-05-14 21:10:54.872 I/System.out: 2 {
2019-05-14 21:10:54.872 I/System.out: _id=3
2019-05-14 21:10:54.872 I/System.out: name=Jane
2019-05-14 21:10:54.872 I/System.out: }
2019-05-14 21:10:54.873 I/System.out: 3 {
2019-05-14 21:10:54.873 I/System.out: _id=4
2019-05-14 21:10:54.873 I/System.out: name=John
2019-05-14 21:10:54.873 I/System.out: }
2019-05-14 21:10:54.873 I/System.out: <<<<<