Android ローカル保存

Android のローカルファイルへの保存(/data/data/パッケージ/file/)への格納/読込み
ファイルの中は暗号化で、Mapのように、Key-Value で管理したいと考えた。。。

ポイントは、ContextWrapper を継承すること。
暗号化するデータを1文の文字列にすること(Key-Value)の文字列化で
JSON形式を採用したこと。
JSONを扱うので、Google GSON を使ったことである。

同期の問題はとりあえず無視して以下のように。。。

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.lang.reflect.Type;
import java.security.Key;
import java.security.spec.AlgorithmParameterSpec;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import android.content.Context;
import android.content.ContextWrapper;
/**
 * ローカルファイル  key-value 管理
 */

public final class PrivateStorage extends ContextWrapper{
   private static PrivateStorage inst;
   private Map<String,String> map;
   private Criptor criptor;        // inner class
   private String filename = "my.dat";
   GsonBuilder gonbuilder;

   private PrivateStorage(Context base){
      super(base);
      gonbuilder = new GsonBuilder();
      criptor = new Criptor();
      map = new HashMap<String,String>();
      this.reload();
   }
   /**
    * インスタンス生成or取得
    */

   public static synchronized PrivateStorage getInstance(Context context){
      if (inst==null){
         inst = new PrivateStorage(base);
      }
      return inst;
   }
   /**
    * キーによる値取得
    */

   public String get(String key){
      return map.get(key);
   }
   /**
    * key-value 格納
    */

   public void put(String key,String value){
      map.put(key,value);
   }
   /**
    * ローカルファイルへの書き込み
    */

   public void commit(){
      try{
      Gson gson = gonbuilder.create();
      OutputStream out = openFileOutput(filename,MODE_PRIVATE);
      out.write(criptor.encrypt(gson.toJson(map)));
      out.close();
      }catch(Exception e){
         throw new RuntimeException(e);
      }
   }
   /**
    * ローカルファイル削除
    */

   public void deleteAll(){
      try{
      deleteFile(filename);
      map.clear();
      }catch(Exception e){
         throw new RuntimeException(e);
      }
   }
   /**
    * @return Key Set
    */

   public Set<String> keySet(){
      return map.keySet();
   }
   /**
    * 再読み込み
    */

   public void reload(){
      map.clear();
      try{
      FileInputStream inputStream = openFileInput(filename);
      int len = inputStream.available();
      if (len > 0){
         BufferedInputStream stream = new BufferedInputStream(inputStream);
         byte b = new byte[len];
         stream.read(b);
         map.clear();
         Gson gson = gonbuilder.create();
         Type type = new TypeToken<Map<String,String>>(){}.getType();
         map = gson.fromJson(criptor.decrypt(b),type);
      }
      inputStream.close();
      }catch(Exception e){
      }
   }

   class Criptor{
      protected String key       = "0123456789abcdef";
      protected String initvecor = "abcdef0123456789";
      private Key secretKey;
      private AlgorithmParameterSpec ivParamSpec;

      public Criptor(){
         byte
 keybyte = key.getBytes();
         this.secretKey = new SecretKeySpec(keybyte,"AES");
         byte vector = initvecor.getBytes();
         this.ivParamSpec = new IvParameterSpec(vector);
      }
      public final byte encrypt(String text){

         try{
         Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
         cipher.init(Cipher.ENCRYPT_MODE,this.secretKey,this.ivParamSpec);
         byte iv = cipher.getIV();
         byte
 enc = cipher.doFinal(text.getBytes());
         byte bs = new byte[iv.length + enc.length];
         System.arraycopy(iv,0,bs,0,iv.length);
         System.arraycopy(enc,0,bs,iv.length,enc.length);
         return bs;
         }catch(Exception e){
            throw new RuntimeException(e);
         }
      }
      public final String decrypt(byte
 data){

         try{
         Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
         cipher.init(Cipher.DECRYPT_MODE,this.secretKey,this.ivParamSpec);
         int blocksize = cipher.getBlockSize();
         return new String(cipher.doFinal(data,blocksize,data.length - blocksize));
         }catch(Exception e){
            throw new RuntimeException(e);
         }
      }
   }
}
===============
改めて、Google GSON が凄いと思ったのは、
JSONの読込、fromJson のメソッドで
Type を指定できることで、総称型を含む Map<String,String> への変換を綺麗に書けることだ。

Type type = new TypeToken<Map<String,String>>(){}.getType();
map = gson.fromJson(criptor.decrypt(b),type);

の部分である。