ハッシュと暗号化・復号化について

## 概要
ハッシュ・暗号化・復号化について、調べた内容を忘れないようにメモしておく。

## やり方
大きく分けて以下の２つの方法があると思われる。

- アプリ側で暗号化・復号化
- データベース側で暗号化・復号化

どちらでも一長一短ありそう。
ここではデータベース側で管理する方法を調べてみる。

## ツールの選定

PostgreSQLの場合、pgcryptoというものがあり、PostgreSQL9.1以降であれば、
スーパーユーザー権限を持つユーザーで、下記SQLにてインストールできるようです。

```sql:psqlコンソール
postgres=# CREATE EXTENSION pgcrypto;
```

## パスワードハッシュ化関数

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

### crypt関数

```sql
crypt(password text, salt text) returns text
```

**サポートするアルゴリズム**

| アルゴリズム      |  パスワード最大長  |    ソルトビット長    |        説明        |
|:-----------------|------------------:|-------------------:|:-------------------|
| bf               |                72 |                128 |Blowfishベース、2a版 |
| md5              |            無制限 |                  48 |MD5ベースの暗号      |
| xdes             |                 8 |                 24 |拡張DES             |
| des              |                 8 |                 12 |元来のUNIX crypt     |

**パスワード登録**

```sql
INSERT ... VALUES (..., pwd = crypt('default password', gen_salt('md5'), ...);
```

**パスワード更新**

```sql
UPDATE ... SET pwd = crypt('new password', gen_salt('md5'));
```

### gen_salt関数

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

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

※ iter_countパラメータを使用して繰り返し回数を指定できます。
※ 指定する回数を高くすれば、破るための時間も長くなります。
　しかし、多くの回数を指定するとハッシュ計算に数年かかってしまう可能性あり
　( 省略した場合、デフォルトの繰り返し回数が使用される )

## 暗号化そのものを行う関数

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

- 暗号キーとしてユーザキーをそのまま使用
- 暗号化されたデータが変更されたかどうかを確認するための整合性検査をまったく提供しない
- ユーザが、IVをも含め暗号化パラメータ自体をすべて管理していることを想定
- テキストは扱わない

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

### 暗号化 ( encrypt )

```sql
encrypt(data bytea, key bytea, type text) returns bytea
```

### 復号化 ( decrypt )

```sql
decrypt(data bytea, key bytea, type text) returns bytea
```

## PGP暗号化関数 ( 対称PGP )

対称PGP（pgp_sym_encrypt、pgp_sym_decrypt)を使って特定のカラムを暗号化する

### 暗号化 (pgp_sym_encrypt)

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

### 復号化 (pgp_sym_decrypt)

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

## PGP暗号化関数 ( 公開キーと秘密キー )

公開キーと秘密キーを使った暗号化・復号化の仕組みを提供する

### 暗号化 ( pgp_pub_encrypt )

公開PGPキーkeyでdataを暗号化します。

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

### 復号化 ( pgp_pub_decrypt )

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

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

など

## 参考サイト (PostgreSQL)
- [PostgreSQL 9.1.5文書 - 17.8.暗号化オプション](https://www.postgresql.jp/document/9.1/html/encryption-options.html)
- [Let's Postgres - pgcrypto](https://lets.postgresql.jp/documents/technical/contrib/pgcrypto)
- [一行入魂 - PostgreSQLでパスワードをハッシュで保存](http://aoyagikouhei.blog8.fc2.com/blog-entry-182.html)
- [PowerGres - 第3回 データを暗号化してみよう](https://powergres.sraoss.co.jp/s/ja/tech/exp/plusv91/03_tde.php#pgcrypto-about)

## 参考サイト (GnuPG)
- [1分でわかるPGP](http://www.wakayama-u.ac.jp/~takehiko/pgp.html)
- [GnuPG で遊ぶ - 暗号化してみる](http://blog.eiel.info/blog/2013/07/31/gpg/)
- [RDS for PostgreSQLでデータを暗号化する](http://dev.classmethod.jp/cloud/aws/data-encryption-on-rds-for-postgresql/)

## 参考サイト
- [ハッシュとソルト、ストレッチングを正しく理解する：本当は怖いパスワードの話](http://www.atmarkit.co.jp/ait/articles/1110/06/news154.html)
- [レインボーテーブルを使ったハッシュの復号とSalt](http://sssslide.com/www.slideshare.net/h13i32maru/salt-6671675)
- [データベースの暗号化、もしくはパスワードの保存方法のまとめ](http://d.hatena.ne.jp/nekoruri/20110430/passwordhash)