sqlcipher_export didn't export my tables - android

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");

Related

View/edit SQLite database on Android emulator

I am developing an app (that uses SQLite) in Android Studio 2.3 on Mac OS and would like to view the SQLite database, but can't seem to find the sqlite file. Where are the AVM files and specifically the sqlite file?
I found the AVD folder
/Users/<my name>/.android/avd/Pixel_XL_API_26.avd but can't find the user generated data. Any suggestions?
You could always include methods to find out information about the database.
For example you can query the sqlite_master table e.g. :-
Cursor csr = db.query("sqlite_master",null,null,null,null,null,null);
which equates to :-
SELECT * FROM sqlite_master
The are PRAGMA statments that allow you to interrogate/change internals PRAGMA Statements.
Note use rawQuery to obtain information into a cursor but use execSQL to make changes e.g. to set and get user_version (Database Version) respectively:-
db.execSQL("PRAGMA user_version=" + Integer.toString(version));
Cursor csr = db.rawQuery("PRAGMA user_version",null);
You could also look at the data, output to the log, in the tables with something based upon (where tablename would be changed to the appropriate tablename) :-
Cursor csr = db.query("tablename",null,null,null,null,null,null);
String logdata;
while (csr.moveToNext()) {
Log.d("DBINFO","Row " + csr.getPosition());
logdata = "";
for (int i =0; i < csr.getColumnCount(); i++) {
String val;
try {
val = csr.getString(i);
}
catch (Exception e) {
val = "unobtainable";
}
logdata = logdata + "\t\nColumn Name=" +
csr.getColumnName(i) +
" Value=" + val;
}
Log.d("DBINFO",logdata);
}
csr.close();
Note! this only uses getString so will not properly represent some values e.g. double's and floats, if a BLOB then the value will be unobtainable.

connect to sqlite in android using connection string

I am so new and new in android , i have a big problem with it, i create an app that needs to connect to database .so i create a database using sqllite expert pro as you can see here :
CREATE TABLE [user](
[name] tEXT,
[id] INT PRIMARY KEY);
My database name is a .i want to read the value from the user table as you can see here in my code :
SQLiteDatabase mydatabase = openOrCreateDatabase("a",MODE_PRIVATE,null);
Cursor resultSet = mydatabase.rawQuery("Select * from user",null);
resultSet.moveToFirst();
String username = resultSet.getString(1);
String password = resultSet.getString(2);
TextView tv = (TextView) findViewById(R.id.editText1);
tv.setText("Text is: " + username + password);
but it doesn't work ,should i add connection string to my code ,or should i import the database into my project,because the database is in my workspace folder.
I use this code to create a test database inside android ,but it doesn't work again?
SQLiteDatabase mydatabase = openOrCreateDatabase("ali",MODE_PRIVATE,null);
mydatabase.execSQL("CREATE TABLE IF NOT EXISTS TutorialsPoint(Username VARCHAR,Password VARCHAR);");
mydatabase.execSQL("INSERT INTO TutorialsPoint VALUES('admin','admin');");
Cursor resultSet = mydatabase.rawQuery("Select * from TutorialsPoint",null);
resultSet.moveToFirst();
String username = resultSet.getString(1);
String password = resultSet.getString(2);
Your database needs to be copied to the phone's internal storage first. You can do it manually or with the help of this library Android SqliteAsset Helper
Follow the right method for creating database in android using codes:
Create a class that extends SqliteOpenHelper.
public class DbOpener extends SqliteOpenHelper {
DbOpener(Context c){
super(c, 1, "a", null, 1); //where "a" is the database name
}
public void onCreate (SqliteDatabase db){
db.execSQL("CREATE TABLE TutorialsPoint (Username VARCHAR, Password VARCHAR);");
}
}
Then in your activity use it as follows:
DbOpener opener = new DbOpener(this);
SqliteDatabase myDatabase = opener.getWritableDatabase();
//Now you can perform all your queries (including insertions) using the myDatabase object
First, you should change your database name to a readable one like "mydata.db"
Second, there is no need for connection string on using SQLite in Android like the usual ways we do with accessing database from Java code.
You need to access database by using SQLiteOpenHelper. Tutorial from Android SQLite database and content provider. Try to get the feel with Android and SQLite from the tutorial.
Then, after you've mastering the concept and know the how, you can use your predefined database by utilizing Android SQLiteAssetHelper

