無料スクリプト配布のPHP.TO   PHPの実用的なtips PHPマニュアル MySQLマニュアル Apacheマニュアル PostgreSQLマニュアル マニュアル検索    

F.25. pgcrypto

pgcrypto モジュールは PostgreSQL 用の暗号関数を提供します。

F.25.1. 汎用ハッシュ関数

F.25.1.1. digest()

digest(data text, type text) returns bytea
digest(data bytea, type text) returns bytea

与えられた data のバイナリハッシュを計算します。 type は使用するアルゴリズムです。 標準アルゴリズムは md5 sha1 sha224 sha256 sha384 、および sha512 です。 pgcrypto がOpenSSL付きで構築された場合、 表F-18 で詳解する、より多くのアルゴリズムを利用することができます。

ダイジェストを16進数表記の文字列としたい場合は、結果に対して encode() を使用してください。 以下に例を示します。

CREATE OR REPLACE FUNCTION sha1(bytea) returns text AS $$
    SELECT encode(digest($1, 'sha1'), 'hex')
$$ LANGUAGE SQL STRICT IMMUTABLE;

F.25.1.2. hmac()

hmac(data text, key text, type text) returns bytea
hmac(data bytea, key text, type text) returns bytea

key をキーとした data のハッシュ化MACを計算します。 type digest() の場合と同じです。

digest() と似ていますが、ハッシュはキーを知っている場合にのみ再計算できます。 これは、誰かがデータを変更し、同時に一致するようにハッシュを変更するという状況を防ぎます。

キーがハッシュブロックサイズより大きい場合、まずハッシュ化され、その結果をキーとして使用します。

F.25.2. パスワードハッシュ化関数

crypt() および gen_salt() 関数は特にパスワードのハッシュ化のために設計されたものです。 crypt() がハッシュ処理を行い、 gen_salt() はハッシュ処理用のアルゴリズム上のパラメータを準備します。

crypt() アルゴリズムは、以下の点で通常のMD5やSHA1のようなハッシュ処理アルゴリズムと異なります。

  1. 低速です。 データ量が少ないためパスワード総当たり攻撃に対して頑健にする唯一の方法です。

  2. 結果には ソルト というランダムな値が含まれます。 このため同じパスワードのユーザでも異なった暗号化パスワードを持ちます。 これはアルゴリズムの逆処理に対する追加の防御です。

  3. 結果内にアルゴリズムの種類が含まれます。 このため異なるアルゴリズムでハッシュ化したパスワードが混在可能です。

  4. 一部は適応型です。 つまり、コンピュータが高速になったとしても、既存のパスワードとの互換性を損なうことなくアルゴリズムを低速に調整することができます。

crypt() 関数がサポートするアルゴリズムを 表F-15 に列挙します。

表 F-15. crypt() がサポートするアルゴリズム

アルゴリズム パスワード最大長 適応型かどうか ソルトビット長 出力長 説明
bf 72 はい 128 60 Blowfishベース、2a版
md5 無制限 いいえ 48 34 MD5ベースの暗号
xdes 8 はい 24 20 拡張DES
des 8 いいえ 12 13 元来のUNIX crypt

F.25.2.1. crypt()

crypt(password text, salt text) returns text

password のcrypt(3)形式のハッシュを計算します。 新しいパスワードを保管する時には、 gen_salt() を使用して新しい salt を生成する必要があります。 パスワードを検査する時、既存のハッシュ値を salt として渡し、結果が格納された値と一致するかどうかを確認します。

新しいパスワードの設定例を以下に示します。

UPDATE ... SET pswhash = crypt('new password', gen_salt('md5'));

認証の例です。

SELECT (pswhash = crypt('entered password', pswhash)) AS pswmatch FROM ... ;

入力パスワードが正しければ true を返します。

F.25.2.2. gen_salt()

gen_salt(type text [, iter_count integer ]) returns text

crypt() で使用するランダムなソルト文字列を新規に生成します。 また、このソルト文字列は crypt() にどのアルゴリズムを使用するかを通知します。

type パラメータはハッシュ化アルゴリズムを指定します。 受付可能な種類は、 des xdes md5 bf です。

繰り返し回数を持つアルゴリズムでは、ユーザは iter_count パラメータを使用して繰り返し回数を指定できます。 指定する回数を高くすれば、パスワードのハッシュ化にかかる時間が長くなり、それを破るための時間も長くなります。 しかし、あまりに多くの回数を指定すると、ハッシュ計算にかかる時間は数年に渡ってしまう可能性があります。 これは実用的ではありません。 iter_count パラメータを省略した場合、デフォルトの繰り返し回数が使用されます。 iter_count で受け付けられる値はアルゴリズムに依存し、 表F-16 に示す通りです。

