▼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();
    }
}



−戻る−