Decrypting the sqlcipher encrypted database on windows

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();

Android + Sqlite : Table creation sql has no effect

I am trying to create a simple android application which creates a database using SQLiteDatabase (not using SQLiteOpenHelper). So the database creation and the table creation sql executes successfully without any issues/exceptions.
Now the issue is when I reopen the same database, the earlier table created does not exist!!
I am checking the existence of the table using the following code :
Cursor cursor = db.rawQuery("select DISTINCT tbl_name from sqlite_master where tbl_name = '"+ sqlQueryString +"'", null);
if(cursor!=null) {
if(cursor.getCount() == 0) {
//error handling code here
}
cursor.close();
}
Obviously am ending in the if(cursor.getCount() == 0) condition.
I pulled the db file and also checked with a sqlite viewer on the pc, the table created earlier simply does not exist.
So my question is how do I verify that my create table query has created the table properly?
Adding requested information:
Create table ExampleTable ( ROWID integer primary key autoincrement , FIRSTNAME text , LASTNAME text ) ;
Adding the android code the execute the above query:
db.beginTransaction();
db.execSQL(sqlQueryString);
db.endTransaction();
You need to call db.setTransactionSuccessful() before you end the transaction, or else the operation is assumed to have failed and the transaction is rolled back.
Typical transaction usage is:
db.beginTransaction();
try {
// execute DB queries here
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
Credit to njzk2 for first mentioning the solution in a comment.

In android, sqlite text field is retrieved using getBlob, not getString

I am attempting to make an android application with a pre-populated database. When learning about how to go about this, I came across this article http://www.reigndesign.com/blog/using-your-own-sqlite-database-in-android-applications/ , which basically takes an existing sqlite database and streams it into the correct location on the android device. The data I had was dealt with in ruby, so I grabbed the sqlite gem, and created a database like so.
db = SQLite3::Database.new( "cards.db" )
db.execute("CREATE TABLE android_metadata (locale TEXT DEFAULT \"en_US\")")
db.execute("INSERT INTO android_metadata VALUES (\"en_US\")")
db.execute("
CREATE TABLE #{##card_table_name} (
_id INTEGER PRIMARY KEY,
name TEXT UNIQUE
)")
cards.each do |card|
begin
db.execute("INSERT INTO #{#card_table_name} (_id, name) VALUES (?, ?)",
card.id, card.name)
rescue => e
puts "#{card.name} (#{card.id})"
puts e
end
end
When I go into the database, both the one made from the ruby script, and the one from using adb and examining the database on the emulator, I get this for the schema.
sqlite> .schema
CREATE TABLE Cards (
_id INTEGER PRIMARY KEY,
name TEXT UNIQUE
);
However, when I pull the data back out in my application, getString can't deal with the name, specifically, this block gets into the exception clause, and prints the name successfully within that block
Cursor cursor = myDataBase.query("Cards", new String[] {"_id", "name"}, null, null, null, null, null, "5");
while (cursor.moveToNext()) {
try {
cards.add(new Card(cursor.getInt(0), new String(cursor.getString(1))));
} catch (Exception e) {
byte[] blob = cursor.getBlob(1);
String translated = new String(blob);
Log.i(MagicApp.TAG, "DB retrival blew up on " + cursor.getInt(0) + ", " + blob + " : " + translated);
e.printStackTrace();
}
}
I can deal with that, but it seems like I shouldn't have to do that. Any one else encountered this, or know what I'm doing wrong?

Categories

Resources