パスフレーズ暗号化/暗号鍵管理に関する私的メモ

暗号鍵管理に関する私的メモのつづきです。
調べていたらいろいろな疑問が発生し記事にするのが遅くなってしまいました。

パスフレーズ暗号化とは

これは通常のアプリケーションでも日常的に使われている鍵の管理手法であり、直感的に分かりやすい手法ですね。秘密鍵をストレージなどで永続的に保存する際に生のままで保存するのは危険なので、暗号化して保存する手法ですが、その暗号化にパスフレーズ(パスワード)を使用する手法です。一般ではPBE(Password Based Encryption)とも呼ばれています。

一般的に使われている例としては、SSHプロトコルでクライアント認証をするための秘密鍵の暗号化がよく知られているかもしれません。SSHではパスワード認証方式以外に公開鍵認証方式というのがあり、認証のために使用する秘密鍵を接続するSSHクライアント側で保存しておく必要があります。そのためにパスフレーズで暗号化して保存する方式が使われています。

ちなみにパスフレーズもパスワードなんだったら秘密鍵なんか使わずにパスワード認証でいいんじゃね?と思われるかもしれません。

SSHの公開鍵認証方式ではサーバではなくクライアントでパスワードを検証する方が安全である、という考え方をしています。パスフレーズ入力による本人確認がクライアントの端末内で完結すれば、サーバとの接続は秘密鍵による認証となります。前回記事で述べた通り鍵の選択肢は天文学的な数になるため正攻法でサーバへの接続を攻撃するのは大変です。そうなると攻撃者はクライアント側の秘密鍵を手に入れる必要に迫られます。24時間ネット接続されてポートが開いていて様々な攻撃を試すことができるサーバと、個人所有で稼働時間、ネット接続時間帯も不明、Listenポートも閉じられているクライアント端末と、では後者の方がハッキングの難易度が高いはず、だから一般論としては公開鍵認証方式の方が安全、という考え方になります。

ただ、これはクライアント側のハッキングが困難である、ということが前提となるので、昨今のクライアント攻撃手法の進化を見ているとこれには疑問符が付きます。クライアントのセキュリティがガバガバで端末がウィルス感染したりすれば簡単に盗まれてしまうわけで、セキュリティ管理の甘いクライアントに認証の要を置くことが、必ずしも安全とは言えないのが最近の常識ではないかと思います。仮に秘密鍵が盗まれたとして、暗号化されていれば解読されるまで多少時間稼ぎができる訳ですが、そのパスフレーズが短いとか特定のワードを使用していたりなどで脆弱だとあまり意味がありません。

安全かどうかは環境と運用次第なわけで、パスワード認証方式より公開鍵認証方式の方が安全であるなどと一般論で語れるものではありません。これはsshに限った話ではなく、秘密鍵を暗号化したファイルとして保存しておくというアイデアは様々なケースで使用されています。問題は復号するための仕組みに何を使うのかということで、パスフレーズというのは人間にとっては大変分かりやすい手法ではあるのですが、現在はそれだけに依存するのは少々心許ないです。クライアント側の2要素認証などと組み合わせて非常に強力なパスワードを使用するなどすれば比較的安全になるかもしれません。

パスフレーズ暗号化の仕組み

話が脱線しましたが、パスフレーズ暗号化の仕組みについておさらいしましょう。sshで良く使われているOpenSSHの例で見ていきます。OpenSSHにはssh-keygenという鍵生成コマンドが含まれており、コマンドラインで公開鍵認証方式に使用する鍵ペアを生成する場合に使用できます。ssh-keygenで鍵を作る時は鍵フォーマットが指定できます。

  • PEM
  • PKCS8
  • RFC4716
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,115EF2DD645DEE385FEBFE7674814155

bR2WBlfpSu1wqDObiIICTPfPF1kZBSB3X63nfB3qficYxFh/6cPjPzR3IyFjMuUv
zwvq40qGsLYCqCRSQEPLt1svXjaAlhwlGLR1kzADSomrxV8pp44BLu40vgfsT5IG
~(省略)~
vJbrOejLLTwQ8WekpAS7NxudF16Do7FmgBkzurp4h/0K9YCPPODAscmSe7FRjNQj
8Xd0Ym5vv/1Or46cq0wRvj110TRY3IjAfE96YTxnYNxqC34sP1vp3ckpFJ+OY6Sl
-----END RSA PRIVATE KEY-----

OpenSSHではこれらのフォーマットの仕組みがすなわち秘密鍵暗号化の仕組みになります。ただ、PEMはバイナリデータをBASE64エンコードしたテキストで表現する形式のことなので厳密にはPBEのフォーマットのことではないですね。ここでPEMを指定した場合に出力されるフォーマットはPKCS#5形式で暗号化されたフォーマットになります。PKCS#5は旧RSA社(現EMC社)が策定したPBEの規格を標準化したものになります。PEMは例えば次のようなテキストです。

