メールの暗号化

## メールの暗号化とは?
メールの本文や添付ファイルを暗号化して第三者によってメールにアクセスされないようにすること
暗号化ソフトを導入すれば、通常通りメールの送受信をするだけで自動的に暗号化されて第三者による盗聴や改ざんを防ぐ
メールの暗号化には公開鍵暗号方式と秘密鍵暗号方式の2つがある

## 公開鍵暗号方式
公開鍵暗号方式は「公開鍵」「秘密鍵」と呼ばれる2つの鍵を利用してデータのやり取りを行う方法
1. 秘密鍵を使って公開鍵を作成
2. メール相手に公開鍵を送付
3. 公開鍵を受け取った側が公開鍵を使ってメールを暗号化
4. 暗号化されたメールを受信し、公開鍵を作るときに使った秘密鍵で複合する

## 秘密鍵暗号方式
秘密鍵暗号方式は共通鍵のみでデータを暗号化・複合する

## メール暗号化方法の種類
メールの暗号化には次の2つのプロトコル(通信手順)が用いられる
– PGP・S/MIME: メールの暗号化、電子署名に使われている
– SSL・TLS: インターネット上でやり取りされる通信を暗号化する技術。SSL/TLSを使うには第三者機関が発行するサーバ証明という電子証明書が必要

### Gmailでの確認方法
Gmailでは暗号化されていないメールサーバを経由して送られてきたメールをやり取りした時に、暗号化されていないことを示すマークが表示される

### Outlookでの確認方法
Outlookでも設定を確認することができる

Basic認証の脆弱性

Basic認証では.htaccess, .htpasswdという2つのヘッダが働いている。
サーバの認証をかけたいフォルダに.htaccess, .htpasswdというファイルを作成するだけ

## Basic認証のデメリット
– サーバを跨いだ認証設定ができない
– クローラが巡回できないため、SEO対策ができない
– セキュリティレベルが高いとは言えない

## Basic認証の脆弱性
– 脆弱性が指摘される理由として、「文字コードの種類」「httpであること」が挙げられる
– Basic認証ではログイン情報を入力する際に「Base64」を平文でやり取りする 「http」通信のため、盗聴されやすい
– 公開直前の確認用Webページ、特定のメンバーとのみ共有する場合、無料サイトなどは簡易的な認証で問題ない。個人情報は含めてはいけない
– Basic認証はクローラが巡回しない

Basic認証はブラウザにID、パスワードを保存する。Base64でエンコードされているが、デコードすれば簡単に確認できる
また、ログアウト機能がない

APIの暗号化

ほとんどのAPIはREST(Representational State Transfer)またはSOAP(Simple Object Access Protocol)で実装されている
REST APIはTLS暗号化(HTTPS)をサポートする。そのため、データを読み取ることも変更することもできない
REST APIはJSONも使用する。SOAP APIよりも高速

SOAPはXML暗号化、XML署名、SAMLトークンを組み合わせて使用する

### APIセキュリティ強化の例
– トークンを使用する
– 暗号化と署名を使用する
– 脆弱性を特定する
– クオータとスロットリングを使用する
– APIゲートウェイを使用する

### API管理とセキュリティ
– APIキー
– 基本認証
– OpenID Connect

MySQLで暗号化、復号化

* AES_ENCRYPT()/ AES_DECRYPT()などの暗号化関数を使用する

CREATE TABLE IF NOT EXISTS `user` (
	`user_id` VARCHAR(100) NOT NULL,
	`password` VARBINARY(200) NOT NULL,
	PRIMARY KEY (`user_id`)
)
COMMENT='ユーザ'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=11;

INSERT INTO `user`(`user_id`,`password`) VALUES(`user1`,AES_ENCRYPT(`password1`,`ENCRYPT-KEY`));
INSERT INTO `user`(`user_id`,`password`) VALUES(`user2`,AES_ENCRYPT(`password2`,`ENCRYPT-KEY`));
INSERT INTO `user`(`user_id`,`password`) VALUES(`user2`,AES_ENCRYPT(`password3`,`ENCRYPT-KEY`));

SELECT `user_id`, AES_DECRPYPT(`password`, `ENCRYPT-KEY`) FROM `user`;

