2011/04/08

Mailユニットで送受信するメールを暗号化する

Mailユニットに用意されているPOP3クラスを使用すれば、定期的に新着メールをチェックして特定の書式のメールがあったときに本文に記述された命令を実行するというスクリプトを起動しておき、外出先からメールで自宅のPCを操作することも可能です。
しかし、何者かに偽の命令メールで勝手に操作されてしまっては困ります。
命令メールの送信をPC上から行うのであれば、送信時に内容を暗号化するようにすればよいでしょう。

メールを暗号化するには、Cipherユニットを使用し、以下のようにします。
var subject='NILScript:Command';
var addr='test@example.com';
var msg="HELLO";
var key='password';
var opt={cipher:"AES-128-CFB",salt:true,encoding:"utf8"};
try{
    var smtp=new (require('Mail').SMTP)({
        host:'vm01xp',
        user:'test',
        password:'asdf',
        pop:true,
    });
    smtp.send({
        subject:subject,
        from:addr,
        to:addr,
        message: require('Cipher').Cipher.encode(JSON.stringify(
            {time:now().getTime(),text:msg}
        ),key,opt),
    });
}finally{
    free(smtp,cp);
}
Cipherクラスのencode()メソッドを、平文データとパスワード、暗号化オプションを引数にして呼び出すことで、暗号化されたBASE64文字列を取得できます。
これをSMTPオブジェクトのsend()メソッドの引数オブジェクトのmessageメンバに指定して、メール本文として送信します。
なお、BASE64文字列ではなくバイト列へのPointerオブジェクトを返すCipher.encodeToBytes()などのメソッドも用意されています。

受信側では、以下のようにスレッドを生成して定期的にPOP3サーバに接続し、規定の件名のメールがあったときに、本文をCipher.decode()で復号化します。
この例では「Main.notifyIcon.showInfo()」で本文を表示しているだけですが、eval()関数に渡せば、任意のNILScript文を実行させたりもできます。
var subject='NILScript:Command';
var addr='test@example.com';
var msg="HELLO";
var key='password';
var opt={cipher:"AES-128-CFB",salt:true,encoding:"utf8"};
Main.createNotifyIcon();
var last=now().getTime();
Thread.create(function(){
    while(true){
        try{
            var pop3=new (require('Mail').POP3)({
                host:'vm01xp',
                user:'test',
                password:'asdf',
            });
            
            for(let m in pop3.items){
                if(m.subject==subject){
                    var {text,time}=JSON.parse(
                        require('Cipher').Cipher.decode(m.message,key,opt)
                    );
                    if(text && time && (time>last)){
                        Main.notifyIcon.showInfo(text);
                        last=time;
                    }
                    m.remove();
                }
            }
        }catch(e){
            println(e);
        }finally{
            free(pop3);
        }
        sleep(60000);
    }
});

セキュリティを強化するため、単に命令本文を暗号化するのではなく、実際の命令本体と命令の送信日時の2つのメンバからなるオブジェクトのJSON文字列を暗号化して、受信側では前回実行した命令よりも新しい命令でないと実行しないようにしています。
こうしておかないと、メールを傍受した何者かが、後でそのメールを送りつけることで過去に送信された命令を任意のタイミングで再実行できてしまいます。
ハッシュなどによる改竄チェックは行っていないので、出鱈目なBASE64文字列が送りつけられても復号化してJSON文字列の解析まで行われてしまいますが、偶然timeとtextのメンバを持つオブジェクトのJSON文字列として正しくデコード出来てしまう可能性は低いので問題ないでしょう。

0 件のコメント:

コメントを投稿