文字列の暗号化とバイナリの文字列化 (Oracle Database 12c)

# 文字列暗号化の結果
Oracle Databaseには暗号化に関するパッケージとしてDBMS_CRYPTOが提供されています。このパッケージは各種のメソッドを使った暗号化やハッシュ化を行うファンクションが提供されています。
DBMS_CRYPTOパッケージには以下のパッケージが提供されています。

|サブプログラム名| 説明　|
|:---|:---|
|DECRYPT|複号を行う|
|ENCRYPT|暗号化を行う|
|HASH|ハッシュ値を計算する|
|MAC|秘密鍵を使用したハッシュを計算する|
|RANDOMBYTES|疑似乱数を使ったバイト列を取得する|
|RANDOMINTEGER|疑似乱数を使った整数を取得する|
|RANDOMNUMBER|疑似乱数を使った整数を取得する|

上記の内、ENCRYPTファンクションは、入力データ／出力データ共にRAW型になります。ENCRYPTプロシージャはBLOB型またはCLOB型で、出力データはBLOB型になります。

以下は、文字列を暗号化し、RAW型として取得する例です。暗号化は以下の仕様で行います。

|項目|設定|備考
|:---|:---|:---|
|暗号化を行う文字列|東京都新宿区西新宿２丁目８−１ |
|暗号化アルゴリズム|AES 256bit | |
|暗号化鍵| 文字列12345678901234567890123456789012| 32バイト|
|初期化ベクター|なし|
|暗号連鎖|暗号ブロック連鎖|CHAIN_CBC|
|パディング|PKCS#5|PAD_PKCS5|

```
DECLARE
  srcval RAW(2000);	-- 暗号化用データ
  encval RAW(2000);	-- 暗号化結果用
  enctyp PLS_INTEGER := DBMS_CRYPTO.ENCRYPT_AES256
        + DBMS_CRYPTO.CHAIN_CBC
        + DBMS_CRYPTO.PAD_PKCS5;	-- 暗号化メソッド等
  secret VARCHAR2(100) := '東京都新宿区西新宿２丁目８-１';	-- 暗号化を行うデータ
  keyval RAW(32);
  keystr VARCHAR2(100) := '12345678901234567890123456789012';	-- 暗号化鍵
BEGIN
  srcval := UTL_I18N.STRING_TO_RAW(secret, 'AL32UTF8');	-- 暗号化対象をRAW変換
  keyval := UTL_I18N.STRING_TO_RAW(keystr, 'AL32UTF8');	-- 暗号化鍵をRAW変換

  encval := dbms_crypto.encrypt(srcval, enctyp, keyval);	-- 暗号化実行 encvalが暗号化結果(RAW)
END;
```

# RAWデータの文字列化
暗号化結果をテーブルのRAW型の列にそのまま格納することもできますが、文字列型に格納することで運用を容易にしてみます。RAWデータを文字列に変換するにはUTL_I18Nパッケージ、UTL_ENCODEパッケージ、UTL_RAWパッケージを使います。

## UTL_I18Nパッケージ
UTL_I18Nパッケージはもともとはグローバリゼーション関連に使うパッケージですが、以下のようなRAW型から文字列型への変換関数が提供されています。

|ファンクション名| 説明　|
|:---|:---|
|RAW_TO_CHAR|RAW型からVARCHAR2型に変換| 
|RAW_TO_NCHAR|RAW型からNVARCHAR2型に変換|
|STRING_TO_RAW|文字列型からRAW型に変換| 

## UTL_ENCODEパッケージ
UTL_ENCODEパッケージにはRAWデータを様々な形式にエンコード／デコードを行うプロシージャがそろっています。

|ファンクション名| 説明 |
|:---|:---|
|BASE64_DECODE|Base64形式からデコード|
|BASE64_ENCODE|Base64形式に変換|
|MIMEHEADER_DECODE|MIMEヘッダー形式からデコード|
|MIMEHEADER_ENCODE|MIMEヘッダー形式に変換|
|QUOTED_PRINTABLE_DECODE|引用符付文字列のデコード|
|QUOTED_PRINTABLE_ENCODE|引用符付文字列に変換|
|TEXT_DECODE|指定文字コード指定への変換|
|TEXT_ENCODE|データベース文字コードに変換|
|UUDECODE|uuencode形式のデコード|
|UUENCODE|uuencode形式への変換|

## UTL_RAWパッケージ
RAWを扱う専用のパッケージとしてUTL_RAWパッケージが提供されています。以下のファンクションが提供されています。

|ファンクション名| 説明 |
|:---|:---|
|CAST_FROM_*|特定のデータ型からRAW型に変換|
|CAST_TO_*|特定のデータ型をRAW型から変換|

## RAW型をBase64文字列に変換
以下の例はRAW型のデータをBase64フォーマットの文字列に変換しています。[Base64フォーマット](https://ja.wikipedia.org/wiki/Base64) はバイナリデータを英数字と少数の記号だけで表現するエンコード方式です。

```
SQL> DECLARE
  b64enc RAW(2000);	-- Base64変換されたRAW
  b64str VARCHAR2(4000); -- Base64変換されたVARCHAR2
BEGIN

  --省略--

  b64enc := UTL_ENCODE.BASE64_ENCODE(encval);	-- Base64に変換したRAW
  b64str := UTL_RAW.CAST_TO_VARCHAR2(b64enc);	-- VARCHAR2型に変換

  dbms_output.put_line('Original: ' || secret); -- 暗号化元の出力
  dbms_output.put_line('Base64: ' || b64str); -- 暗号化+Base64化した文字列の出力
END;
/

Original: '東京都新宿区西新宿２丁目８-１'
Base64: kHzozNoj1ZoGomxV/h2AVRXrBUL6g4UoR7zoAYKUMf3Bv20+56R6p+rNU886d6QJ

PL/SQLプロシージャが正常に完了しました。
```

## 復号
復号はBase64エンコードをデコードし、同一の鍵を使って元の文字列に戻します。

```
DECLARE
  b64dst RAW(2000);
  dstval RAW(2000);
  result VARCHAR2(2000);
BEGIN

  --省略--

  b64dst := UTL_ENCODE.BASE64_DECODE(b64enc);
  dstval := DBMS_CRYPTO.DECRYPT(b64dst, enctyp, keyval);
  result := UTL_I18N.RAW_TO_CHAR(dstval, 'AL32UTF8');

  DBMS_OUTPUT.PUT_LINE('Decrypted: ' || result);
END;
/

Decrypted: 東京都新宿区西新宿２丁目８-１

```