表 F-16. crypt() 用の繰り返し回数

アルゴリズム デフォルト 最小 最大
xdes 725 1 16777215
bf 6 4 31

xdes の場合は他にも、回数が奇数でなければならないという制限があります。

適切な繰り返し回数を選択するために、元々のDES暗号は当時のハードウェアで1秒あたり4個のハッシュを持つことができるように設計されたことを考えてください。 毎秒4ハッシュより遅いと、おそらく使い勝手が悪いでしょう。 毎秒100ハッシュより速いというのは、十中八九、あまりにも速すぎるでしょう。

ハッシュ化アルゴリズム別に相対的な速度に関する概要を 表F-17 にまとめました。 この表は、8文字のパスワード内のすべての文字の組合せを取るためにかかる時間を示します。 また、すべて小文字の英字のみのパスワードである場合と大文字小文字が混在した英字と数字のパスワードの場合を仮定します。 crypt-bf の項では、スラッシュの後の数値は gen_salt iter_count です。

表 F-17. ハッシュアルゴリズムの速度

アルゴリズム 1秒当たりのハッシュ数 [a-z] の場合 [A-Za-z0-9] の場合
crypt-bf/8 28 246年 251322年
crypt-bf/7 57 121年 123457年
crypt-bf/6 112 62年 62831年
crypt-bf/5 211 33年 33351年
crypt-md5 2681 2.6年 2625年
crypt-des 362837 7日 19年
sha1 590223 4日 12年
md5ハッシュ 2345086 1日 3年

注意:

  • Pentium 4 1.5GHzのマシンを使用しました。

  • crypt-des および crypt-md5 アルゴリズムの数値はJohn the Ripper v1.6.38の -test 出力から得たものです。

  • md5ハッシュ の数値はmdcrack 1.2のものです。

  • sha1 の数値はlcrack-20031130-betaのものです。

  • crypt-bf の数は、1000個の8文字パスワードをループする単純なプログラムを使用して得たものです。 こうして、異なる回数の速度を示すことができました。 参考までに、 john -test crypt-bf/5 で213 loops/secでした。 (結果の差異が非常に小さいことは、 pgcrypto における crypt-bf 実装がJohn the Ripperで使用されるものと同じであるという事実と一致します。)

"すべての組み合わせを試行する" ことは現実的な行使ではありません。 通常パスワード推定は、普通の単語とその変形の両方を含む辞書を使用して行われます。 ですので、いささかなりとも言葉に似たパスワードは上で示した数値よりも速く推定されます。 また6文字の単語に似ていないパスワードは推定を免れるかもしれませんし、免れないかもしれません。

F.25.3. PGP暗号化関数

ここで示す関数はOpenPGP(RFC 4880)標準の暗号処理部分を実装します。 対称キーおよび公開キー暗号化がサポートされます。

暗号化されたPGPメッセージは次の2つの部品(または パケット )から構成されます。

  • セッションキーを含むパケット。 対称キーまたは公開キー暗号化の両方。

  • セッションキーにより暗号化されたデータを含むパケット。

対称キー(つまりパスワード)で暗号化する場合

  1. 与えられたパスワードはString2Key(S2K)アルゴリズムでハッシュ化されます。 これはどちらかというと crypt() アルゴリズムと似て、意図的に低速で、かつランダムなソルトを使用します。 しかし、全長のバイナリキーを生成します。

  2. 分離したセッションキーが要求された場合、新しいランダムなキーが生成されます。 さもなくば、S2Kキーがそのままセッションキーとして使用されます。

  3. S2Kキーがそのまま使用される場合、S2K設定のみがセッションキーパケットに格納されます。 さもなくば、セッションキーはS2Kキーで暗号化され、セッションキーパケットに格納されます。

公開キーで暗号化する場合

  1. 新しいランダムなセッションキーが生成されます。

  2. これは公開キーを使用して暗号化され、セッションキーパケットに格納されます。

どちらの場合でもデータ暗号化は以下のように処理されます。

  1. 省略可能なデータ操作として、圧縮、UTF-8への変換、改行の変換があります。

  2. データの前にはランダムなバイト数のブロックが付きます。 これはrandom IVを使用する場合と同じです。

  3. ランダムな前置ブロックとデータのSHA1ハッシュが後に付けられます。

  4. これをすべてセッションキーで暗号化し、データパケットに格納します。

F.25.3.1. pgp_sym_encrypt()

