[IM]RSAを使って、JavaScriptで暗号化し、PHPで復号する

表題の通りの仕組みを、INTER-Mediatorに組み込もうとして、2日ほどもがきました。RSAつまり秘密鍵と公開鍵を使った暗号化をフレームワークに組み込み、クライアントで入力したパスワードを、暗号化してサーバに送るという仕組みを組み込んでいます。普通パスワードはハッシュだろうと思われるかもしれませんが、フレームワークが認証するパスワードではなく、パスワードをデータベースエンジンへのアクセスに使うべく、クライアントで入力したものをバックエンドまで安全に到達させるための暗号化なのです。

RSAやハッシュ関連のことは、ネイティブな開発ならOpenSSLを使えばおおむねOKなので、同じようにライブラリを集めれば楽勝だろうと思っていました。また、PHPにはopensslライブラリがあるので、まあ、なんとかなるだろうと思いました。要件としては、キーの指定を簡単にするということ。つまり、公開鍵と秘密鍵が1つもPEM形式で得られれば、それを設定ファイルに書き込むことでキーの指定ができるということです。もちろん、生成は「openssl rsagen 1024」みたいなコマンドで簡単に済ませたいわけです。

JavaScriptの世界では、Dave Shapiroさんが作っているライブラリがあり、後々のいくつかのライブラリの多くはこれを改良しています。DaveさんのはPEM形式でキーを与えられないので、Tom WoさんのCrypticoが作られたようで、さらに別の人が署名までできるようにしています。Crypticoでいろいろやっていたのですが、うまくいかない…というか、単純にこのライブラリの問題ではなく、PHPのライブラリとの組み合わせの問題があったのです。

それで、PHPの方はというと、openssl関連関数があるので大丈夫かと思っていたら、これがなかなかうまくいかいないのです。まず、PEMでキーを与えるのが原則とすれば、Crypticoを使ってクライアント側で暗号化するのが手軽です。それを、PHPのopensslの関数で復号するのがどうしてもうまくいかないのです。そのあたりのドキュメントが今ひとつ詳しく書いておらず、コメントには「マニュアルは正しくない…」などと書いてある始末で、あれこれやってもだめでした。

ただし、PHPのopensslの関数を使えば、PEMの鍵データから、RSAの本来の鍵というか、計算式に出てくる鍵の数値をそのまま得られる事がわかりました。さらに、RSA: Encrypting in JavaScript and Decrypting in PHPというドンピシャなものがあったのですが、それはDave Shapiroさんのライブラリを使っていて、RSAの本来の鍵を使う方法が記載されています。ところが、このサイトに書いてあるPHPのライブラリはpearにあるCrypt_RSAで、説明に使っているものはすでのメンテナンスがなされていません。それを使う手もありますが、メンテナンスされているライブラリの方がいいかと思い新しいサイトへのリンクを見ると、なんとこれが、以前このblogでも紹介したPHPだけで作られたSSHのライブラリを含むphpseclib:に移行していたのです。SSHのライブラリはきわめて順調に動いたので期待をして、こちらのRSAを使って復号しようとしました。しかしながら、どんなにこねくり回してもだめなのです。このライブラリのサポートのBBSにあるこの書き込みと同じ場所でエラーが出ているようです。Macだとだめで、debianだと動くようなことが書かれているのが気になるところですが、この方法でうまく流すには簡単には行きそうにありません。

Dave Shapiroさんのライブラリで暗号復号するのはできます。また、phpseclib:で暗号復号はできます。つまり、異なるライブラリをまたいでの暗号復号がうまくいかないのです。Dave Shapiroさんのライブラリで暗号化したものを、opensslコマンドで復号してみると、パディングに関するエラーが出て復号できません。データ形式の微妙な違いがあるのでしょうか? ドキュメンテーションの薄いライブラリや、あまりカスタマイズできないライブラリということで、これ以上手を下すことができず、ここで行き詰まってしまいました。

