We are trying to encrypt a database using sqlcipher for an app on an windows system.
Following is the code we are trying to encrypt
SQLiteDatabase.loadLibs(this);
File databaseFile = getDatabasePath("demo.db");
databaseFile.mkdirs();
databaseFile.delete();
SQLiteDatabase database = SQLiteDatabase.openOrCreateDatabase(databaseFile, "test123", null);
database.execSQL("create table t1(a, b)");
database.execSQL("insert into t1(a, b) values(?, ?)",
new Object[]{"one for the money",
"two for the show"});
database.close();
We are successfully able to encrypt the database and when we are trying to decrypt the database we are getting an error saying like file is encrypted or database not found.
Can some one please help in decrypting the database.
Thanks in advance :)
EDIT
File unencFile = getDatabasePath("Plaintext.db");
unencFile.delete();
File databaseFile = getDatabasePath("demo.db");
databaseFile.mkdirs();
databaseFile.delete();
SQLiteDatabase database = SQLiteDatabase.openOrCreateDatabase(databaseFile, "test123", null);
database.rawExecSQL(String.format("ATTACH DATABASE '%s' as plaintext KEY '' ", unencFile.getAbsolutePath()));
// database.rawExecSQL("ATTACH DATABASE '"+"plaintext.db"+"' AS plaintext KEY '';");
database.rawExecSQL("SELECT sqlcipher_export('plaintext');");
database.rawExecSQL("DETACH DATABASE plaintext;");
android.database.sqlite.SQLiteDatabase sqlDB = android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(unencFile, null);
sqlDB.close();
database.close();
EDIT 2
Now I am able to get the decrypted Plaintext.db file. but table name in the db is android_metadata rather than t1. Both the table size are same but i am not able to see data.
You are deleting the DB file before decrypting. Do changes to your code like below and try
File unencFile = getDatabasePath(PhoneNumbersDatabase.DATABASE_NAME);
unencFile.delete();
File databaseFile = getDatabasePath("demo.db");
SQLiteDatabase database = SQLiteDatabase.openOrCreateDatabase(databaseFile, "test123", null);
if (database.isOpen()) {
database.rawExecSQL(String.format("ATTACH DATABASE '%s' as plaintext KEY '';",unencFile.getAbsolutePath()));
database.rawExecSQL("SELECT sqlcipher_export('plaintext');");
database.rawExecSQL("DETACH DATABASE plaintext;");
android.database.sqlite.SQLiteDatabase sqlDB = android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(unencFile, null);
sqlDB.close();
database.close();
}
databaseFile.delete();
Also make changes to your DB encryption code like below -
databaseFile.delete();
databaseFile.mkdirs();
Related
I am using DBFlow with SQLCipher. I am trying to encrypt the already existing SQLite Database(using DBFlow) with SQLCipher in Android.
I used the following code to encrypt the DB:
private void encryptDB() {
SQLiteDatabase.loadLibs(this);
String password = "test123";
String LEGACY_DATABASE_NAME = "legacy.db";
String NEW_DATABASE_NAME = "new_crypt.db";
File newDBFile = getDatabasePath(NEW_DATABASE_NAME);
File legacyFile = getDatabasePath(LEGACY_DATABASE_NAME);
if (!newDBFile.exists() && legacyFile.exists()) {
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(legacyFile, "", null);
db.rawExecSQL(String.format("ATTACH DATABASE '%s' AS encrypted KEY '%s';", newDBFile.getAbsolutePath(), password));
db.rawExecSQL("SELECT sqlcipher_export('encrypted')");
db.rawExecSQL("DETACH DATABASE encrypted;");
db.close();
db = SQLiteDatabase.openDatabase(newDBFile.getAbsolutePath(), password, null, SQLiteDatabase.OPEN_READWRITE);
db.close();
legacyFile.delete();
newDBFile.renameTo(legacyFile);
}
}
The DB is encrypted fine but when I am trying to write any operations:
Place place = new Place();
place.setName("Test");
place.save();
DB Model:
#Table(database = DatabaseManager.class)
public class Place extends BaseModel {
#Column
String name;
// set and get methods goes here
}
then getting the following exception:
io.reactivex.exceptions.UndeliverableException: android.database.sqlite.SQLiteReadOnlyDatabaseException: attempt to write a readonly database (code 1032 SQLITE_READONLY_DBMOVED[1032])
I found a similar post here but not found any solution to it.
Also, I found this to encrypt the DBFlow database with SQLCipher and implemented it. Then it is working if I install it as a fresh app but when I install this app on top of the old app which is having not encrypted DB then it is failing.
net.sqlcipher.database.SQLiteException: file is not a database: , while compiling: select count(*) from sqlite_master;
Please suggest how can I fix this?
I have wrote those lines of code to be able to add something in my SQL DB by using "external" values. Does anyone knows how can I delete something from my DB by using again external values?
My Code to add:
String UserName = "AnyName";
String UserAge = "AnyAge";
try {
myDatabase = this.openOrCreateDatabase("Users", MODE_PRIVATE, null);
myDatabase.execSQL("CREATE TABLE IF NOT EXISTS users (name VARCHAR, age VARCHAR)");
SQLiteStatement statement = myDatabase.compileStatement("INSERT INTO users (name, age) VALUES(?, ?)");
statement.bindString(1, UserName);
statement.bindString(2, UserAge);
statement.execute();
}catch (Exception e){
e.printStackTrace();
}
You can directly delete with database instance using delete method like below
String UserName = "AnyName";
String UserAge = "AnyAge";
myDatabase = this.openOrCreateDatabase("Users", MODE_PRIVATE, null);
myDatabase.delete("users", "name =? AND age =?" , new String[]{UserName, UserAge});
this is my code :
SQLiteDatabase.loadLibs(this);
File databaseFile = getDatabasePath("db");
SQLiteDatabase database = SQLiteDatabase.openOrCreateDatabase(databaseFile, "Ab61", null);
database.execSQL("drop table comments");
database.execSQL("CREATE TABLE IF NOT EXISTS comments(_id INTEGER PRIMARY KEY,spot_id INTEGER,server_id INTEGER" +
",description TEXT,uid TEXT ,dates TEXT,name TEXT)");
database.execSQL("insert into comments values (null, 34, 3, 'asdasd', 'asdsad', 'asda', 'asds');");
Cursor ss=db.rawQuery("SELECT * from comments", null);
Log.v("this",Integer.toString(ss.getCount()));
I've db database ,it's an sqlite database . this is a test code so , I remove the whole database ,create it again and insert a new row .
It doesn't get any error .
the cursor getCount return 0 , it means there is nothing added to database .
It driving me crazy :(
could you help me ?
You are inserting the data into a different database (database) than that which you are querying (db).
private void InitializeSQLCipher(){
try {
SQLiteDatabase.loadLibs(getApplicationContext());
}
catch (Exception e) {
e.printStackTrace();
}
File databaseFile = getDatabasePath("demo.db");
databaseFile.mkdirs();
databaseFile.delete();
database = SQLiteDatabase.openOrCreateDatabase(databaseFile, "test123", null);
database.execSQL("create table t1(a, b)");
database.execSQL("insert into t1(a, b) values(?, ?)", new Object[]{"one for the money","two for the show"});
}
Cursor c = null;
c = database.rawQuery("SELECT a,b from t1", null);
if (c != null){
if(c.moveToFirst()){
while(!c.isAfterLast()){
//Log.e("xlcx", c.getString(c.getColumnIndex("a")));
Log.d("xlcx", c.getString(c.getColumnIndex("b")));
c.moveToNext();
}
}
}
please refer
http://androidjug.blogspot.in/2014/07/sqlcipher-for-android-application.html
I am using sqlciper with android to encrypt an existing sqlite db, and ran into a problem that the encrypted db didn't contain my tables, it only contains sqlite_master and android_metadata.
My original db looks like:
shell#umts_spyder:/sdcard $ sqlite3 d000000.dat
sqlite3 d000000.dat
SQLite version 3.7.4
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> select * from sqlite_master;
select * from sqlite_master;
table|android_metadata|android_metadata|2|CREATE TABLE android_metadata (locale TEXT)
table|PageData|PageData|3|CREATE TABLE PageData(File_Path TEXT NOT NULL UNIQUE, File_Content BLOB)
index|sqlite_autoindex_PageData_1|PageData|4|
I paste my encrypting code below, use empty key("") to open the plain db, if using null, NullPointerException raised(For both plain db I mentioned in the end of my post):
File plain = new File(mDbPath); /* /sdcard/d0000000.dat */
File encrypt = new File(plain.getParent(), "encrypted.dat");
encrypt.delete();
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(mDbPath, "", null);
String sql = String.format("ATTACH DATABASE '%s' AS encrypted KEY '%s'", encrypt.getPath(), mvKey.getText().toString()); // key is qqqqqqqq
db.execSQL(sql);
db.rawQuery("SELECT sqlcipher_export('encrypted')", null);
db.execSQL("DETACH DATABASE encrypted");
and below is the the code I used to test the encrypted db, there is only "android_metadata, " in the output, my table PageData lost. If I use "select * from PageData" directly, it raises no such table exception:
File file = new File(Environment.getExternalStorageDirectory(), "encrypted.dat");
if(!file.exists())
{
mvBrowse.setText("not exist");
return;
}
String key = mvKey.getText().toString();
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(file, key, null);
Cursor cursor = db.rawQuery("SELECT * FROM sqlite_master", null);
String str = new String();
while(cursor.moveToNext())
{
str += cursor.getString(1)+", ";
}
mvBrowse.setText(str); // output is "android_metadata, "
cursor.close();
db.close();
The encrypting should work, because if I open encrypted.dat with empty("") key, it raise "file is encrypted or is not a database" exception, but I can read sqlite_master and android_metadata table with correct key.
I Confirmed the path I tested is the same one I write encryption to;
Tested creating plain db by sqlcipher, using empty key:
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(file, "", null); /* /sdcard/d000000.dat */
db.execSQL("CREATE TABLE PageData(File_Path TEXT NOT NULL UNIQUE, File_Content BLOB)");
As well as creating it by standard sqlite tools(SQLite Export Professional, and I didn't use BLOB field in this case, just only TEXT and INTEGER);
And tested with two API versions, "SQLCipher for Android v2.2.2" and "SQLCipher for Android v3.0.0".
I also tried to apply the Decrypt precedure as describled in http://sqlcipher.net/sqlcipher-api/ to a encrypted db.
All above got the same result. Will somebody help me? I beleive there is some tiny wrong inside but I can't figure it out.
Finally, I get fixed the problem, by learning from https://github.com/sqlcipher/sqlcipher-android-tests/blob/master/src/main/java/net/zetetic/tests/ImportUnencryptedDatabaseTest.java. (Thanks to #avlacatus, the link has been moved to: https://github.com/sqlcipher/sqlcipher-android-tests/blob/master/app/src/main/java/net/zetetic/tests/ImportUnencryptedDatabaseTest.java). The problem was, when executing the encrypting precedure, one must NOT use execSQL or rawQuery, but use a new introduced method "rawExecSQL. To be clear, the following code just work fine:
String sql = String.format("ATTACH DATABASE '%s' AS encrypted KEY '%s'", encrypt.getPath(), mvKey.getText().toString());
db.rawExecSQL(sql);
db.rawExecSQL("SELECT sqlcipher_export('encrypted')");
db.rawExecSQL("DETACH DATABASE encrypted");
I'm using the below piece of code to encrypt and decrypt the database i'm able to encrypt but when i'm trying to decrypt i'm getting the below exception.I referred this documentation and TestCases too still facing the same problem.
Exception:
sqlite returned: error code = 26, msg = file is encrypted or is not a database
CREATE TABLE android_metadata failed
Failed to setLocale() when constructing, closing the database
net.sqlcipher.database.SQLiteException: file is encrypted or is not a database
Encrypt:
private static void ConvertNormalToSQLCipheredDB(Context context,
String startingFileName, String endingFileName, String filePassword)
throws IOException {
File mStartingFile = context.getDatabasePath(startingFileName);
if (!mStartingFile.exists()) {
return;
}
File mEndingFile = context.getDatabasePath(endingFileName);
mEndingFile.delete();
SQLiteDatabase database = null;
try {
database = SQLiteDatabase.openOrCreateDatabase(MainApp.mainDBPath,
"", null);
database.rawExecSQL(String.format(
"ATTACH DATABASE '%s' AS encrypted KEY '%s'",
mEndingFile.getAbsolutePath(), filePassword));
database.rawExecSQL("select sqlcipher_export('encrypted')");
database.rawExecSQL("DETACH DATABASE encrypted");
database.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (database.isOpen())
database.close();
mStartingFile.delete();
}
}
Decrypt:
private void decryptDatabase() {
File unencryptedFile = getDatabasePath(PhoneNumbersDatabase.DATABASE_NAME);
unencryptedFile.delete();
File databaseFile = getDatabasePath("encrypt.db");
SQLiteDatabaseHook hook = new SQLiteDatabaseHook() {
public void preKey(SQLiteDatabase sqLiteDatabase) {
sqLiteDatabase
.rawExecSQL("PRAGMA cipher_default_use_hmac = off;");
}
public void postKey(SQLiteDatabase sqLiteDatabase) {
}
};
SQLiteDatabase database = SQLiteDatabase.openOrCreateDatabase(
databaseFile, "test123", null, hook); // Exception
if (database.isOpen()) {
database.rawExecSQL(String.format(
"ATTACH DATABASE '%s' as plaintext KEY '';",
unencryptedFile.getAbsolutePath()));
database.rawExecSQL("SELECT sqlcipher_export('plaintext');");
database.rawExecSQL("DETACH DATABASE plaintext;");
android.database.sqlite.SQLiteDatabase sqlDB = android.database.sqlite.SQLiteDatabase
.openOrCreateDatabase(unencryptedFile, null);
sqlDB.close();
database.close();
}
databaseFile.delete();
}
You do not need to set cipher_default_use_hmac to off in the preKey event when you attempt to decrypt the database. It is not being disabled when you encrypt the database so an HMAC is being included for every page of the database. Try removing your SQLiteDatabaseHook from the decryption function. Also, consider joining the SQLCipher Mailing List for these type of discussions.