2014年2月26日水曜日

Android4.3 で暗号化処理が変わる・・・?

自力では調査しきれなくて先輩に助けて頂いた内容だけど、今後のためにメモ。


つい先日(2014/2/17)にGalaxyS4のOS4.3アップデートが開始されまして、
「(暗号化して保存している)IDが表示されない(復号化できない)よ!!」
とたくさん報告があがってくるようになりました。

何度も寄り道しながらやっと突き止めた原因はなんと、
4.2から4.3で暗号化に使うプロバイダのデフォルト値が変わっている
というものでした。
OS4.2より前のデフォルトは(ほとんどが)Bouncy Castle ですが、
OS4.3、4.3はAndroidOpenSSLに変わっています。


具体的に何が起こったのかというと、
4.2より前の端末で暗号化 (Bouncy Castle) したものを、
4.3(AndroidOpenSSL) で復号しようとしているので、エラーになるというものでした。

対策としては、暗号化と復号化のプロバイダをちゃんと指定してやれば
デフォルト値を使われることがないので、とりあえず復号化できるようになります。



Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
このように書いてしまうと、デフォルトプロバイダが適応される
               ↓
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "BC");
このように書いてやれば、BC(Bouncy Catsle)を指定できる

AndroidOpenSSLを指定する場合はこう。
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "AndroidOpenSSL");



とりあえずこれで解決なのですが、今までのOSに採用されていた
Bouncy Castleのバージョンを調べてみると、ちょいちょい更新されているみたいなんです。
で、今回のいきなりのデフォルト値変更。
今後またデフォルト値が変わったり、BCがなくなったりする可能性がゼロではないことを考えると、
暗号化ライブラリを自分で用意してやるのが一番安全だろう、という結論になりました。



で。
すでにデフォルト値で暗号化・保存したIDを利用するアプリをリリースしちゃっているので、
次バージョンから内部でBCライブラリ持って復号化しよう!
と思ったんですが、Androidで採用されていたBCはどうやらカスタマイズされたものらしいんです。
おそらくそういう理由で、Android内部処理のBCで暗号化したものを、
拾ってきたBCライブラリで復号してやることはできませんでした・・・。


うーん、、なんだか。。。

2014年2月18日火曜日

Androidで画像をタイル状に敷き詰める

Androidアプリで画像をタイル状に敷き詰める方法。
xmlで指定する方法はたくさん見つかるのに、Javaから画像を指定する方法が少ないのでメモ。

Bitmapの画像データを設定してます。

※残念なことに、2.3系の端末だと縦に繰り返しができなかった

xml
<ImageView
        android:id="@+id/bg_image"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:scaleType="fitXY" />
java
BitmapDrawable bd = new BitmapDrawable(bitmap);    // bitmap に指定したい画像
bd.setTileModeX(Shader.TileMode.REPEAT);
bd.setTileModeY(Shader.TileMode.REPEAT);
((ImageView)findViewById(R.id.bg_image))..setImageDrawable(bd);

Shader.TileMode は REPEATとMIRRORとCLAMPが選べる。




応用編

またまた残念なことに、超高解像度端末に対応する画像を用意してもらえなかったので、
画面サイズいっぱいに引き延ばして縦に繰り返して表示することになった実装が以下。

        // 縦横比を保ったまま横幅いっぱいにリサイズ
        DisplayMetrics metrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metrics);
        float widthScale = (float) metrics.widthPixels / result.getWidth();

        Matrix matrix = new Matrix();
        matrix.postScale(widthScale, widthScale);
        BitmapDrawable repeateImage
            = new BitmapDrawable(Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true));

        // 縦方向に繰り返し表示
        repeateImage.setTileModeY(Shader.TileMode.REPEAT);
        image.setImageDrawable(repeateImage);