端末下部のハードウェアキーが、4.0から標準のタッチパネル上のソフトウェアキー置き換わった端末のチェックとメモ
注)
ホームページ上の写真から判断しているので間違えがあるかもしれません。
スペック一覧は他のサイトでまとめられているのでそっちを確認してください。
2012年5月24日木曜日
2011年12月20日火曜日
SQLite暗号化OSS「SQLCipher for Android」を使ってみた。
こんにちは@katsummyです。
Android Advent Calendar 2011 の参加への投稿となります。
Android Advent Calenderについてはこちらを参照下さい。
使用するにはgithubからダウンロードしましすが、ソースコードが不要の場合、
https://github.com/guardianproject/android-database-sqlcipher/tree/master/dist/SQLCipherForAndroid-SDK
からダウンロードすれば良いと思います。
必要な
SQLCipherをプロジェクトに設定する手順
1) libs フォルダをプロジェクトにコピーします。
- commons-codec.jar
- guava-r09.jar
- sqlcipher.jar
+ armeabi
- libdatabase_sqlcipher.so
- libsqlcipher_android.so
- libstlport_shared.so
※ ターゲットが2.2以下の場合、 assets フォルダもプロジェクトにコピーします。
+ assets
- icudt44l.zip
2) ソースコードの修正
a) importするパッケージはSQLiteをSQLCipherに変更します。
import android.database
-->>
import info.guardianproject.database
b) 初期処理としてライブラリのロードを行います。
SQLiteDatabase.loadLibs(context);
c) データベースをオープンする時にパスワードを指定します。
SQLiteOpenHelper.getWritableDatabase("thisismysecret"):
SQLiteOpenHelper.getReadableDatabase("thisismysecret"):
後は、SQLiteと同じ記述となります。
サンプルソース
ダンプ
※Twitterとデベロッパー名が違いますのであしからず^^
Android Advent Calendar 2011 の参加への投稿となります。
Android Advent Calenderについてはこちらを参照下さい。
勢いで参加したものの、先の方々がガチな技術や面白いネタの投稿をされてるのを見て恐縮してます。
。。゛(ノ><)ノ ヒィ
初心者向けな内容です。過度の期待はしないで下さい。
初心者向けな内容です。過度の期待はしないで下さい。
ネタは敷居高そうだし、技術的な投稿の内容を考えておりましたが、
あるところでAndroidの端末内のデータの暗号化について話題が上がったので、
その際に考えてた内容とSQLiteの暗号化について記載したいと思います。
Android 3.x 以降では、ストレージ暗号化機能を使用することができます。
SDカードや内蔵ストレージをすべて暗号化できますので安全性は高くなります。
その端末が専用に使用しているのであれば、有効では無いかと思います。しかし、他の用途でも使用している場合、ひとつのアプリのためだけに、全体を暗号化するのはどうかなと思います。
そもそも、Android 2.3.x 以前の端末では使用できません。
アプリ個別に管理しているファイルを暗号化する。
端末レベルで暗号化するより、比較的導入が容易かと思います。
Androidで、データを管理する方法としては、
・ファイル (.TXT .CSV .XML etc...)
・プリファレンス(XML)
・SQLite
これらのファイルを暗号化します。
ファイルの暗号化は、AES/DES/RSA暗号などを用いれば良いと思います。コードサンプルはググれば多く見つかると思うので記載はか割愛します。
プリファレンス(XML)は、それ自信は暗号化されませんので、中に持つ値を暗号化する必要があります。
SQLiteは、暗号化機能を持っていないため、中のレコード自体は暗号化されていません。バイナリー化もされていない(?)ようなので、ダンプをとると容易に中身を参照することができてしまいます。レコードに格納する値を暗号化する方法もありますが、SQLのクエリーやソートが使用できなくなってしまいます。
SQLiteを暗号化するオープンソース・ソフトウェアにSQLCipherがあります。
CやPHP、iPhoneで使用することができてましたが、Android版も11月末に正式版?( v1 FINAL)がリリースされました。
Public Project: https://github.com/guardianproject/android-database-sqlcipher
使用するにはgithubからダウンロードしましすが、ソースコードが不要の場合、
https://github.com/guardianproject/android-database-sqlcipher/tree/master/dist/SQLCipherForAndroid-SDK
からダウンロードすれば良いと思います。
必要な
SQLCipherをプロジェクトに設定する手順
1) libs フォルダをプロジェクトにコピーします。
- commons-codec.jar
- guava-r09.jar
- sqlcipher.jar
+ armeabi
- libdatabase_sqlcipher.so
- libsqlcipher_android.so
- libstlport_shared.so
※ ターゲットが2.2以下の場合、 assets フォルダもプロジェクトにコピーします。
+ assets
- icudt44l.zip
2) ソースコードの修正
a) importするパッケージはSQLiteをSQLCipherに変更します。
import android.database
-->>
import info.guardianproject.database
b) 初期処理としてライブラリのロードを行います。
SQLiteDatabase.loadLibs(context);
c) データベースをオープンする時にパスワードを指定します。
SQLiteOpenHelper.getWritableDatabase("thisismysecret"):
SQLiteOpenHelper.getReadableDatabase("thisismysecret"):
後は、SQLiteと同じ記述となります。
サンプルソース
import android.database.Cursor;
import info.guardianproject.database.sqlcipher.SQLiteDatabase;
import android.app.Activity;
import android.content.ContentValues;
import android.os.Bundle;
import android.util.Log;
public class SQLDemoActivity extends Activity {
EventDataSQLHelper mSQLHelper;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// SQLCipherライブラリのイニシャルロード
SQLiteDatabase.loadLibs(this);
String password = "foo123";
mSQLHelper = new EventDataSQLHelper(this);
// パスワードを指定して書き込み可能なデータベースを開く
SQLiteDatabase db = mSQLHelper.getWritableDatabase(password);
// レコードのインサート
for (int i = 1; i < 10; i++) {
addEvent("こんにちは Android イベント: " + i, db);
}
db.close();
// パスワードを指定して読み込み可能なデータベースを開く
db = mSQLHelper.getReadableDatabase(password);
// クエリー
Cursor cursor = db.query(EventDataSQLHelper.TABLE, null, null, null, null, null, null);
startManagingCursor(cursor);
// レコードの読み込み
StringBuilder ret = new StringBuilder("Saved Events:\n\n");
while (cursor.moveToNext()) {
long id = cursor.getLong(0);
long time = cursor.getLong(1);
String title = cursor.getString(2);
ret.append(id + ": " + time + ": " + title + "\n");
}
Log.i("sqldemo", ret.toString());
db.close();
}
@Override
public void onDestroy() {
super.onDestroy();
mSQLHelper.close();
}
private void addEvent(String title, SQLiteDatabase db) {
ContentValues values = new ContentValues();
values.put(EventDataSQLHelper.TIME, System.currentTimeMillis());
values.put(EventDataSQLHelper.TITLE, title);
db.insert(EventDataSQLHelper.TABLE, null, values);
}
}
import info.guardianproject.database.sqlcipher.SQLiteDatabase;
import info.guardianproject.database.sqlcipher.SQLiteOpenHelper;
import android.content.Context;
import android.provider.BaseColumns;
import android.util.Log;
// SQLiteOpenHelper
public class EventDataSQLHelper extends SQLiteOpenHelper {
// データベス名
private static final String DATABASE_NAME = "events.db";
private static final int DATABASE_VERSION = 1;
// テーブル名
public static final String TABLE = "events";
// カラム
public static final String TIME = "time";
public static final String TITLE = "title";
// コンストラクタ
public EventDataSQLHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
String sql = "create table " + TABLE + "( "
+ BaseColumns._ID + " integer primary key autoincrement, "
+ TIME + " integer, "
+ TITLE + " text not null);";
Log.d("EventsData", "onCreate: " + sql);
db.execSQL(sql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
ダンプ
$ hexdump -C events.db
なお、サンプルコードは、パスワードをソースコードに記述してますが、
端末を識別する情報やGoogleアカウント情報など一意となる情報から、
生成した方が良いと思います。
※ IMEI(端末識別番号)、IMSI(加入者識別番号)、ICCID(SIMカード固有番号)、Android IDの文字列を組み合わせて、ハッシュ化するとか〜。
SQLiteのデータベースは通常/data/data/package/databasesに作成されるためアプリ以外のユーザ権限で取得することはできませんがルートユーザでは可能になります。
また、データベースの保管先は、SDCardに指定することも可能です。
Rooted端末対策として、保管をSDCard指定する際には、SQLCipherを利用してみてはどうかなと思います。
ライセンス
同梱されているLICENSEファイルには、Apache License Version 2.0とされていました。
別にSQLCIPHER_LICENSEファイルにも再配布や免責事項に付いて記載がありますので確認しておいた方がよいと思います。
でわでわ。
- SQLite
00000000 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 |SQLite format 3.|
...
00000e30 00 00 00 00 00 31 09 04 00 05 5b 01 34 42 1d 75 |.....1....[.4B.u|
00000e40 20 e3 81 93 e3 82 93 e3 81 ab e3 81 a1 e3 81 af | ...............|
00000e50 20 41 6e 64 72 6f 69 64 20 e3 82 a4 e3 83 99 e3 | Android .......|
00000e60 83 b3 e3 83 88 3a 20 39 31 08 04 00 05 5b 01 34 |.....: 91....[.4|
00000e70 42 1d 74 ec e3 81 93 e3 82 93 e3 81 ab e3 81 a1 |B.t.............|
00000e80 e3 81 af 20 41 6e 64 72 6f 69 64 20 e3 82 a4 e3 |... Android ....|
00000e90 83 99 e3 83 b3 e3 83 88 3a 20 38 31 07 04 00 05 |........: 81....|
00000ea0 5b 01 34 42 1d 74 d4 e3 81 93 e3 82 93 e3 81 ab |[.4B.t..........|
00000eb0 e3 81 a1 e3 81 af 20 41 6e 64 72 6f 69 64 20 e3 |...... Android .|
…
- SQLCipher
00000000 5a f7 b6 fa 3e 78 f2 9b 10 71 bc cd 64 e8 f4 01 |Z...>x...q..d...|
00000010 11 7c 48 1b 3f d9 15 e3 70 01 68 c0 d0 7c be 0b |.|H.?...p.h..|..|
00000020 af 55 b5 95 7b a3 d2 83 90 61 31 0a 83 ce 52 13 |.U..{....a1...R.|
00000030 0a ac 02 a3 39 ad ec e2 92 65 3f 01 c6 d6 5d 97 |....9....e?...].|
00000040 b0 d0 f3 a3 5a c2 3b 1d 58 b4 d2 41 2a d0 bf 39 |....Z.;.X..A*..9|
00000050 3c 96 88 8b 66 ff d1 de 73 c5 c8 2e d6 52 6b 7d |<...f...s....Rk}|
00000060 6c 7e f9 41 bb 9e 00 bb 3e d6 2e 9a dc 07 da 0f |l~.A....>.......|
00000070 fe 0e 14 38 63 34 01 3e e7 70 c4 4c 20 da c5 d5 |...8c4.>.p.L ...|
…
暗号化されているのが分かると思います。なお、サンプルコードは、パスワードをソースコードに記述してますが、
端末を識別する情報やGoogleアカウント情報など一意となる情報から、
生成した方が良いと思います。
※ IMEI(端末識別番号)、IMSI(加入者識別番号)、ICCID(SIMカード固有番号)、Android IDの文字列を組み合わせて、ハッシュ化するとか〜。
SQLiteのデータベースは通常/data/data/package/databasesに作成されるためアプリ以外のユーザ権限で取得することはできませんがルートユーザでは可能になります。
また、データベースの保管先は、SDCardに指定することも可能です。
Rooted端末対策として、保管をSDCard指定する際には、SQLCipherを利用してみてはどうかなと思います。
ライセンス
同梱されているLICENSEファイルには、Apache License Version 2.0とされていました。
別にSQLCIPHER_LICENSEファイルにも再配布や免責事項に付いて記載がありますので確認しておいた方がよいと思います。
でわでわ。
2011年10月22日土曜日
Conversion to Dalvik format failed with error 1
ADT14 にアップデートしたら「Conversion to Dalvik format failed with error 1」でまくったので、その時の対応メモ。
原因は参照ライブラリでした。
プロジェクトツリーに、参照しているライブラリのソースパスが追加されてました。
プロジェクトのプロパティでLibraryに追加しています。
これは問題ありません。
Java Build Path に参照ライブラリのパスが追加されていました。
こいつが悪さしてるっぽいので削除します。
プロジェクトツリーに、参照しているライブラリのソースパスが残っているので、
これも削除してしまいました。
これでエラーが出なくなりました。
ActionBarSherlock の Issues にも対応方法が上がってました。
#79: not compatible with Android SDK Tools 14 - Issues - JakeWharton/ActionBarSherlock - GitHub https://github.com/JakeWharton/ActionBarSherlock/issues/79#issuecomment-2464701
2011年10月13日木曜日
List of libraries for android
[覚書] Android用各種ライブラリ一覧
- UI (Front)
- Compatibility Package
- iosched - Google I/O App for Android
- Look at the schedule
- Look through detailed session and speaker info
- Look through info about companies in the Developer Sandbox
- Star sessions and Sandbox companies
- Get the current buzz on I/O via real time search stream
- Guide yourself using the conference map
- Create and manage notes with a third-party intent integration
- ActionBarSherlock | JakeWharton/ActionBarSherlock
- ActionBarSherlock is an extension of the compatibility library designed to facilitate the use of the action bar design pattern across all versions of Android with a single API.
- JakeWharton/Android-ViewPagerIndicator
- Paging indicator widget compatible with the ViewPager from the Compatibility Library and ActionBarSherlock. Ported and enhanced from Patrik Åkerfeldt's ViewFlow.
- JakeWharton/Android-DirectionalViewPager
- Implementation of the compatibility library ViewPager class that supports paging both vertically and horizontally.
- GreenDroid | cyrilmottier/GreenDroid
- GreenDroid is a development library for the Android platform. It makes UI developments easier and consistent through your applications.
- Back
- Twitter4J
- A Java library for the Twitter API
- Android ROME Feed Reader
- ROME is an open source Java tool for parsing, generating, and publishing RSS and Atom feeds. Android ROME Feed Reader is a repackaging of ROME so that it works on Android devices.
- Spring Android
- A Rest Client for Android
- Auth support for accessing secure APIs
- Graph
- AChartEngine
- AChartEngine is a charting library for Android applications. It currently supports the following chart types:
- line chart / area chart / scatter chart / time chart / bar chart / pie chart / bubble chart / doughnut chart / range (high-low) bar chart / dial chart / gauge / combined (any combination of line, cubic line, scatter, bar, range bar, bubble) chart / cubic line chart
- AndroidPlot
- AndroidPlot is a pure Java API for creating dynamic and static charts within your Android application. AndroidPlot currently supports the following types of charts:
- Line charts / Scatter charts / Bar charts / Step charts
- ChartDroid
- ChartDroid is an Intent-based "library application" for static chart and graph generation on Android. It can graph/plot/display numerical data in many representations.
2011年9月28日水曜日
Android からApp EngineのフォームにPOSTする
「Google アカウントを使用して Google App Engine の認証を行う」の続きです。
Google App Engine のスタートガイドで作成しているゲストブックのフォームにポストするサンプルです。
以前のソースはActivityクラスにコードを記載してましたが、もう少し汎用的なクラスを作成しました。
GoogleServiceAuthenticator
GoogleServiceAuthExampleActivity
フルプロジェクトはgithubに上げました。
http://github.com/granoeste/GoogleServiceAuthExample
Google App Engine のスタートガイドで作成しているゲストブックのフォームにポストするサンプルです。
- App Engine for Java の概要 - Google App Engine - Google Code
- プロジェクトの作成 - Google App Engine - Google Code
以前のソースはActivityクラスにコードを記載してましたが、もう少し汎用的なクラスを作成しました。
GoogleServiceAuthenticator
- コンストラクタにはContextを指定してます。
- getGoogleAccounts() で、アカウントリストを取得できます。
- execute()で、認証を実行してます。
- 引数 accountには、リストから選ばられた一意のアカウントを指定します。typeは、Googleのアカウントタイプ(AppEngineの場合は"ah")。postExecuteCallbackには、認証終了後にコールしたいクラスを指定します。
- AccountManagerのgetAuthTokenを呼び出します。
- GetAuthTokenCallbackをcallbackに指定してます。
- GetAuthTokenCallbackのrun()の認証処理の実態のgetAuthToken()を呼び出してます。
- getAuthToken()では、認証処理を失敗時のリトライのためにループさせてます。
- getLoginUrl()を呼び出して、アプリのUrlを作成。
- https://yourappl.appspot.com/_ah/login?continue=http://localhost/&auth=[authToken]
- authTokenは、AccountManagerから取得した文字列を指定してます。
- urlを読んで、レスポンスを取得。
- 取得したレスポンスが500の場合、AccountManagerのキャッシュからauthTokenを削除して、リトライをさせてます。
- 認証に成功したら、Cookieから、ASCID または、SACSIDを取得します。
- httpsで認証した場合は、SACSID、httpの場合は、ASCIDが取得できます。
- その後、postExecuteCallbackを実行させてます。
- postExecuteCallback内で、App Engineにアクセスするときに、Http Headerの CookieにASCID/SACSIDをセットする必要があります。
Activityの実装例
GoogleServiceAuthExampleActivity
フルプロジェクトはgithubに上げました。
http://github.com/granoeste/GoogleServiceAuthExample
Google アカウントを使用して Google App Engine の認証を行う
AccountManager から、端末に登録されているGoogleアカウントを取得して、
そのアカウントでGoogle App Engineの認証を行う簡単なサンプルです。
AndroidManifest.xmlは、次のパーミッションを指定します。
AccountManagerから、AccountsByTypeに"com.google"を指定して、Googleアカウントの一覧を取得します。
それをリスト表示してます。
※リストは簡易的に標準のレイアウトを使用してます。
リストで選んだAccountでGoogle App Engineの認証を行ってます。
AccountManager#getAuthToken() の 第2引数に AuthTokenTypeを指定します。
"ah"がGoogle App EngineのAuthTokenTypeとなってます。
AuthTokenTypeについては、次のサイトが参考になると思います。
Account Managerについて - adsaria mood
Google Data APIs Frequently Asked Questions - Google Base Data API - Google Code
認証画面が表示されます。
ユーザがAllowを選択するとauthTokenを取得することができます。
そのアカウントでGoogle App Engineの認証を行う簡単なサンプルです。
AndroidManifest.xmlは、次のパーミッションを指定します。
- android.permission.GET_ACCOUNTS
- android.permission.MANAGE_ACCOUNTS
- android.permission.USE_CREDENTIALS
Activity
AccountManagerから、AccountsByTypeに"com.google"を指定して、Googleアカウントの一覧を取得します。
それをリスト表示してます。
※リストは簡易的に標準のレイアウトを使用してます。
public class AccountList extends ListActivity {
protected AccountManager accountManager;
protected Intent intent;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
accountManager = AccountManager.get(getApplicationContext());
Account[] accounts = accountManager.getAccountsByType("com.google");
this.setListAdapter(new ArrayAdapter(
this, android.R.layout.simple_list_item_1, accounts));
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Account account = (Account)getListView().getItemAtPosition(position);
AccountManagerFuture accountManagerFuture =
accountManager.getAuthToken(account, "ah", null, this, null, null);
Bundle authTokenBundle;
try {
authTokenBundle = accountManagerFuture.getResult();
String authToken = authTokenBundle.get(
AccountManager.KEY_AUTHTOKEN).toString();
Log.i(TAG,"authToken:"+authToken);
} catch (OperationCanceledException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (AuthenticatorException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
リストで選んだAccountでGoogle App Engineの認証を行ってます。
AccountManager#getAuthToken() の 第2引数に AuthTokenTypeを指定します。
"ah"がGoogle App EngineのAuthTokenTypeとなってます。
AuthTokenTypeについては、次のサイトが参考になると思います。
Account Managerについて - adsaria mood
Google Data APIs Frequently Asked Questions - Google Base Data API - Google Code
認証画面が表示されます。
ユーザがAllowを選択するとauthTokenを取得することができます。
2011年9月19日月曜日
外部メディア (SDカード) へのインストール不可にする
Android 2.2.x (Froyo) から、アプリケーションは内蔵ストレージ(携帯端末)だけでなく、外部メディア(SDカード) にインストールさせることが可能になってます。
端末によっては、内蔵ストレージは、通常数百MBとサイズが小さく、プリインストールのアプリケーションなどで、ユーザが使用できるサイズ100MB以下の場合があります。
その場合、ゲームなどサイズの大きいアプリケーションは、2GB-32GBとサイズの大きい外部メディアにインストールさせることで、内蔵ストレージの消費を抑えることができます。
しかし、常に常駐するタイプのものや、ホームに配置するウィジェットの場合、外部メディアにインストールされてしまうと問題が発生します。
外部メディアは、端末から取り外したり、USBでパソコンと接続した場合にアンマウントされてしまいます。アンマウントされてしまうと、端末から外部メディアが認識できなくなり、その上で動作していたアプリケーションも停止することなります。
この問題を防ぐために、アプリケーションの開発時に外部メディアに移動できないように設定することが可能です。
AndroidManifest.xmlの<manifest>タグに、android:installLocation属性を定義します。
"internalOnly"と定義することで、外部メディアへの移動が出来なくなります。
android:installLocation属性の詳細はDev Guideを参照してください。
<manifest> | Android Developers
android:installLocation属性には、他に"auto"と"preferExternal"が設定することが可能です。
auto - アプリケーションは、外部ストレージにインストールすることができますが、システムはデフォルトで内部ストレージにアプリケーションをインストールします。内部ストレージがいっぱいになっている場合、システムは外部ストレージにインストールします。
preferExternal - アプリケーションは、外部ストレージ(SDカード)にインストールされることを優先します。
Android 2.1.x (Eclar) までは、外部メディアへのインストールができないため、android:installLocation属性はありませんので、通常のインストール先は内蔵ストレージとなります。
Android 2.2.x (Froyo)でも、android:installLocation属性を設定していない場合、通常のインストール先は内蔵ストレージとなります。
通常の端末の状態では、問題はありませんが、アプリケーションの通常のインストール先を内蔵ストレージから外部ストレージに変更することが出来てしまいます。
USB接続して、次のコマンドを実行します。
adb shell pm setInstallLocation 2
コマンドを実行することで、アプリケーションの通常のインストール先を外部メディアに変更します。
このような場合、android:installLocation属性に"internalOnly"を指定してない場合、外部メディアにインストールされてしまうことになります。
ウィジェットの場合、外部メディアにインストールされると、ホーム画面でウィジェットの一覧に表示されなくなります。
なので、
ウィジェットや常駐アプリは android:installLocation属性に "internalOnly" を指定しましょう!!
Android 2.1 以下を対象とするアプリケーションの場合、プロジェクトのビルドターゲットにAndroid 2.2 以上を指定して、AndroidManifest.xmlにuses-sdkタグでターゲットバージョンを指定します。
登録:
投稿 (Atom)





