マイナンバーに付属の個人番号カード(マイナンバーカード)でも、利用されている公開鍵暗号や電子署名技術。
そして、Let’s Encryptも含めウェブに関しては常時TLS化が始まっている時代。その認証基盤技術である公開鍵暗号と電子署名の基礎をステップごとに復習します。
公開鍵認証に関しては比較的新しいECC楕円などもありますが、いろいろな場面では未対応のシステムが多いことがわかり、2015年11月現在で標準的な
– 公開鍵暗号方式:RSA 2048 bit
– 共通鍵暗号方式:AES 256 bit
– 暗号学的ハッシュ関数:SHA-2(SHA-256)
を用いることにします。SHA-2に関しては64bit環境では、SHA-512などが良いのでしょうが、スマートカード内CPUはまだまだ32bit環境も多いため、SHA-256とします。
*テスト環境:Cent OS 7 (64bit), OpenSSL 1.0.1e-fips 11 Feb 2013
*留意:2015/11/22時点での記事です。未来で参照する場合は最新技術、特に上記の方式なども使用禁止などの可能性があるのでご留意ください。
<その1:公開鍵暗号を用いてテキストファイルを暗号化・復号化>
1) 秘密鍵の生成(RSA 2048bit, X509 .PEMファイル)
# openssl genrsa 2048 > private_key.pem
秘密鍵`private_key.pem`ができました。(パスフレーズなしの秘密鍵)
2) 公開鍵の生成(秘密鍵より公開鍵を作成します)
# openssl rsa -pubout < private_key.pem > public_key.pem
公開鍵`public_key.pem`ができました。
3) それほど長くない暗号化するための平文テキストファイルを生成します。
# echo ‘hello, encrypt / decrypt world’ > test_plain.txt
text_plain.txtという31バイトの平文テキストファイルが生成されました。これを暗号化・復号化してみます。
それほど長くないという意味は、鍵長が2048bitなのでそれを超えるファイルサイズの物は原理的に暗号化できない。
4.1) 公開鍵で暗号化
# openssl rsautl -encrypt -pubin -inkey public_key.pem < test_plain.txt > test_plain.txt.encrypted
text_plain.txt.encryptedという暗号化されたバイナリファイルが生成されています(256バイト)
以上でテキストファイルを暗号化することができました。
4.2) 秘密鍵で復号化
# openssl rsautl -decrypt -inkey private_key.pem < test_plain.txt.encrypted > test_plain.txt.decrypted
text_plain.txt.decryptedというテキストファイルが生成されているはずです(31バイト)。
これで無事に元の平文テキストファイル(ファイルサイズも同じ)を復号化して生成することができました。
*補足:4.1), 4.2)は公開鍵で暗号、秘密鍵で復号でしたが、公開鍵暗号はその逆もできることが電子署名技術で重要な考え方です。つまり秘密鍵で暗号化されたものは、秘密鍵でのみ復号化できるという公開鍵暗号=非対称暗号の特徴です。
そこで試してみようと調べてみたらopenssl rsautlは秘密鍵で暗号、公開鍵で復号はできないようです。試してみたら復号化時に`A private key is needed for this operation`というエラーが出てしまいます。
つまり、秘密鍵での暗号に関しては、電子署名のみに使うことが前提となっているようです。
(非対称暗号の原理・特徴の前に実利用的なことを考えるとあたりまえかな。テストだけしてみたかったのですが)
*補足:あまり長いファイルを暗号化できないと上述しましたが、ではウェブのHTTPS(SSL/TLS)やSSHのリモートログイン時などはどうしているかというと、あくまで多量なデータ・ファイルの通信には暗号化・復号化の速度も速い共通鍵暗号を用いており、その共通鍵の受け渡しに今回の公開鍵暗号を使っているわけですね。
おまけ)共通鍵暗号(AES 256bit)を用いたファイルの暗号化・復号化
暗号化:
# openssl aes-256-cbc -e < test_plain.txt > test_plain.txt.AES256
暗号化するための共通鍵を問われますので何か入力して暗号化します。test_plain.txt.AES256という暗号化されたファイルが生成されます。
復号化:
# openssl aes-256-cbc -d < test_plain.txt.AES256 > test_plain.txt.AES256.decrypted
同じく復号化するための共通鍵を問われますので暗号化時に入力したものを入力します。test_plain.txt.AES256.decryptedというファイルで復号化されているはずです。
<その2:何らかのファイルに電子署名をし、そのファイルが途中で第三者に改ざんされていないかを確認する>
秘密鍵はその名の通り、厳密に秘密に管理され、その鍵を使用する個人しか持っていないとされている鍵です。これは言葉で書くのは簡単ですが、実際には上記でテストしたように秘密鍵をPC上などでファイルで扱うのは本当に`秘密`にしておけるのかというのが難しい問題です。そのPCがウイルスに侵されてファイルが盗まれたとか、もっと単純に他の人がログインをしてUSBメモリにコピーされたなど。その問題に対して、スマートカードやUSBトークンなどがあり、そのカード内に秘密鍵を保持し、その秘密鍵は取り出すことも複製もできなくすれば良いわけです。今回のマイナンバーにおける個人番号カード(スマートカード)も希望者にはマイナンバーの他に秘密鍵などが書きこまれた状態で取得できるはずです。最近のスマートカード(おそらく個人番号カードも)は内部にCPUを持っており、鍵生成・認証等の処理をカード内で行い、カードから秘密鍵等を端末まで出してこなくても処理ができるので、使用した端末に秘密鍵が残ることはほぼないはずです。NFCの電力伝送で非接触カード内CPUを動かしてRSAなどの演算をさせるのはやや大変な気がするので、個人番号カードはカードリーダーを用いる接触型が多いのではないかなと思います。しかし、スマートフォンのNFCで個人認証などをする未来を考えると、非接触でカード内認証ができるほうが良い様な気もします。スマートフォンにカードリーダーをつけるわけにはいきませんしどうなるのでしょう。FelicaやMIFAREなどの非接触カードで、公開鍵認証ができるものは無いような気がするのですが、そういう製品が出ているのですかね。マイナンバー特需でメーカーもがんばっているかもしれません。
さて、電子署名に関してですが、秘密鍵はその個人が唯一持っている鍵であることと、公開鍵暗号の非対称性を利用して行うものです。つまり秘密鍵で暗号化されたものは、公開鍵で復号できる特徴です。
(電子署名技術はいろいろ種類がありますが、有力である公開鍵暗号方式に基づくデジタル署名ということで話を進めます)
基本的な流れを復習すると
(い)Aさんが大切な文章をWordファイルで作成。(今回たまたまWordファイルを例にして紹介していますが、どんなファイルでも同じです)
(ろ)Aさんは、秘密鍵を使ってWordファイルで暗号化する。
(は)Aさんは、取引先のBさんに、Wordファイル原本と、暗号化したファイルの2つを渡す。
(に)Bさんは、届いた2つのファイルの内、暗号化されているファイルを公開されているAさんの公開鍵で復号する。
(ほ)Bさんは、Wordファイル原本と、Aさんの公開鍵で復号したWordファイルを比較する。
(へ)2つのファイルがまったく同じものだったら、「これはAさんが作成されたものに間違いなく、他の人が改変などしていない」ことと判断できる。
となるわけですね。これは秘密鍵がAさんしか持っていない特徴によって実現できるものです。
ただし一般的に‘電子署名をする‘といったら、上記の方法の様にWordファイル全体を暗号化して送ることはしません。公開鍵暗号で大きなファイルを暗号化するのは処理的にも重いものですし、Bさんに2つのファイルを転送するのは転送量も2倍(以上)になり、また巨大な2つのファイルをバイナリ・ビットレベルで比較するのも大変であるからです。
そこで、暗号化ハッシュ関数を用います。Wordファイル(Wordに限らずどんなファイルでもOK)にハッシュ関数を計算すると、Wordファイルの大きさにかかわらず同じ長さのハッシュ値(メッセージダイジェストとも表現される)を取得できます。ファイルの内容が1bitでも異なるとこのハッシュ値は異なりますので、1つのファイルに対して確実に1つだけのハッシュ値を生成できます。またハッシュ値からファイル本体を復元(復号)することはできません。つまり上記の(い)~(へ)を暗号化ハッシュ関数を用いると
(い)Aさんが大切な文章をWordファイルを作成し、またハッシュ関数でそのファイルのハッシュ値を生成。
(ろ)Aさんは、ハッシュ値を秘密鍵を使って暗号化。そのことを‘電子署名する‘と言います。「このファイルの電子署名をお願いします」と頼まれたらハッシュ値を取ってそれを秘密鍵で暗号化することを意味します。
(は)Aさんは、取引先のBさんにWordファイル原本と、(ろ)で生成した電子署名(ハッシュ値を暗号化したもの)の2つを渡す。
(に)Bさんは、受け取った電子署名を、Aさんの公開鍵で復号し、Aさんが生成したハッシュ値を取得します。
(ほ)Bさんは、受け取った原本のWordファイルのハッシュ値を求め、(に)で取得したハッシュ値と比較します。
(へ)2つのハッシュ値がまったく一緒だったら、「これはAさんが作成されたものに間違いなく、他の人が改変していたらハッシュ値もかわるはずなので、改変はない」と判断できる。
以上を踏まえ、OpenSSLで電子署名の動きを実際に確認してみます。
5) 上記の例に沿ってWordファイルを用意します。
5.1) 正しいWordファイル(test_word1.docx : 835666バイト)
5.2) 正しいWordファイルを改変したファイル(test_word2.docx : 835812バイト)
6) 正しいWordファイルをSHA-256でハッシュを取得してみます(参考)
# sha256sum test_word1.docx
ハッシュ値:b37c7c542a5af29ef6edb5e1cb2406385121c46e1b406361d80e9e6d6c5df9f6
*本来はこのハッシュ値を秘密鍵で暗号化すれば電子署名になりますが、上述のとおり秘密鍵で暗号化がOpenSSLではできないのでこのハッシュ値の取得は参考例です。
7) 正しいWordファイルをSHA-256でハッシュ値(ダイジェスト)を求め、秘密鍵で暗号化します(つまり電子署名します)
# openssl dgst -sha256 -sign private_key.pem test_word1.docx > test_word1.sign
test_word1.signというバイナリファイル(256バイト)が生成され、電子署名となります。
8) ここからは別の人が2つのWordファイル(正しいもの、改変されたもの)、そして7)の電子署名を受け取ったことにして、電子署名を公開鍵を用いて検証します。
– 正しいファイル(test_word1.docx)の場合
# openssl dgst -sha256 -verify public_key.pem -signature test_word1.sign test_word1.docx
Verified OKと出て検証OKです。
– 改変ファイル(test_word2.docx)の場合
# openssl dgst -sha256 -verify public_key.pem -signature test_word1.sign test_word2.docx
Verification Failureと出て、改変された(少なくとも電子署名をしたファイルではない)ことが分かります。
まとめ
・公開鍵暗号、電子署名をOpenSSLを用いて実際の動作をステップ毎に確認しました。
・今回秘密鍵生成を‘パスフレーズなし‘で行いましたが、実利用では秘密鍵の使用を制限するパスフレーズを設ける必要があります。スマートカードならPIN(Personal Identification Number)になります。
・実際にはOpenSSLを実装したシステム・ソフトが勝手にこの作業を行ってくれています。
・公開鍵に関して雑に扱いましたが、公開鍵は信頼できる第三者機関(Trusted Third party)が信頼できる公開鍵ですよとして公開されている(つまり電子証明書=公開鍵証明書)のが望ましく、それが前提となっています。
・日本において印鑑は血判状なども含め大切にされてきました。一方で今のグローバル時代には非効率であるという点は避けられない事実です。電子署名は法律的にも認められていますし、印鑑の良さを残しつつ、スマートな契約等が進むと良いですね。