pgp_sym_encrypt(data text, psw text [, options text ]) returns bytea
pgp_sym_encrypt_bytea(data bytea, psw text [, options text ]) returns bytea

対称PGPキー psw data を暗号化します。 options パラメータには後述のオプション設定を含めることができます。

F.25.3.2. pgp_sym_decrypt()

pgp_sym_decrypt(msg bytea, psw text [, options text ]) returns text
pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea

対称キーで暗号化されたPGPメッセージを復号します。

pgp_sym_decrypt bytea 型のデータを復号することはできません。 これは無効な文字データの出力を防止するためです。 元のテキストのデータを pgp_sym_decrypt_bytea で復号することが正しい方法です。

options パラメータには後述のオプション設定を含めることができます。

F.25.3.3. pgp_pub_encrypt()

pgp_pub_encrypt(data text, key bytea [, options text ]) returns bytea
pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea

公開PGPキー key data を暗号化します。 この関数に秘密キーを与えるとエラーになります。

options パラメータには後述のオプション設定を含めることができます。

F.25.3.4. pgp_pub_decrypt()

pgp_pub_decrypt(msg bytea, key bytea [, psw text [, options text ]]) returns text
pgp_pub_decrypt_bytea(msg bytea, key bytea [, psw text [, options text ]]) returns bytea

公開キーで暗号化されたメッセージを復号します。 key は、暗号化に使用した公開キーに対応する秘密キーでなければなりません。 秘密キーがパスワードで保護されている場合は、そのパスワードを psw で指定しなければなりません。 パスワードはないが、オプションを指定したい場合は空のパスワードを指定する必要があります。

pgp_pub_decrypt bytea 型のデータを復号することはできません。 これは無効な文字データの出力を防止するためです。 元のテキストのデータを pgp_pub_decrypt_bytea で復号することが正しい方法です。

options パラメータには後述のオプション設定を含めることができます。

F.25.3.5. pgp_key_id()

pgp_key_id(bytea) returns text

pgp_key_id はPGP公開キーまたは秘密キーのキーIDを取り出します。 暗号化されたメッセージが指定された場合は、データの暗号化に使用されたキーIDを与えます。

2つの特殊なキーIDを返すことがあります。

  • SYMKEY

    メッセージは対称キーで暗号化されました。

  • ANYKEY

    メッセージは公開キーで暗号化されましたが、キーIDが消去されていました。 つまり、どれで復号できるかを判定するためにはすべての秘密キーを試行しなければならないことを意味します。 pgcrypto 自身はこうしたメッセージを生成しません。

異なるキーが同一IDを持つ場合があることに注意してください。 これは稀ですが、正常なイベントです。 この場合クライアントアプリケーションはどちらが当てはまるかを調べるために、 ANYKEY の場合と同様に、それぞれのキーで復号を試行しなければなりません。

F.25.3.6. armor() , dearmor()

armor(data bytea) returns text
dearmor(data text) returns bytea

PGPのASCIIアーマー形式にデータを隠す、または、データを取り出します。 ASCIIアーマーは基本的にCRC付きのBASE64という形式で、追加のフォーマットがあります。

F.25.3.7. PGP関数用のオプション

オプションはGnuPGに似せて命名しています。 オプションの値は等号記号の後に指定しなければなりません。 複数のオプションはカンマで区切ってください。 以下に例を示します。

pgp_sym_encrypt(data, psw, 'compress-algo=1, cipher-algo=aes256')

convert-crlf を除くすべてのオプションは暗号化関数にのみ適用可能です。 復号関数はPGPデータからこうしたパラメータを入手します。

もっとも興味深いオプションはおそらく compress-algo unicode-mode でしょう。 残りはデフォルトで問題ないはずです。

F.25.3.7.1. cipher-algo

使用する暗号アルゴリズム。

値: bf, aes128, aes192, aes256 (OpenSSL-only:  3des cast5 )
デフォルト: aes128
適用範囲: pgp_sym_encrypt, pgp_pub_encrypt

F.25.3.7.2. compress-algo

使用する圧縮アルゴリズム。 PostgreSQL がzlib付きで構築されている場合のみ利用可能です。

値:
 0 - 非圧縮
 1 - ZIP圧縮
 2 - ZLIB圧縮 (ZIPにメタデータとブロックCRCを加えたもの)
デフォルト: 0
適用範囲: pgp_sym_encrypt, pgp_pub_encrypt

F.25.3.7.3. compress-level

どの程度圧縮するかです。 レベルが大きい程小さくなりますが、低速になります。 0は圧縮を無効にします。