psqlの暗号化と復号

PostgreSQLの機能にpgcryptという暗号関数を提供するライブラリがある

CREATE TEMPORARY FUNCTION decrypt(_text STRING) RETURNS STRING LANGUAGE js AS
"""
	if (_text === null) {return _text}
	let base64_text = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Hex.parse(_text))
	let key = CryptJS.enc.Utf.parse('PASSWORD\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000')
	let iv = CryptoJS.enc.Utf8.parse('')
	let options = { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 };
	let _decrypt = CryptoJS.AES.decrypt(base_text, key, options);
	return _decrypt.toString(CryptoJS.enc.Utf8);
""" OPTIONS (library="gs://xxxxxxxxx/crypto-js-4.1.1/crypto-js.js");

SELECT decrypt(substring('\\xba9a0a4189f691d761c431c89f42e319', 3));

データベースの暗号化

データベース暗号化の種類
1. データベース管理システム(DBMS)による暗号化
DBMSが持つ暗号化機能を使用する方法
しかし、サーバやパソコンのメモリ上には暗号化されていないデータが一時的に残る場合があり、高度な技術があれば読み取られてしまう恐れがある

2.ストレージ(記録装置)の暗号化
データを記録するストレージ(記録装置)自体を暗号化する方法。OSやファイルシステム、ストレージが備える暗号化機能を使ってデータが書き込まれる際に自動的に暗号化し、読み取るときに同じく自動的に解読される仕組み
OSから見ると暗号化されない状態

3.データ自体の暗号化
データ自体を暗号化してからデータベースに記録する

アクセス制御を含む暗号化を考える必要がある
情報機器の紛失・盗難対策
誤操作対策
情報機器の処分時の対策

アクセス制御など複数の対策を組み合わせて実施する訳ね

暗号処理のパディングモード(パディング方式)

分割する時にブロックで綺麗に割り切れない場合は、パディングで穴埋めします。

### パディングモード
・PKCS#5 PKCS#7 : AESと組み合わせることが多い
・Optimal Asymmetric Encryption Padding(OAEP) : RSAと組み合わせることが多い。その場合はRSA-OAEPと呼ばれる

def self.encrypt(data, pass, salt)
	cipher = OpenSSL::Cipher::Cipher.new("AES-256-CBC")
	key_iv = OpenSSL::PKCS5.pbkdf2_hmac_sha1(pass, salt, 1000, cipher.key_len+cipher.iv_len)
	key = key_iv[0, cipher.key_len]
	iv = key_iv[cipher.key_len, cipher.iv_len]
	cipher.encrypt
	cipher.key = key
	cipher.iv = iv
	encryptvalue = cipher.update(data) + cipher.final
	return Base64.b64encode(encryptvalue)
end	

test_214_bytes.txt 214 bytes
test_215_bytes.txt 215 bytes
openssl rsautl -encrypt -oaep -pubin -inkey public-key.pem -in test_214_bytes.txt -out test_214_bytes.enc
openssl rsautl -encrypt -oaep -pubin -inkey public-key.pem -in test_215_bytes.txt -out test_215_bytes.enc

暗号アルゴリズム AES, DES, RC4, RSA, 楕円曲線暗号

共通鍵暗号方式には「DES」「RC4」「AES」などがある

