fizzbuzz
条件分岐のやり方を忘れたネットワーク園児がなんかfizzbuzz書いてみました。ifと剰余演算子を使わない例。(http://bugrammer.g.hatena.ne.jp/nisemono_san/20111008 を見た)
#!ruby class FizzBuzzer @@max = 1000 def self.define_my_methods num, word num.step(@@max, num) {|n| define_method "to_#{n}" do word end } end def method_missing method, *args, &block method.to_s =~ /^to_(\d+)$/ return $1 if $1 super end define_my_methods 3, :fizz define_my_methods 5, :buzz define_my_methods 15, :fizzbuzz end (1..100).each do |n| puts FizzBuzzer.new.send("to_#{n}") end
Rubyはオブジェクト指向言語なので、オブジェクト指向で書けばこんな感じになると思います。上記だと一応1000までは対応しますね。
追記:よく見たらif文使ってた…orz if $1; super はなくてもfizzbuzzに関しては動くので、上記コードは簡単にifなしにできますが、method_missingでsuperしないのはとってもお行儀が悪いのでおすすめできません。
#!ruby def fizzbuzz x begin x / (x % 15) rescue return :fizzbuzz end begin x / (x % 3) rescue return :fizz end begin x / (x % 5) rescue return :buzz end x end (1..100).each do |x| puts fizzbuzz x end
こっちは剰余演算子は使う場合。とっても素直。
ECCの動作の現状
Apache22
Oops, no RSA or DSA server certificate found for 'YOUR.DOMAIN:0'?!
Holy shit! Apache2.2 doesn't support EC-based Server-Certificate yet!
http://www.jnsa.org/seminar/pki-day/2010/data/4_urushima.pdf
によると、ECDH/ECDSAの認証がApache2.3になるまで完成していないとのこと。
http://www.takeyellow.com/apachemirror//httpd/CHANGES_2.3
公式情報で見れば、2.3.3でECC鍵及びECDHのサポートを開始したとある。
http://mail-archives.apache.org/mod_mbox/httpd-dev/201012.mbox/%3CA418DE49-617A-45E2-9F6E-68642611773B@apache.org%3E
2010/12/22に2.3.10-alphaが出て、2011/3/7に2.3.11-betaが出た。2.4.0の正式版が出るのは2011年初頭とされていたけど、2.1-alphaから2.2が出るまでに9ヶ月かかったらしいし、まだ若干先のことになりそうだ。
Dovecot 2.0.9
起動まではOK。
Windows上のThunderbird3.1.9では ssl_error_no_cypher_overlap と怒られる。Outlook でも受信できず。サーバ上でのエラーはno shared cipherとのこと。もちょっと確認したい。
openssl s_clientで確認。ECDSA鍵ではSSLv3通信成立せず、RSA鍵に変えないと通信不能だった。どうやら未対応。
OpenSSL1.0.0で楕円曲線志向なサーバ証明書を作る
楕円曲線を用いた暗号方式でサーバ証明書を作ろう、というお話。
ユーザが証明書署名要求を作るまで
# openssl ecparam -genkey -name prime256v1 -out server.pem # openssl ec -in server.pem -out server.des.pem -des
先ほどは知らなかったので書き損ねたけれど、openssl1.0.0ではecサブコマンドからec鍵対をDES暗号化することが可能。passphraseを使用/記述できる環境で使うのであれば暗号化しておいた方が安全になる。
# openssl req -new -key server.des.pem -out server.req.csr
で、これを署名してくれる人に送る。
一般的な注意として、Organization Nameに認証先と同じものを入力すること・Common NameにサーバのFQDNを入力すること、の二つがある。
CAが証明書をサインしてユーザに送り返すまで
ここの操作はecであろうと関係ないので、普通に。
# openssl ca -keyfile cakey.pem -cert cacert.cer -md sha256 -out newcert.pem -infiles server.req.csr
なお、-mdはhelpにsha1までしか載っていないが、実際にはsha256を指定できる模様。-mdを指定しないとsha1になる。設定ファイルでCA鍵対やsign用証明書を設定していれば-keyfileや-certのオプションは不要。
これまでCAがやるべきかどうかはわからないけど、証明書の部分だけを出力するためには、
# openssl x509 -in newcert.pem -out server.crt
とする。これでnewcert.pemから普通の公開鍵部分だけ取り出せる。
そしてserver.crtをサーバ証明書として活用する。
OpenSSL1.0.0で楕円曲線志向なCAを立てる
楕円曲線を用いた暗号方式でCAの証明書を作ろう、というお話。OpenSSLは1.0.0から楕円曲線暗号(ECC)への対応がきちんとしてきているのだけど、ディストリ付属のOpenSSLは古い(0.9.8)ことがある。$ openssl version とコマンド打てば使っているopensslのバージョンが分かるので、古いようだったら新しいモノを入れると幸せになれる。
環境:FreeBSD 8.1-RELEASE, opensslはportsから入れる
準備
# cat /usr/ports/security/openssl/distinfo | head -1 SHA256 (openssl-1.0.0d/openssl-1.0.0d.tar.gz) = 92511d1f0caaa298dba250426f8e7d5d00b271847886d1adc62422778d6320db # portinstall security/openssl # cp /usr/local/openssl/openssl.cnf.sample /usr/local/openssl/openssl.cnf # rehash # openssl version OpenSSL 0.9.8n 24 Mar 2010 # which openssl /usr/bin/openssl
portsからインストールしてもopensslのバージョンは1.0.0dにならない。これは/usr/bin/opensslが使われているから。
そこで、/usr/bin/opensslの実行権限を落としてしまう。良い方法かは怪しいけど、ファイル名を変えるよかマシ。
# chmod -x /usr/bin/openssl # rehash # openssl version OpenSSL 1.0.0d 8 Feb 2011
無事1.0.0dになりました。
CAの鍵対を準備する
# openssl ecparam -list_curves (略) sect233r1 : NIST/SECG/WTLS curve over a 233 bit binary field sect239k1 : SECG curve over a 239 bit binary field sect283k1 : NIST/SECG curve over a 283 bit binary field (略) # openssl ecparam -genkey -name prime256v1 -out cakey.pem
曲線については、http://www.secg.org/download/aid-784/sec2-v2.pdfを参照するに、list_curvesにて出てくる曲線のだいたいがexplicitly recommendedらしい。ただしsect239k1などの一部の曲線は様々な標準に準拠こそしているがrecommendedではないので*1、鍵対を作る前に曲線の準拠具合をチェックしておくべき。
で、2011年2月現在の調査結果*2によると、現段階でWindowsにて実装されているのはprime256v1, secp384r1, secp521r1の三種類のみらしい*3。
あとは、現在のところ楕円曲線の有効な攻撃法は見つかっていないはずなので、bit数を基準に選ぶ。160bitがRSA1024bitと同様の強度とされているので、2048bitに対応するのは224くらいだろうか、ということでprime256v1を選んでみる。
cakey.pemが鍵対ファイル。読むときはこんな感じ:
# openssl ec -in cakey.pem -text -noout
CAの自己署名証明書を作成する
# openssl req -new -x509 -days 1826 -sha256 -key cakey.pem -out cacert.cer # openssl x509 -text -noout -in cacert.cer
0.9.8dではsha1しか対応していなかったが、1.0.0bではsha256でサインできるようになっている。1826日はだいたい5年。これで自己署名証明書ができた。
鍵対と証明書との対応を確認するさい、RSAのときにはmodulusを比較したが、ecdsaの場合は上記x509の出力結果のpubの部分とecの出力結果のpubの部分が同じになっていればok。
自己署名ではなくCSR(証明書署名要求)を作る場合は以下のようなコマンド。pkcs形式なのでverisignに送るときも安心*4。
# openssl req -new -key cakey.pem -out careq.csr # openssl req -in careq.csr -text -noout
それを自分でサインするなら:
# openssl x509 -req -in careq.csr -signkey cakey.pem -out cacert.cer -days 1826
CAの諸設定
- openssl.cfgの初期設定ではCAの場所が./demoCAとなっていてとても怪しいので、まずこれをどこかの絶対パスに変更する(例:/var/ssl/CA)
- 各種ディレクトリを作る
- certs, crl, newcerts
- ファイルをtouchする
- index.txt, serial
- ファイルの中身を作る
- serialに「01」と書く
# vi /usr/local/openssl/openssl.cfg (略; [CA_default]のdir項目を絶対パスにする等) # mkdir -p /var/ssl/CA # cd /var/ssl/CA # mkdir certs crl newcerts # touch index.txt serial # cat > serial 01 ^D(ctrl-Dで入力終了)
これで最低限動くようになる。より心地よい設計は今後の課題。
参考サイトさん:
http://webframe.sourceforge.jp/wiki/index.php?OpenSSL%A4%CB%A4%E8%A4%EB%C2%CA%B1%DF%B6%CA%C0%FE%B0%C5%B9%E6%A4%CE%CD%F8%CD%D1
http://researchmap.jp/index.php?action=cv_download_main&upload_id=11085
http://cro-pel.com/modules/penguin/content0103.html
http://www.fc-lab.com/network/server/pki/openssl.html
*2:http://researchmap.jp/index.php?action=cv_download_main&upload_id=11085
*3:sect283k1で試したところ、確かにダメっぽかった
プロトタイプチェーン
ふとJavaScriptに入門してみたところ、プロトタイプチェーンなるものが現れた。
var SomeObject = function(){}; SomeObject.prototype.someMethod = function() { print("some method!\n"); }; var AnotherObject = function(){}; AnotherObject.prototype = new SomeObject();
newしたものを入れることでワークするらしい。なんで?
通常のプロトタイプはこう。
var SomeObject = function(){}; SomeObject.prototype.someMethod = function() { print("some method!\n"); }; SomeObject.prototype.anotherMethod = function() { print("another method!\n"); };
あるいは、こういう書き方もある、と紹介されてる。
var SomeObject = function(){}; SomeObject.prototype = { someMethod : function() { print("some method!\n");}, anotherMethod : function() { print("another method!\n");} };
それがどうして唐突にnewに?と疑問を抱いた。
このままでは覚えられそうにないと思ったので、spidermonkeyを使って色々試してみた。
まずはコンストラクタの動作。
js> var Hoge = function(hoge){ this.hoge = hoge; }; js> Hoge function (hoge) { this.hoge = hoge; } js> var hoge = new Hoge(2); js> hoge; [object Object] js> new Hoge(2) [object Object] js> Hoge(2) js>
コンストラクタは関数で、new + コンストラクタ によって返されるのは辞書(あるいは連想配列)。
で、コンストラクタに正しい引数を与えても何も返らない。これはコンストラクタを単に関数として判断しても何も返ってないから。return文を入れてれば対応したものが返る。
続いて生成されたオブジェクトについて見てみた。
js> var Hoge = function(hoge){ this.a = hoge + " a"; this.b = hoge + " b"; this.print_it = function(){ print (this.a + " " + this.b); }; }; js> Hoge function (hoge) { this.a = hoge + " a"; this.b = hoge + " b"; this.print_it = function () {print(this.a + " " + this.b);}; } js> hoge = new Hoge("wow"); [object Object] js> for (key in hoge) {print(key)} a b print_it js> for (key in hoge) {print(key + " = " + hoge[key])} a = wow a b = wow b print_it = function () { print(this.a + " " + this.b); } js>
オブジェクトは辞書だと納得。
で、最後に、辞書の宣言。
js> var dic = { "a" : "ahoge", "b" : "bhoge", c : "choge" } js> dic["a"] ahoge js> dic.b bhoge js> dic["c"] choge
辞書はオブジェクトと等価っぽい。
てわけで、
要は全部が辞書だからあんな書き方が許容されるみたいね。
prototypeの参照を追っかけるのは言語の仕様に入っちゃってるのかな、追いかけ方は今のところ見当もつかない。