値: 0, 1-9
デフォルト: 6
適用範囲: pgp_sym_encrypt, pgp_pub_encrypt

F.25.3.7.4. convert-crlf

暗号化の際に \n \r\n に、復号の際に \r\n \n に変換するかどうか。 RFC 4880では、テキストデータは改行コードとして \r\n を使用して格納すべきであると規定されています。 完全にRFC準拠の動作を行いたければ、これを使用してください。

値: 0, 1
デフォルト: 0
適用範囲: pgp_sym_encrypt, pgp_pub_encrypt, pgp_sym_decrypt, pgp_pub_decrypt

F.25.3.7.5. disable-mdc

データをSHA-1で保護しません。 このオプションを使用することが良い唯一の理由は、SHA-1で保護されたパケットがRFC 4880に追加される前の、古いPGP製品との互換性を得るためです。 最近のgnupg.orgおよびpgp.comのソフトウェアではこれを正しくサポートしています。

値: 0, 1
デフォルト: 0
適用範囲: pgp_sym_encrypt, pgp_pub_encrypt

F.25.3.7.6. enable-session-key

分離したセッションキーを使用します。 公開キー暗号では常に分離したセッションキーを使用します。 これは対称キー暗号向けのもので、デフォルトではS2Kをそのまま使用します。

値: 0, 1
デフォルト: 0
適用範囲: pgp_sym_encrypt

F.25.3.7.7. s2k-mode

使用するS2Kアルゴリズム。

値:
  0 - ソルト無。危険です
  1 - ソルト有。固定繰り返し回数。
  3 - 可変繰り返し回数
デフォルト: 3
適用範囲: pgp_sym_encrypt

F.25.3.7.8. s2k-digest-algo

S2K計算で使用するダイジェストアルゴリズム。

値: md5, sha1
デフォルト: sha1
適用範囲: pgp_sym_encrypt

F.25.3.7.9. s2k-cipher-algo

分離したセッションキーの暗号化に使用する暗号。

値: bf, aes, aes128, aes192, aes256
デフォルト: cipher-algoを使用
適用範囲: pgp_sym_encrypt

F.25.3.7.10. unicode-mode

テキストデータをデータベース内部符号化方式からUTF-8に変換して戻すかどうかです。 データベースがすでにUTF-8であれば、変換は起こらず、データにUTF-8としてタグが付くのみです。 このオプションがないと、何も行われません。

値: 0, 1
デフォルト: 0
適用範囲: pgp_sym_encrypt, pgp_pub_encrypt

F.25.3.8. GnuPGを使用したキーの生成

新しいキーを生成します。

gpg --gen-key

推奨するキー種類は "DSAとElgamal" です。

RSA暗号化のためには、マスタとしてDSAまたはRSAで署名のみのキーを作成し、そして gpg --edit-key を使用してRSAで暗号化された副キーを追加しなければなりません

キーを列挙します。

gpg --list-secret-keys

ASCIIアーマー形式で公開キーをエキスポートします。

gpg -a --export KEYID > public.key

ASCIIアーマー形式の秘密キーをエキスポートします。

gpg -a --export-secret-keys KEYID > secret.key

PGP関数にこれらのキーを渡す前に dearmor() を使用する必要があります。 バイナリデータを扱うことができる場合、gpgから -a フラグを省略することができます。

詳細は man gpg The GNU Privacy Handbook http://www.gnupg.org サイトの各種文書を参照してください。

F.25.3.9. PGPコードの制限

  • 署名に関するサポートはありません。 これはまた、暗号化副キーがマスタキーに属しているかどうか検査しないことを意味します。

  • マスタキーとして暗号化キーをサポートしません。 一般的にこうした状況は現実的ではありませんので、問題にならないはずです。

  • 複数の副キーに関するサポートはありません。 よくありますので、これは問題になりそうに見えます。 一方、通常のGPG/PGPキーを pgcrypto で使用すべきではありません。 使用する状況が多少異なりますので新しく作成してください。

F.25.4. 暗号化そのものを行う関数

これらの関数はデータ全体を暗号化するためだけに実行します。 PGP暗号化の持つ先端的な機能はありません。 したがって、大きな問題がいくつか存在します。

  1. 暗号キーとしてユーザキーをそのまま使用します。

  2. 暗号化されたデータが変更されたかどうかを確認するための整合性検査をまったく提供しません。

  3. ユーザが、IVをも含め暗号化パラメータ自体をすべて管理していることを想定しています。

  4. テキストは扱いません。

このため、PGP暗号化の導入もあり、暗号化のみの関数はあまり使用されません。