### AES
AESは無線LANなどに用いられる暗号化アルゴリズムの一つで Advanced Encryption Standardの略で標準的に使われている。共通鍵暗号で、データの送信者と受信者が同じ暗号鍵を用いて暗号化と復号を実行する DES以上の強度を持つ。処理速度も優れている
AESは128,192, 256bitから鍵長を選んで利用可能
SubBytes, ShiftRows, MixColumns, AddRoundKeyなどの変換を行う
WPA2(無線LAN), SSL/TLS化通信(https://)、ファイルの暗号化などで使われている
WifiのWPA2, WPA3はAESを採用している

### DES/3DES
1977年にアメリカ連邦政府標準が採用した暗号アルゴリズム
DESは鍵長が短い(56bit)などの難点があった 総当たり攻撃に弱い
鍵長は56bitですが、パリティチェック用の8bitを加えて64bitとして扱う
この弱点を補うために2DES(DESを2回繰り返す112bitの鍵長)、3DES(DESを3回繰り返す、168bitだが処理に時間がかかる)が登場したが別の攻撃に弱いなどの弱点が見つかった
DESでは64bitのデータを半分(LとR)に分割し、同じような処理を繰り返す過程がある。この繰り返しの単位をラウンドと言う

### RC4(Rivest’s Cipher4)
ブロックのが長さ(鍵長)を自由に設定できるアルゴリズム
鍵の長さを40〜2048bitの間で自由に設定できる
逐次暗号化するすストリーム暗号 簡単にセキュリティを突破されてしまう
SSL3.0以前やWifiのWEPやWAPはRC4を用いている

### RSA
公開鍵暗号方式、暗号化と復号に別の鍵を使用する
「大きな数字を素因数分解するには膨大な時間がかかる」ことを利用したアルゴリズム。
安全性が高いが処理に時間がかかる

### 楕円曲線暗号
楕円曲線( y2 = x3 + ax + b で表される曲線)の数学的な特性を安全性の根拠とする暗号。「一方向の計算は容易でも、反対方向の計算は困難」な性質が使われることで、公開鍵が知られても容易に秘密鍵を割り出せない仕組み。暗号化や復号に必要な計算量が少なく、他のアルゴリズムより短い鍵で同等の強度が得られることから、活用の幅が広がっている。

### ハイブリッド暗号方式
共通鍵暗号方式と公開鍵暗号方式の特徴を組み合わせた方式
1. 受信者が公開鍵と秘密鍵を作成する
2. 送信者は通信で使用する「共通の秘密鍵」を作成する
3. 送信者は取得した受信者の公開鍵を使って「共通の秘密鍵」を暗号化し、送付する
4. 受信者は秘密鍵を使って「共通の秘密鍵」を復号する
ハイブリッド暗号方式は、共通鍵暗号方式の持つ鍵の受け渡しの課題を公開鍵暗号方式でカバーし、公開鍵暗号方式が持つ処理速度の遅さを共通鍵暗号方式でカバー

### ハッシュ化
不可逆性(元に戻せない性質)を持つ
ユーザーがパスワードを初期登録する際にハッシュ化によってパスワードが変換されハッシュ値が得られます。ログインをする際は、入力されたパスワードのハッシュ値と登録の際に保存されたハッシュ値を比較することで、ユーザーが同一であると認証できる

OpenSSLの実装

// 暗号化
openssl_encrypt($data, $method, $key, $options, $iv);

// 復号
openssl_decrypt($data, $method, $key, $options, $iv);

暗号化時は bin2hex、復号時は hex2bin を用いる

$enc_string = bin2hex(openssl_encrypt($data, $method, $key, 0, $iv));
$dec_string = openssl_decrypt(hex2bin($data), $method, $key, 0, $iv);
$key = "passphrase";
$str = "abcdef";

$encrypt = openssl_encrypt($str, 'aes-256-ecb', $key);
echo $encrypt;

echo "\n";
$decrypt = openssl_decrypt($encrypt, 'aes-256-ecb', $key);
echo $decrypt;

$ php index.php
HR6LV+jGY5iU8Rycs+Jv8g==
abcde

平文の暗号化 – 暗号処理の流れ

### 暗号化の流れ
(1)ブロック長に満たない部分をパディング方式で補完する
(2)アルゴリズムに対応したブロック長に分割する
※この時の分割ルールを決めるのが暗号利用モード
※分割モードによっては初期値が必要で、それがIV(初期ベクトル)
(3)暗号鍵を用いてアルゴリズムで暗号化
(4)分割されたデータを結合

複合化の流れ
(1)アルゴリズムに対応したブロック長に分割する
(2)暗号鍵を用いてアルゴリズムで複合化する
(3)暗号利用モードを元に分割されたデータを結合する
※分割モードによっては初期値が必要で、これがIV(初期化ベクトル)
(4)補完されたパディングをパディング方式で除去する

ブロック暗号では、ブロック長、秘密鍵、暗号アルゴリズム、暗号利用モード、パディング方式、IV(初期化ベクトル)のキーワードが重要
使用できる暗号化アルゴリズムは組み込まれているライブラリに依存
暗号利用モードにはECB, CBD, OFB, CFB
パディング方式はZeroBytePadding, パディング不要な状態であればZeroBytePaddingは何もしないのでPKCS#5 Paddingなどは独自に実装することができる。NoPaddingはできない

$ sudo apt install php-dev libmcrypt-dev php-pear
$ sudo pecl channel-update pecl.php.net
$ sudo pecl install mcrypt-1.0.1

function cipher_encrypt($input, $key){
  // 指定した暗号のブロックサイズを得る
  $size = mcrypt_get_block_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
  // PKCS5Padブロック長に満たないサイズを埋める
  $input = pkcs5_pad($input, $size);
  // 使用するアルゴリズムおよびモードのモジュールをオープンする
  $td = mcrypt_module_open(MCRYPT_BLOWFISH, '', MCRYPT_MODE_ECB, '');
  // オープンされたアルゴリズムのIVの大きさを返す
  $ivsize = mcrypt_enc_get_iv_size($td);
  // MCRYPT_RANDの初期化を行う
  srand();

  // 乱数ソースから初期化ベクトル(IV)を生成する
  // ECB以外では複合にIVが必要
  // ECBではIVは使用されないがIVがないとエラーが出る
  $iv = mcrypt_create_iv($ivsize, MCRYPT_RAND);
  // 暗号化に必要な全てのバッファを初期化
  mycrypt_generic_init($td, $key, $iv);
  // データを暗号化
  $data = mcrypt_generic($td, $input);
  // 暗号化モジュールを修了する
  mycrypt_generic_deinit($td);
  // mcryptモジュールを閉じる
  mcrypt_module_close($td);
  return $data;
}

// 複合化を行う
function cipher_decrypt($input, $key){
  // 指定した暗号のブロックサイズを得る
  $size = mcrypt_get_block_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
  // 使用するアルゴリズムおよびモジュールをオープンする
  $td = mcrypt_module_open(MCRYPT_BLOWFISH, '', MCRYPT_MODE_ECB, '');
  // オープンされたアルゴリズムのIVの大きさを返す
  $ivsize = mcrypt_enc_get_iv_size($td);
  // MCRYPT_RANDの初期化を行う
  srand();

  // 乱数ソースから初期化ベクトル(IV)を生成する
  // ECB以外では複合にIVが必要
  // ECBではIVは使用されないがIVがないとエラーが出る
  $iv = mcrypt_create_iv($ivsize, MCRYPT_RAND);
  // 暗号化に必要な全てのバッファを初期化する
  mcrypt_generic_init($td, $key, $iv);
  // データを複合する
  $data = mdecrypt_generic($td, $input);
  // 暗号化モジュールを修了
  mcrypt_generic_deinit($td);
  // mcryptモジュールを閉じる
  mcrypt_module_close($td);
  // PKCS5Padding埋められたバイト値を除く
  $data = pkcs5_unpad($data, $size);
  return $data;
}

// PKCS5Padding
// ブロック長に満たないサイズを埋める
function pkcs5_pad($text, $blocksize){
  $pad = $blocksize - (strlen($text) % $blocksize);
  return $text . str_repeat(chr($pad), $pad);
}

// PKCS5Padding
// 埋められたバイト値を除く
function pkcs5_unpad($text){
  $pad = ord($text{strlen($text)-1});
  if($pad > strlen($text)) return false;
  if(strspn($text, chr($pad), strlen($text) - $pad)!= $pad) return false;
  return substr($text, 0, -1 * $pad);
}

// 暗号化例
$data = "この文字を暗号化する";
$key = "ABCDEF";

echo "元データ:" . $data;
echo "<br>";
$encrypt = cipher_encrypt($data, $key);
echo "暗号化されたデータ:". $encrypt;
echo "<br>";
$decrypt = cipher_decrypt($encrypt,$key);
echo "複合化されたデータ:". $decrypt;

pecl/mcrypt requires PHP (version >= 7.2.0, version <= 7.3.0, excluded versions: 7.3.0), installed version is 7.4.3-4ubuntu2.18 No valid packages found install failed 仕組みはわかったけど、mcryptではなく、openssl_ecnrypt出ないと駄目やな