それで、改めてググって必死に探した結果、見つけたのがbi2phpというライブラリで、しかもMIT Licenseです。JavaScriptのライブラリは、Daveさんのものに独自に改良したものだそうです。それと互換でPHPのクラスを作ったというところでしょうか。いずれも、RSAの本来の鍵を指定するのですが、「データは全部HEX」というように、ある意味非常にわかりやすく、さくっとうまく行きました。

ということで、わかった事をまとめておきます。RSAの秘密鍵、公開鍵という仕組みはもういいとして、そこで使う鍵は、たとえば「openssl genrsa 1024」というコマンド入力で作られます。そのデータはPEMという1つのテキスト列であり、いわば、そこに秘密鍵と公開鍵などなど、RSA暗号処理に必要なデータがPKCSのルールに従ってパックされたものです。

$ openssl genrsa 1024
Generating RSA private key, 1024 bit long modulus ...................++++++ ............++++++ e is 65537 (0x10001) -----BEGIN RSA PRIVATE KEY----- MIICXwIBAAKBgQC/BlONnPUfSc95YmrcOUV0IbmeBZvibbAssetKBXAG0DGeKzc7        : 2MgfcIZ3C7lf0+yx3/RhXwJBAIYHkht7UPSpPeTvPzc4v89yBlkkGeN9xLbdONT3 uzINAQkGvVmDhNLYqxkgDysBUy/Q2f41DenUZJfEFLQBs5w= -----END RSA PRIVATE KEY-----

PHP側では、このPEM形式の文字列を使って、以下のプログラムで、RSAの計算に使うキーを求めることができます。$generatedPrivateKeyにはPEM形式のキーの文字列、圧縮アルゴリズムがAESの場合はパスフレーズを入れるので、その場合は$passPhraseに指定しますが、パスフレーズが設定されていない鍵は2つ目の引数は適当に無視します。

$res = openssl_pkey_get_private( $generatedPrivateKey, $passPhrase );
$keyArray = openssl_pkey_get_details($res);

この、$keyArrayの配列にいろいろなものが入っていて、公開鍵だけを取り出すには、$keyArray[‘key’]とします。

Daveさんのライブラリを使うには、鍵のオブジェクトを作成しますが、当然、自分で生成するのではなく、このPEMを鍵としてオブジェクトを初期化します。初期化関数部分は、次のように定義されています。biRSAKeyPairが鍵のクラス名と考えていいでしょう。

function biRSAKeyPair(encryptionExponent, decryptionExponent, modulus)

ここで、encryptionExponentは$keyArray[‘rsa’][‘e’]、decryptionExponentは$keyArray[‘rsa’][‘d’]、modulusは$keyArray[‘rsa’][‘n’]から得られます。生成した鍵からopensslのコマンドを使って出力(例えば、openssl rsa -text -in gen.key)した結果を見ながら、対応付けを確認しました。配列から得られた結果はバイナリなので、PHPの場合、bin2hex関数を使って16進文字列にして、JavaScript側の引数に指定をします。2次元目のeとdは、encrypt、decryptなんでしょうね。

なお、INTER-Mediatorでは、JavaScript側では暗号化しかしないので、2番目の引数は指定しません。というか、指定してクライアント側で見えたらいけません。なぜなら、$keyArray[‘rsa’][‘d’]は秘密鍵であり、暗号化には使わないからです。いずれにしても、JavaScriptのプログラムをサーバ側のPHPで生成してクライアントに送り込むという部分がこうした処理を組み合わせて作る事ができます。

bi2phpのPHP側のクラスは、JavaScriptとほぼ同様なプログラムでいいようになっており、サンプルのHTMLを見ればプログラムの作り方はすぐにわかると思います。非常に紆余曲折がありましたが、JavaScriptとPHPの双方で暗号復号をするには、bi2phpというライブラリでOKということです。ただし、PHPのopenssl関数を使って、PEMから鍵の値を得たりということは処理として必要になるということです。このライブラリをまとめたAndrey Ovcharenkoさんに感謝するともに、ライブラリをここまで育て上げたみなさんに感謝します。