PEMのヘッダ部分からフォーマットの意味が分かります。まず「RSA PRIVATE KEY」はこの秘密鍵はRSAの秘密鍵であること、「Proc-Type: 4 ,ENCRYPTED」はこの秘密鍵を共通鍵暗号方式で暗号化していることを意味しています。そして「DEK-Info:」で実際に暗号化をしているアルゴリズムを示しており、この場合はAES-128-CBCを使って暗号化していることが分かります。そして、その横に暗号化する際の初期化ベクタ(IV)の値が並んでいます。以降は実際に暗号化されてBase64エンコードされた秘密鍵のデータが並んでいます。

上記IVの先頭8バイトは「ソルト」という乱数として使用されます。ソルトと入力されたパスワードを組み合わせてハッシュ関数にかけたハッシュ値を「秘密鍵を暗号化する鍵」と「初期化ベクタ(IV)」に分割して暗号化に使用します。なぜソルト(乱数)と組み合わせるのかというとパスワードに対して鍵が一意にならないようにするためです。

乱数がないとどうなるかというと、事前に特定のパスフレーズに対応する「秘密鍵を暗号化する鍵」の値のセットを辞書として用意しておけば、試行すべき「秘密鍵を復号(暗号化)する鍵」のパターンを辞書の数に限定できるので、攻撃が比較的容易になります。ソルトが加われば鍵のパターンは膨大になるので、攻撃者はソルトと想定するパスフレーズの両方を使ったハッシュ値の計算から試行をしなければならないので、予め用意した鍵で時間短縮を図ることはできなくなります。

もちろんパスフレーズが特定のキーワードではなく完全にランダムな文字列ならそのような攻撃を回避できますが、それは「人間が覚えやすい」というパスフレーズ暗号化のメリットを損なうことになるため、そのようなパスフレーズを使うケースは少ないであろう、ということを前提に仕組みで安全性を補強しているわけです。

さて、このようにして作った「秘密鍵を暗号化する鍵」を使って実際に鍵を暗号化しますが、上の例で言うとアルゴリズムにAES-128-CBCを使って暗号化することになります。暗号化が完了すると暗号化された鍵をIV(上記DEK-Infoのデータ列でソルトを含む)と一緒に保存します。そして、ここで「秘密鍵を暗号化する鍵」は破棄します。

復号は「秘密鍵を暗号化する鍵」を作る部分までは暗号化とほぼ同じ手順です。ただしソルトは暗号化された鍵と一緒に保存されたIVから取得します。ソルトと入力されたパスフレーズから「秘密鍵を復号(暗号化)する鍵」ができたら、暗号化と同様のAES-128-CBCのアルゴリズムで復号を行います。これで晴れて暗号化が解けて必要な秘密鍵を入手することができます。

メリット・デメリット

既に書いていますが、メリットはパスフレーズは人間にとって覚えやすく直感的に分かりやすいということになります。また、暗号化されたデータはファイルの形式などに保存できるため、比較的ポータビリティが高く運用しやすいというメリットがあります。もちろん、暗号化されたデータは安全な場所に保存するのが大前提です。

デメリットは正規の手続きでパスフレーズを試していくことは可能なので 辞書攻撃で復号される可能性がある、という点になります。パスフレーズが単純な単語だけで構成された脆弱な文字列の場合、比較的少ない試行回数で破られる可能性があります。もちろん試しに復号してみただけでは、復号結果が本当に正しいかは、攻撃者に分かりません。しかし、RSAの秘密鍵などは特定のASN.1構造をしているため、解析すればそれが正しいかどうかはある程度判定できるでしょう。パスフレーズの強度やパスフレーズそのものの管理(脳内かメモかなど)、暗号化ファイルの保存場所など、安全性において運用に依存する要素が多いため管理のしやすさという面では実は難のある方式であると言えます。

ポータビリティが高いゆえの利便性と脆弱性もあるので、用途に応じて安全性と利便性のバランスを考慮して活用する必要があります。

活用シーン

主に通常のファイルシステム上で秘密鍵を安全に管理したい場合、秘密鍵をファイルとして別のアプリケーションに受け渡す必要がある場合、などに活用できます。

注意事項

過去にはハッシュ(ダイジェスト)にMD5やSHA-1を使用していたようですが、現在はこれらのアルゴリズムは危殆化しているため利用すべきではありません。最低でもPBKDF2を使った鍵生成プロセスを使用する必要があります。

類似手法

ssh-keygenの選択肢にあった「PKCS8」すなわちPKCS#8という秘密鍵フォーマットの定義もありますが、これもパスフレーズによる暗号化をサポートしています。またPKCS#12では秘密鍵と公開鍵や証明書を一つにしてパスフレーズで暗号化することができます。これらの方式はASN.1構造の中に暗号化データを含んでいるのでPKCS#5に比べると比較的、攻撃の難易度は高いと言えます。現在はこれらの方がメジャーかもしれません。

参考

PKCS #5: Password-Based Cryptography Specification

コメント

  1. […] ・パスフレーズ暗号化 →(2019.01.04)記事を公開しました。 […]

タイトルとURLをコピーしました