2014-05 << 2014-06 >> 2014-07

2014-06-22 (日)

今日の成果 http://binzume.github.io/secure-chat/public/test/rsa.html

安全なチャットサービス欲しいなと思ってjsの公開鍵暗号化ライブラリ探す.

サーバサイドでの暗号化は,サーバを管理している組織なり人なりを信頼しないといけない時点で不安なので,クライアントサイドで暗号化するしか無い.とくに個人だとVPSとかAWSとか使うので,サーバの物理的な安全性には手出しできない.

本来は,ブラウザがSSLのインターフェイスをjsから使えるように公開するべきだと思うのだけど...

*[JavaScript] JSEncryptを使ってみる

最近はJavaScriptの実行速度もかなり良い感じになってきたので,RSAの鍵生成とかも実用に耐える気がします.

JavaScriptでRSA暗号を扱うために,JSEncryptを使ってみます.MTIライセンス.

https://github.com/travist/jsencrypt

まず,適当に bin/jsencrypt.js を読み込む.

RSAキーを生成してみる.

    var crypt = new JSEncrypt({default_key_size: 1024});
    console.log(crypt.getKey());
    console.log("pub:" +crypt.getPublicKey() );
    console.log("pri:" +crypt.getPrivateKey() );

pem形式で出力される.

getKey()を呼ぶと,鍵がなければ新たに作るらしい.

512ビットだと一瞬だけど1024だと1~2秒待たされる.2048とかだと結構待たされるので,非同期にしたほうが良さげ.getKey()に何か関数渡すと非同期になるっぽい.

キーを生成するときの乱数は,window.crypto + マウスイベントを使っている.まぁ,大丈夫そうに見える.

setKeyで,pemフォーマットの鍵を読み込める.

    var crypt = new JSEncrypt({default_key_size: 1024});
    crypt.setKey(document.getElementById('ras_key').innerText);
    console.log(crypt.getKey());
    console.log("pub:" +crypt.getPublicKey() );

あたりまえだけど,公開鍵を setKey()に渡した場合は,getPrivateKey()は呼べない.

得られるのはPEM形式の鍵なので,SSH形式が欲しい場合はRFC4253を読みつつ,

function hex2b64(h) {
  var len = h.length / 2;
  var buf = new Uint8Array(len);
  for (var i=0; i<len; i++) {
    buf[i] = parseInt(h.substr(i*2,2),16);
  }
  return btoa(String.fromCharCode.apply(null, buf));
}

function int2hex(n) {
     return ("0000000" + n.toString(16)).substr(-8);
}
function sshkey(key) {
    var e = "0"+key.e.toString(16);
    var n = "0"+key.n.toString(16);
    var e = e.substr(e.length%2);
    var n = n.substr(n.length%2);
    var hex = int2hex(7) + stohex("ssh-rsa") + int2hex(e.length/2) + e + int2hex(n.length/2) + n;
    return "ssh-rsa " + hex2b64(hex);
}

console.log(sshkey(crypt.getKey()));

みたいにすればそれっぽくなる.(ちゃんと出来てるかは確認してない)

hex2b64()関数は,JSEncrypt内にあるけど外から呼べないのでコピペしてくるほうが良さげかも?.

自分でパースした公開鍵を読み込むには,RSAKey や BigIntegerを自分では作れないので,setKey(null)で初期化したあと,getKey().setPublic(n,e)でセットするしかなさそう(?).

あとは,encrypt(), decrypt()メソッドが使えるので良しなに.

色々やるにはJSEncrypt.js使うより,JSEncryptが中で使ってるRSAライブラリを直接使うほうが良さそう.

*RSASSA-PSS-SIGNを実装する

RSA使えるの確認して,準備が整ったので署名とかを実装してみる.RSAベースの電子署名で安全だとされているものに,RSASSA-PSSがあります.

RFC 3447 の Section 8と9 を読めば良さそう.

RFC読んでいけば実装できそうなのですが,全体を見渡さないと意味がわからないので調べると,わかり易そうな解説はロシア語のWikipediaが見つかる.見た感じ,わかり易そうなのだけど,そもそも読めない...

ハッシュ関数はSHA1を使うことにして,光成せんせのこれを使う.

http://labs.cybozu.co.jp/blog/mitsunari/2007/07/sha1_1.html

先,長い.

リンク:

http://www.ohdave.com/rsa/

https://github.com/travist/jsencrypt

http://kjur.github.io/jsrsasign/

2014-05 << 2014-06 >> 2014-07