消費税増税で忘れられていること

消費税が5%から8%、そして将来は10%になるという法案が政府によって進められています。現在、年間12兆円の消費税収入があるらしいのですが、いろいろな議論が巻き起こっているのも周知の通りです。その中でまったく議論が出てこないのが「免税業者」についての話です。

現在は、すべての取引(ただし非課税のものをのぞく)に消費税の徴収が義務とされているはずです。私は2005〜2008年は会社員だったのですが、その期間の前は、「あなたは免税業者ですか」と聞かれてから請求金額が決まるという会社が多かったことが思い出されます。免税業者なら5%付加しない金額で請求書を書き、その金額が払われてたのですが、会社員をやめてフリーになって改めて調べると、免税業者に対する支払いでも消費税を付加するのが必要という記述を税務署のサイトなんかで見つけました。世の中わかりやすくなったものです。会社員以前の消費税話もいろいろあるのですが、今現在の話をしましょう。

では、現在、免税業者になっている個人や法人はその付加された5%をどうしているかというと、単にその人や法人の収入になっています。免除されているので国に対して払う必要がなく、収入なわけです。つまり、借受消費税は単に収入としてあつかっていいことになっています。現在、免税業者としてメジャーなのは年間で1000万円以下の収入のある業者です。それから、会社設立してからの一定期間も免税業者です。零細企業の支援の側面もあるのかもしれませんが、比較的多いと思われるのが、サラリーマンをしながら副業でちょこっと儲けているような人も、その副業部分が免税業者扱いになっているのが多いのではないでしょうか。これは統計がないのでわかりませんが、会社員しながら1000万を超える売り上げがある人はかなりの強者であり、その方は副業でも課税業者になりますね。まあ、普通はそこまでかせげないでしょう。

2001年頃に、免税業者の基準が売り上げ3000万円から1000万円に引き下げられました。免税業者数は368万人から231万人になり、免税業者は全体の40%になるという数字が発表されています。それまでは消費税を払っていない業者の方が数で多いという結果だったのです。当時は「うちは株式会社ですから」みたいな理由で課税業者を名乗っていた人もいましたが、おかしな理屈であり、都市伝説としか言いようがなかったですね。まあ、それはいいでしょう。

私は、1000万円以下という免税業者という施策自体を再検討する必要があると考えます。税金の公平な負担という原則があるのなら、収入に関係なくルールに従って支払うべきです。消費税は、収益に正比例するきわめて公正な税金です。消費者にはあますところなく支払わせるのなら、業者も同様じゃないでしょうか。全業者の支払い義務があるとした上で、優遇措置を検討するべきです。

収入を500万円、そしてさらに中間の250万円を平均的な収益としたら、精算した支払い税額はその5%として12.5万円です。非課税業者が200万人としたら、2500億円となります。全体の税収12兆円の中でみれば少ないのですが、それでも2%程度の増収となります。もちろん、収入額の平均値はもっと少ないとも言えますが、でかくもなく、少なくもない規模ではないかと思います。ただ、徴収のための手間というか、経費が増えるとも言えるのですが、簡易的な計算方法を導入しつつ、オンライン化により、さほどの費用はかからないと思います。

大昔の3000万円のライン、1000万円のライン、いずれも「政治的な判断」とされていて、確固たる基準がありません。これを撤廃すると、必ず「零細企業を苦しめるのか」的な意見が出てきますが、苦しめているのではありません。本来、消費者が国に対して払ったと思っているお金を、自分のところにとどめないようにしましょうというだけのことです。本来の収入ではないものを「自分のもの」として扱うフィーリングが正しくありません。そして、少なくとも、サラリーマンの副収入、つまり生活の糧は本業の給料で得られている人にまで非課税を適用するという点は、過剰な優遇としか言いようがありません。

税の公平は絶対に守られていないといけないと思います。増税の話題で免税業者のことが出てこないことに、やっぱりどこか「選挙対策」が見え隠れしている気がします。