Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/StoreEncryptionPassword/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
30 changes: 30 additions & 0 deletions examples/StoreEncryptionPassword/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
apply plugin: 'com.android.application'
apply plugin: 'realm-android'

android {
compileSdkVersion 23
buildToolsVersion "23.0.3"

defaultConfig {
applicationId "realm.io.storeencryptionpassword"
minSdkVersion 23
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
//noinspection GradleDependency
compile 'com.android.support:appcompat-v7:23.1.1'
//noinspection GradleDependency
compile 'com.android.support:design:23.1.1'
}
6 changes: 6 additions & 0 deletions examples/StoreEncryptionPassword/lint.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<lint>
<issue id="AllowBackup" severity="ignore" />
<issue id="IconLauncherShape" severity="ignore" />
<issue id="IconMissingDensityFolder" severity="ignore" />
<issue id="GoogleAppIndexingWarning" severity="ignore" />
</lint>
17 changes: 17 additions & 0 deletions examples/StoreEncryptionPassword/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/Nabil/Library/Android/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# Add any project specific keep options here:

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package realm.io.storeencryptionpassword;

import android.app.Application;
import android.test.ApplicationTestCase;

/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
}
24 changes: 24 additions & 0 deletions examples/StoreEncryptionPassword/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="realm.io.storeencryptionpassword">

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SecretTodoList"/>
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package realm.io.storeencryptionpassword;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import java.util.Arrays;

import io.realm.Realm;
import io.realm.RealmConfiguration;

public class MainActivity extends AppCompatActivity {
public static final int REQ_UNLOCK = 1;

private Button mBtnUnlock;
private Button mBtnLock;
private View mBtnOpen;

private final Store store = new Store(this);

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mBtnUnlock = (Button) findViewById(R.id.btnUnLock);
mBtnLock = (Button) findViewById(R.id.btnLock);

//TODO use this one RealmConfiguration realmConfig = new RealmConfiguration.Builder(this).encryptionKey(realmKey).build();
RealmConfiguration realmConfig = new RealmConfiguration.Builder(MainActivity.this).build();
Realm.setDefaultConfiguration(realmConfig);

mBtnUnlock.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
store.unlockKeyStore(REQ_UNLOCK);
}
});

mBtnLock.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mBtnLock.setEnabled(false);
Toast.makeText(MainActivity.this, "Locking ...", Toast.LENGTH_SHORT).show();
Realm.setDefaultConfiguration(new RealmConfiguration.Builder(MainActivity.this).build());
mBtnUnlock.setEnabled(true);
}
});

//noinspection ConstantConditions
mBtnOpen = findViewById(R.id.btnOpenList);
mBtnOpen.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
goToList();
}
});

mBtnOpen.setEnabled(store.getEncryptedRealmKey() != null && store.containsEncryptionKey());

mBtnUnlock.setEnabled(true);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQ_UNLOCK:
if (store.onUnlockKeyStoreResult(resultCode, data)) {
onKeystoreUnlocked();
}
break;
default:
super.onActivityResult(requestCode, resultCode, data);
break;
}
}

private void onKeystoreUnlocked() {
byte[] encryptedRealmKey = store.getEncryptedRealmKey();
if (encryptedRealmKey == null || !store.containsEncryptionKey()) {
final byte[] realmKey = store.generateKeyForRealm();
store.generateKeyInKeystore();
encryptedRealmKey = store.encryptAndSaveKeyForRealm(realmKey);

final RealmConfiguration realmConfig = new RealmConfiguration.Builder(MainActivity.this)
.encryptionKey(realmKey)
.build();
Arrays.fill(realmKey, (byte) 0);

// create encrypted Realm
Realm.deleteRealm(realmConfig);
Realm.getInstance(realmConfig).close();

mBtnOpen.setEnabled(true);
}

Toast.makeText(MainActivity.this, "Unlocking ...", Toast.LENGTH_SHORT).show();
mBtnUnlock.setEnabled(false);

final byte[] realmKey = store.decryptKeyForRealm(encryptedRealmKey);

RealmConfiguration realmConfig = new RealmConfiguration.Builder(MainActivity.this).encryptionKey(realmKey).build();
Realm.setDefaultConfiguration(realmConfig);

mBtnLock.setEnabled(true);
}

private void goToList () {
//start Todo list
Intent intent = new Intent(MainActivity.this, SecretTodoList.class);
startActivity(intent);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package realm.io.storeencryptionpassword;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListAdapter;
import android.widget.TextView;

import io.realm.OrderedRealmCollection;
import io.realm.RealmBaseAdapter;
import realm.io.storeencryptionpassword.model.TodoItem;

class MyAdapter extends RealmBaseAdapter<TodoItem> implements ListAdapter {

private static class ViewHolder {
TextView name;
}

public MyAdapter(Context context, OrderedRealmCollection<TodoItem> realmResults) {
super(context, realmResults, true);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
convertView = inflater.inflate(android.R.layout.simple_list_item_1, parent, false);
viewHolder = new ViewHolder();
viewHolder.name = (TextView) convertView.findViewById(android.R.id.text1);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}

TodoItem item = adapterData.get(position);
viewHolder.name.setText(item.getName());
return convertView;
}

public OrderedRealmCollection<TodoItem> getAdapterData() {
return adapterData;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package realm.io.storeencryptionpassword;

import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Message;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Toast;

import java.util.Random;

import io.realm.Realm;
import io.realm.RealmResults;
import realm.io.storeencryptionpassword.model.TodoItem;

public class SecretTodoList extends ListActivity {

private Realm realm;
private Random random;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
random = new Random();

realm = getRealm();
if (realm == null) {
finish();
return;
}
RealmResults<TodoItem> todos = realm.where(TodoItem.class).findAll();
setContentView(R.layout.secret_todo);
final MyAdapter adapter = new MyAdapter(this, todos);
getListView().setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) {
TodoItem timeStamp = adapter.getAdapterData().get(i);
realm.beginTransaction();
timeStamp.deleteFromRealm();
realm.commitTransaction();
return true;
}
});

FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
realm.beginTransaction();
TodoItem todoItem = realm.createObject(TodoItem.class);
todoItem.setName("Item " + random.nextInt());
realm.commitTransaction();
}
});

setListAdapter(adapter);
}

private Realm getRealm() {
try {
return Realm.getDefaultInstance();
} catch (IllegalArgumentException e) {
Toast.makeText(this, "Please unlock Realm first.", Toast.LENGTH_SHORT).show();
return null;
}
}

@Override
protected void onDestroy() {
super.onDestroy();
if (realm != null) {
realm.close();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package realm.io.storeencryptionpassword;

import android.content.Context;
import android.content.SharedPreferences;
import android.util.Base64;

public final class SharedPrefUtils {
private static final String PREF_NAME = "realm_key";
private static final String KEY = "iv_and_encrypted_key";

public static void save(Context context, byte[] ivAndEncryptedKey) {
getPreference(context).edit()
.putString(KEY, encode(ivAndEncryptedKey))
.apply();
}

public static byte[] load(Context context) {
final SharedPreferences pref = getPreference(context);

final String ivAndEncryptedKey = pref.getString(KEY, null);
if (ivAndEncryptedKey == null) {
return null;
}

return decode(ivAndEncryptedKey);
}

private static String encode(byte[] data) {
if (data == null) {
return null;
}
return Base64.encodeToString(data, Base64.NO_WRAP);
}

private static byte[] decode(String encodedData) {
if (encodedData == null) {
return null;
}
return Base64.decode(encodedData, Base64.DEFAULT);
}

private static SharedPreferences getPreference(Context context) {
return context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
}
}
Loading