キジです。今回は、個人情報データを暗号化することについて調べたため、まとめていきます。
本記事でわかること
今回は個人情報を観点に必要な部分を記載します。本記事で、個人情報の暗号化に使うアルゴリズムや暗号化方式が理解できます。
以下の用語を抑えてください。
- 平文 ・・・ データを暗号化する前の状態、テキストのこと
- ブロック ・・・ 暗号化する単位のこと。1ブロックのサイズはアルゴリズムにより異なる。
データを暗号化するタイミング
データの暗号化には、主に3つのタイミングがあります。
- DB格納前
- DB格納後
- ストレージ格納後
「DB格納後」や「ストレージ格納後」は個人情報だけでなく、システムで利用されるデータすべてが対象になります。
上記2つも実施したほうが良いですが個人情報は、「DB格納前」にも暗号化したほうが良いです。理由はいくつかありますが、そのうちの1つが内部からデータが抜き取られることを防ぎます。
暗号化方式について
- 共通鍵方式
- 公開鍵方式
- ハッシュ化
個人情報の種類にもよりますが、主に共通鍵方式、またはハッシュ化を使用します。
共通鍵方式は暗号したテキストを複合する事ができます。そのため、名前や住所など、画面などに平分で表示する必要があるものに使われます。
一方、ハッシュ化は複合することができません。そのためパスワードなど、画面上に表示する必要がないものを暗号化します。
共通鍵方式の暗号アルゴリズムについて
共通鍵暗号方式には、主に3種類のアルゴリズムがあります。
- AES
- DES
- RC4
AESは128,192,256bitからなる鍵を用いて暗号化します。共通鍵方式でもっとも使われているアルゴリズムです。
DESは56bitからなる鍵を用いて暗号化します。ですが、今は使われていません。現在のコンピューターの計算速度では、56bitはかんたんに解読できるためです。
RC4は40~256bitの可変からなる鍵を用いて暗号化します。こちらも、今は使われていません。解読方法が公開されているそうです笑
暗号化モードについて
AESには、2つの暗号化モードというものがあります。
- ECB
- CBC
ECBはデータと鍵の2つを使ってブロック単位に暗号化します。鍵とデータが同じである場合、必ず同じ結果となるため、解読されやすい暗号化モードと言えます。
CBCはデータ、鍵の他に初期化ベクトル(IV)を用意します。IVはランダムな1ブロックのデータで、データを保存するたびにIVを発行します。そのため、ECBのように同じデータ、鍵を使っても、結果が異なるため、解読されにくい暗号化モードと言えます。
実践
今回はNode.jsで実際鍵を作成し、データを暗号、そして複合します。
環境・プログラム
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const crypto = require('crypto'); | |
const algorithm = 'aes-256-cbc'; // 暗号アルゴリズム AES 256bit CBCモード | |
let gek = {}; // idごとに鍵を保持する | |
let iv = {}; // idごとにivを保持する | |
const encrypt = (id, text) => { | |
if (!gek[id]) { | |
// 任意の32Byteの鍵作成 | |
gek[id] = crypto.randomBytes(32); | |
} | |
// 任意の16Byte(1ブロック)の初期ベクトルの作成(毎回新しく作る) | |
iv[id] = crypto.randomBytes(16); | |
// 暗号器を作成 | |
const cipher = crypto.createCipheriv(algorithm, gek[id], iv[id]); | |
// 暗号化したテキストを返却する utf8 to base64 | |
return cipher.update(text, 'utf8', 'base64') + cipher.final('base64'); | |
} | |
const decrypt = (id, text) => { | |
if (!gek[id] || !iv[id]) return '鍵なし'; | |
// 複合器を作成 | |
const decipher = crypto.createDecipheriv(algorithm, gek[id], iv[id]); | |
// 復号化したテキストを返却する base64 to utf8 | |
return decipher.update(text, 'base64', 'utf8') + decipher.final(); | |
} | |
let text = 'example.com'; | |
let textEncrypted = encrypt(1, text); | |
console.log(`—————————————————————-`); | |
console.log(`text => ${text}`); | |
console.log(`encrypted => ${textEncrypted}`); | |
console.log(`decrypted => ${decrypt(1, textEncrypted)}`); | |
console.log(`gek => `); | |
console.dir(Uint8Array.from(gek[1]).toString('utf-8')); | |
console.log(`iv => `); | |
console.dir(Uint8Array.from(iv[1]).toString('utf-8')); | |
console.log(`—————————————————————-`); | |
textEncrypted = encrypt(1, text); | |
console.log(`text => ${text}`); | |
console.log(`encrypted => ${textEncrypted}`); | |
console.log(`decrypted => ${decrypt(1, textEncrypted)}`); | |
console.log(`gek => `); | |
console.dir(Uint8Array.from(gek[1]).toString('utf-8')); | |
console.log(`iv => `); | |
console.dir(Uint8Array.from(iv[1]).toString('utf-8')); | |
console.log(`—————————————————————-`); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ node -v | |
v16.16.0 | |
$ npm -v | |
8.11.0 |
実行結果
解説
Node.jsには、cryptoという暗号化するためのライブラリが用意されています。こういったものは各言語に用意されているため、使用する言語が異なる場合でも処理の流れは同じになります。
暗号処理
このプログラムでは、受け取ったIDごとに、鍵(gek)を保存し再利用するようにしています。
encryptedが暗号した結果になります。この値をDBなどに保存します。
初期ベクトル(iv)は暗号処理が実行されるたびに新しく作成します。結果、鍵とデータが同じでも、1回目と2回目でencryptedが違う値になっています。
複合処理
複合処理では、暗号処理のときに使用した鍵と初期ベクトルを用いて複合機を作成し、複合します。
今回は、gek、ivといった変数ですが、実際のサービスでは、何らかの方法で永続化する必要があるため注意してください。
まとめ
- 個人情報に関するデータの暗号について記載しました
- 共通鍵方式を使って、データを保存する前に暗号化する
- アルゴリズムはAES、モードはCBCが基本
コメント