encrypt(data bytea, key bytea, type text) returns bytea
decrypt(data bytea, key bytea, type text) returns bytea

encrypt_iv(data bytea, key bytea, iv bytea, type text) returns bytea
decrypt_iv(data bytea, key bytea, iv bytea, type text) returns bytea

type で指定した暗号方法を使用してデータの暗号化・復号を行います。 type 文字列の構文は以下の通りです。



algorithm

 [
 
-
 

mode

 
] [
 
/pad:
 

padding

 
]

ここで algorithm は以下の1つです。

  • bf — Blowfish

  • aes — AES (Rijndael-128)

また mode は以下の1つです。

  • cbc — 次のブロックは前ブロックに依存します(デフォルト)

  • ecb — 各ブロックは独自に暗号化されます(試験用途のみ)

padding は以下の1つです。

  • pkcs — データ長に制限はありません(デフォルト)

  • none — データは暗号ブロックサイズの倍数でなければなりません

このため、例えば以下は同じです。

encrypt(data, 'fooz', 'bf')
encrypt(data, 'fooz', 'bf-cbc/pad:pkcs')

encrypt_iv および decrypt_iv では、 iv パラメータはCBCモード用の初期値となります。 ECBでは無視されます。 正確にブロック長でない場合、切り抜かれるか、もしくはゼロで埋められます。 このパラメータがない場合、関数のデフォルト値はすべてゼロです。

F.25.5. ランダムデータ関数

gen_random_bytes(count integer) returns bytea

暗号論的に強いランダムな count バイトを返します。 一度に最大で1024バイトを抽出することができます。 ランダム性ジェネレータプールを空にすることを防止するためのものです。

F.25.6. 注釈

F.25.6.1. 構築

pgcrypto は自身で主PostgreSQLの configure スクリプトの検出結果に従って構築します。 構築に影響するオプションは --with-zlib --with-openssl です。

ZLIB付きでコンパイルされた場合、PGP暗号化関数は暗号化前にデータを圧縮することができます。

OpenSSL付きでコンパイルされた場合、より多くのアルゴリズムが利用できるようになります。 また、OpenSSLがより最適化されたBIGNUM関数を持つため、公開キー暗号化関数は高速になります。

表 F-18. OpenSSLの有無による機能のまとめ

機能 組込み OpenSSL付き
MD5
SHA1
SHA224/256/384/512 ○(注1)
この他のダイジェストアルゴリズム × ○(注2)
Blowfish
AES ○(注3)
DES/3DES/CAST5 ×
暗号化そのもの
PGP対称暗号化
PGP公開キー暗号化

  1. SHA2はOpenSSLバージョン0.9.8から含まれています。 これより古いバージョンでは、 pgcrypto は組込みのコードを使用します。

  2. OpenSSLがサポートする任意のダイジェストアルゴリズムが自動的に選択されます。 これは、明示的にサポートされなければならない暗号では使用できません。

  3. AESはOpenSSLバージョン0.9.7から含まれています。 これより古いバージョンでは、 pgcrypto は組込みのコードを使用します。

F.25.6.2. NULLの扱い

標準SQLの通り、引数のいずれかがNULLの場合、すべての関数はNULLを返します。 注意せずに使用すると、これがセキュリティ上の問題になるかもしれません。

F.25.6.3. セキュリティ上の制限

pgcrypto の関数はすべてデータベースサーバ内部で実行されます。 これは、 pgcrypto とクライアントアプリケーションとの間でやり取りされるデータはすべて平文であることを意味します。 したがって、以下を行う必要があります。

  1. ローカルまたはSSL接続で接続

  2. システム管理者およびデータベース管理者を信頼

これらが不可能であれば、クライアントアプリケーション内で暗号化する方が望まれます。

F.25.6.4. 有用な文書

F.25.6.5. 技術的な参考情報

F.25.7. 作者

Marko Kreen

pgcrypto は以下のソースを使用しています。

アルゴリズム

作者

元ソース

DES crypt David Burren他 FreeBSD libcrypt
MD5 crypt Poul-Henning Kamp FreeBSD libcrypt
Blowfish crypt Solar Designer www.openwall.com
Blowfish cipher Simon Tatham PuTTY
Rijndael cipher Brian Gladman OpenBSD sys/crypto
MD5ハッシュとSHA1 WIDE Project KAME kame/sys/crypto
SHA256/384/512 Aaron D. Gifford OpenBSD sys/crypto
BIGNUM math Michael J. Fromberger dartmouth.edu/~sting/sw/imath


powered by SEO.CUG.NET