AES-256-CBC

AES-256-CBCでは、暗号化と復号する際に以下が必要になる。

  • 256 bitの秘密のkey
  • 16 bitのiv(初期化ベクトル, initialization vector. 暗号化対象ごとに変える)

秘密のkey

AES-256-CBCではkeyは同じ256 bitである必要がある。

256 bit / 8 = 32 byte -> 32文字のランダムな英数字を用意すればいい。ハイフンなしのUUIDで用意するのが簡単。

$ python3 -c 'import uuid; print(uuid.uuid4().hex)'
e61454eb27a145019a5f9696c912ad62

iv

AES-256-CBCではivは16 bitである必要がある。

crypto.randomBytes(16)でランダムなivを取得できる。

Node.jsのCryptoを使った実装サンプル

処理概要

Cipherを使って引数に渡したUTF-8文字列を暗号化する。暗号化したバイナリはBASE64で文字列にエンコードし、同じくBASE64でエンコードしたivと任意の区切り文字($)で繋ぎ合わせてDBに保存する。

後日、DBから取得したデータ([iv]$[暗号化データ])を$で区切り、ivと暗号化データに分割して、Decipherを使って復号する。

※DBアクセスコードは実際には省略する

コード

環境: Node.js v16.13.1

import crypto from 'crypto'

// 秘匿情報のため本来はプログラム上にベタがきしてはいけないもの
const key = 'e61454eb27a145019a5f9696c912ad62';

const algorithm = 'aes-256-cbc';
const delimiter = '$';

const encode = (originalText) => {
    const iv = crypto.randomBytes(16);
    const cipher = crypto.createCipheriv(algorithm, key, iv);
    const encrypted = cipher.update(originalText, 'utf8', 'base64') +
                      cipher.final('base64');
    const ivWithEncrypted = iv.toString('base64') + delimiter + encrypted;
    return ivWithEncrypted;
}

const decrypt = (ivWithEncrypted) => {
    const [iv, encrypted] = ivWithEncrypted.split(delimiter);
    const decipher = crypto.createDecipheriv(algorithm, key, Buffer.from(iv, 'base64'));
    const decrypted = decipher.update(encrypted, 'base64', 'utf8') +
                      decipher.final('utf8');
    return decrypted;
}


const email = '[email protected]';
const emailEncrypted = encode(email);
// emailEncryptedをDBに保存して処理終了
console.log(emailEncrypted);

// 後日、emailEncryptedをDBから取得して、復号する
console.log(decrypt(emailEncrypted));

以上のファイルをcrypto.mjsとすると、node crypto.mjsで実行した結果は以下のようになる。1行目は毎回変わる。

$ node crypto.mjs
8+ZWyRdlpkpQVqdKY3g6pw==$qd5wGkj/nGLRNa77HQM5IWixdiMxw4sHcRMrzBCaQHw=
[email protected]