▼MIDP2.0メモ▼
暗号化を行う
端末内部のデータフォルダ(/ms)にデータを保存する際に暗号化を行うプログラムを作る。以下のサンプルではBouncy Castle Crypto APIを利用している。Nokia J2ME MIDP サンプルコード集を参考にしている。
プログラム
CryptoEx.java import javax.microedition.lcdui.*; import javax.microedition.midlet.*; //ファイルの読み書き public class CryptoEx extends MIDlet { static CryptoEx a;//本体 static CryptoBox b;//テキストボックス //コンストラクタ public CryptoEx(){ a=this; b=new CryptoBox(); (Display.getDisplay(this)).setCurrent(b); } //アプリの開始 public void startApp() { } //アプリの一時停止 public void pauseApp() { } //アプリの終了 public void destroyApp(boolean flag) { } }
CryptoBox.java import com.j_phone.io.*; import javax.microedition.io.*; import javax.microedition.lcdui.*; import javax.microedition.midlet.*; import javax.microedition.rms.*; import java.io.*; //暗号化を行う(テキストボックス) public class CryptoBox extends TextBox implements CommandListener { private String password="abcdefgh";//パスワード(8バイト) //コンストラクタ public CryptoBox(){ super("CryptoBox","",255,0); addCommand(new Command("書込",Command.SCREEN,1)); addCommand(new Command("読込",Command.SCREEN,2)); setCommandListener(this); } //ソフトキーイベント public void commandAction(Command c,Displayable s) { byte[] w; //ファイルの書き込み if (c.getPriority()==1){ try { //暗号化 w=MessageCodec.encode(getString().getBytes(),password); //ファイルの書き込み writeFile("file:///ms/Other Documents/test/test.txt",w); } catch (Exception e) { e.printStackTrace(); Dialog.showDialog("エラー", "ファイルの書き込みに失敗しました。", CryptoEx.a,this); } } //ファイルの読み込み if (c.getPriority()==2) { try { //ファイルの読み込み w=readFile("file:///ms/Other Documents/test/test.txt"); //復号化 setString((new String(MessageCodec.decode(w,password))).trim()); } catch (Exception e) { e.printStackTrace(); Dialog.showDialog("エラー", "ファイルの読み込みに失敗しました。", CryptoEx.a,this); } } } //ファイルの書き込み private void writeFile(String name,byte[] data) throws Exception { String folder; StorageConnection c =null; OutputStream out=null; try { //フォルダの生成 folder=name.substring(0,name.lastIndexOf('/')+1); c=(StorageConnection)Connector.open(folder); if (!c.exists()) c.createFolder(); c.close(); //ファイルとの接続 c=(StorageConnection)Connector.open(name); out=c.openOutputStream(); //ファイルへの書き込み out.write(data); //ファイルとの切断 out.close(); c.close(); } catch (Exception e) { e.printStackTrace(); try { if (c !=null) c.close(); if (out!=null) out.close(); } catch (Exception e2) { } throw e; } } //ファイルの読み込み private byte[] readFile(String name) throws Exception { int size; byte[] w=new byte[10240]; StorageConnection c =null; InputStream in =null; ByteArrayOutputStream out=null; try { //ファイルとの接続 c =(StorageConnection)Connector.open(name); in =c.openInputStream(); out=new ByteArrayOutputStream(); //ファイルからの読み込み while (true) { size=in.read(w); if (size<=0) break; out.write(w,0,size); } //ファイルとの切断 out.close(); in.close(); c.close(); return out.toByteArray(); } catch (Exception e) { try { if (c !=null) c.close(); if (in !=null) in.close(); if (out!=null) out.close(); } catch (Exception e2) { } throw e; } } }
MessageCodec.java import org.bouncycastle.crypto.*; import org.bouncycastle.crypto.digests.*; import org.bouncycastle.crypto.engines.*; import org.bouncycastle.crypto.modes.*; import org.bouncycastle.crypto.paddings.*; import org.bouncycastle.crypto.params.*; import java.io.*; //メッセージコーデック class MessageCodec { //対象暗号方式エンジンの生成(DEF,AES) static BlockCipher createEngine() { return new CBCBlockCipher(new DESEngine()); } //暗号化 static byte[] encode(byte[] data,String password) throws Exception { byte[] cipherData; int cipherDataLen; BufferedBlockCipher cipherEngine; ByteArrayOutputStream out=null; try { //暗号の生成 cipherEngine=new PaddedBufferedBlockCipher(createEngine()); cipherEngine.init(true,new KeyParameter(password.getBytes())); cipherData=new byte[cipherEngine.getOutputSize(data.length)]; //暗号化 cipherDataLen=cipherEngine.processBytes( data,0,data.length,cipherData,0); cipherEngine.doFinal(cipherData,cipherDataLen); //ストリームの生成 out=new ByteArrayOutputStream(); writeInt4(out,cipherData.length); out.write(cipherData); out.close(); return out.toByteArray(); } catch (Exception e) { try { if (out!=null) out.close(); } catch (Exception e2) { } throw e; } } //メッセージの復号化 static byte[] decode(byte[] data,String password) throws Exception { byte[] cipherData; int cipherDataLen; byte[] resultData; int resultDataLen; ByteArrayInputStream in=null; try { //ストリームの解析 in=new ByteArrayInputStream(data); cipherDataLen=readInt4(in); cipherData=new byte[cipherDataLen]; cipherData=readByte(in,cipherDataLen); in.close(); //暗号の生成 BufferedBlockCipher cipherEngine= new PaddedBufferedBlockCipher(createEngine()); cipherEngine.init(false,new KeyParameter(password.getBytes())); //復号化 resultData=new byte[cipherEngine.getOutputSize(cipherDataLen)]; resultDataLen=cipherEngine.processBytes( cipherData,0,cipherDataLen,resultData,0); cipherEngine.doFinal(resultData,resultDataLen); return resultData; } catch (Exception e) { try { if (in!=null) in.close(); } catch (Exception e2) { } throw e; } } //1バイト数値を読み込む private static int readInt1(InputStream in) throws Exception { byte[] w=new byte[1]; int size=in.read(w,0,1); if (size<=0) return -1; return (w[0]&0xFF); } //4バイト数値を読み込む private static int readInt4(InputStream in) throws Exception { return readInt1(in)<<24|readInt1(in)<<16|readInt1(in)<<8|readInt1(in); } //バイトデータの読み込み public static byte[] readByte(InputStream in,int len) throws Exception { int size,pos=0; byte[] w=new byte[len]; while (true) { size=in.read(w,pos,len-pos); if (size<0) break; pos+=size; if (pos>=len) break; } return w; } //1バイト数値を書き込む private static void writeInt1(OutputStream out,int num) throws Exception { out.write(num&0xFF); } //4バイト数値を書き込む private static void writeInt4(OutputStream out, int num) throws Exception{ out.write((num>>24)&0xFF); out.write((num>>16)&0xFF); out.write((num>> 8)&0xFF); out.write((num>> 0)&0xFF); } }
Dialog.java import javax.microedition.lcdui.*; import javax.microedition.midlet.*; //ダイアログ public class Dialog extends Form implements CommandListener { public static int BUTTON_CANCEL =0x0002; public static int BUTTON_NO =0x0008; public static int BUTTON_OK =0x0001; public static int BUTTON_YES =0x0004; public static int DIALOG_ERROR =2; public static int DIALOG_INFO =0; public static int DIALOG_WARNING =1; public static int DIALOG_YESNO =3; public static int DIALOG_YESNOCANCEL=4; //GUI private int type; //種別 private int result; //結果 private MIDlet midlet; //本体 private Displayable disp; //戻り先 private StringItem label; //ラベル private Command[] softKey;//ソフトキー //コンストラクタ public Dialog(int type,String title,MIDlet midlet,Displayable disp){ super(title); //GUI this.type =type; this.result=-999; this.midlet=midlet; this.disp =disp; label=new StringItem("",""); append(label); //ソフトキーの追加 setCommandListener(this); softKey=new Command[2]; if (type==DIALOG_INFO || type==DIALOG_WARNING) { softKey[0]=new Command("OK",Command.SCREEN,0); addCommand(softKey[0]); } else if (type==DIALOG_YESNO || type==DIALOG_YESNOCANCEL) { softKey[0]=new Command("はい", Command.SCREEN,0); softKey[1]=new Command("いいえ",Command.SCREEN,1); addCommand(softKey[0]); addCommand(softKey[1]); } } //テキストの指定 public void setText(String text) { label.setText(text); } //表示 public int show() { Display.getDisplay(midlet).setCurrent(this); while (result>=0) { try { Thread.sleep(200); } catch (Exception e) { } } return result; } //ソフトキーイベント public void commandAction(Command c,Displayable disp) { if (type==DIALOG_INFO || type==DIALOG_WARNING) { if (c==softKey[0]) result=BUTTON_OK; Display.getDisplay(midlet).setCurrent(this.disp); } else if (type==DIALOG_YESNO || type==DIALOG_YESNOCANCEL) { if (c==softKey[0]) result=BUTTON_YES; if (c==softKey[1]) result=BUTTON_NO; Display.getDisplay(midlet).setCurrent(this.disp); } } //メッセージダイアログの表示 public static void showDialog(String title,String msg, MIDlet midlet,Displayable disp){ Dialog dlg=new Dialog(Dialog.DIALOG_INFO,title,midlet,disp); dlg.setText(msg); dlg.show(); } //Yes/Noダイアログの表示 public static int showYNDialog(String title,String msg, MIDlet midlet,Displayable disp){ Dialog dlg=new Dialog(Dialog.DIALOG_YESNO,title,midlet,disp); dlg.setText(msg); return dlg.show(); } }