自分だけのクイズ作成 - Quipha公開中

【JavaScript】AES暗号・復号【CryptoJS】

JavaScript
スポンサーリンク

はじめに

今回はJavaScriptを使って、AESで暗号化・復号を行います。
AESキーは、任意のパスフレーズをもとに生成します。

パスフレーズで暗号・復号を行うことにより、実戦的に使えると思います。
是非、参考にしてみてください。

使用するバージョンなど
  • JavaScript
  • CryptoJS 4.1.1

Evernoteのテキスト暗号化

Evernoteにはテキスト暗号化機能があり、AESで暗号化を行っています。
その仕組みや実際のソースコードについては、以下の記事で解説していますので参考にしてみてください。

スポンサーリンク

暗号化の仕組み

今回はAES暗号化します。

Advanced Encryption Standard (AES) は、アメリカが2001年に標準暗号として定めた共通鍵暗号アルゴリズムである。アメリカ国立標準技術研究所(NIST)が公募し、Rijndael(ラインダール)がAESとして採用された。

https://ja.wikipedia.org/wiki/Advanced_Encryption_Standard

Evernoteの仕組みも同じですが、今回は以下のように暗号化・復号を行う実装をします。

  • 任意のパスフレーズをもとに、PBKDF2を利用しAESキーを生成します。
  • ソルトとHMAC/SHA-256 ハッシュ関数を 50,000 回通して生成します。(反復回数)
  • AESキーを使い、AESで暗号化・復号を行います。

反復回数は多い方が暗号化に時間がかかりますが、復号にも時間がかかりブルートフォース攻撃の対策にもなります。
また、PBKDF2は並列処理に弱いとされていますが、対策としてArgon2などがあり、必要に応じて選択しましょう。

また暗号化を行う際に、毎回同じ値にならないように対応します。
(ソルト・初期ベクトル)

安全でない暗号化の修正 - Google ヘルプ
この情報は、安全でない暗号化パターンが含まれているアプリのデベロッパーを対象としています。該当するアプリは、暗号テキストの生成に使わ

実装

CryptoJS

JavaScriptで暗号・復号しますが、ライブラリにCryptoJSを使用します。

CryptoJS - CryptoJS
Original documentation:

CryptoJSは、PBKDF2やAESの処理を行うことができます。

暗号化

CryptoJSをCDNを使って読み込みます。

    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/core.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/enc-base64.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/cipher-core.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/sha256.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/sha1.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/aes.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/hmac.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/pbkdf2.min.js"></script>

ソルトと初期ベクトルをランダムに生成します。

      // ソルト
      const salt = CryptoJS.lib.WordArray.random(128 / 8);

      // 初期ベクトル
      const iv = CryptoJS.lib.WordArray.random(128 / 8);

PBKDF2を使用して、AESキーを生成します。

      const passPhrase = "password123";
...
      // AESキーの生成(128bit、5万回)
      const key = CryptoJS.PBKDF2(passPhrase, salt, {
        keySize: 128 / 32,
        iterations: 50000,
        hasher: CryptoJS.algo.SHA256,
      });

ソルトとパスフレーズをもとに、AESキーを生成します。
ソルトを使用することにより、毎回違う値を生成することができます。
反復回数は5万回に設定しましたが、任意です。

生成したAESキーを使い、AES(128bit)で暗号化します。

      // AESキーで暗号化
      const encrypted = CryptoJS.AES.encrypt(targetText, key, {
        iv: iv,
      });

      // 暗号化されたテキスト
      console.log(encrypted.toString());

暗号化されたテキストは以下のように表示されました。

f/1TkgxPBqfG02a3Ua/a0NWUoMiQfwyUd0km9jEuD4quuwcvloHuyIRAeXuF23ESgtH3ywSL5pv0gwQlvEdvIg==

実行する度に値が変わることを確認しましょう。

復号

今度は復号を行います。
復号するためには、暗号化する際に使用した以下の情報が必要です。

  • パスフレーズ
  • ソルト
  • 初期ベクトル
  • 反復回数
  • 暗号化された情報

パスフレーズは非公開である必要があります。

AESキーの生成は暗号化と同じで、パスフレーズをもとに行います。

      const passPhrase = "password123";
...
      // AESキーの生成(128bit、5万回)
      const key = CryptoJS.PBKDF2(passPhrase, salt, {
        keySize: 128 / 32,
        iterations: 50000,
        hasher: CryptoJS.algo.SHA256,
      });

AESキーと初期ベクトルを使い、復号できます。

      // AESキーで復号
      const decrypted = CryptoJS.AES.decrypt(encrypted, key, {
        iv: iv,
      });

全容

暗号と復号の処理を分けて実装しました。
ポイントなのは、暗号化に使用した情報をもとに復号する必要があります。

<html>
  <head>
    <meta charset="utf-8" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/core.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/enc-base64.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/cipher-core.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/sha256.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/sha1.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/aes.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/hmac.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/pbkdf2.min.js"></script>

    <script>
      // 暗号化
      function encrypt(text, pass) {
        // ソルト
        const salt = CryptoJS.lib.WordArray.random(128 / 8);

        // 初期ベクトル
        const iv = CryptoJS.lib.WordArray.random(128 / 8);

        // AESキーの生成(128bit、5万回)
        const key = CryptoJS.PBKDF2(pass, salt, {
          keySize: 128 / 32,
          iterations: 50000,
          hasher: CryptoJS.algo.SHA256,
        });

        // AESキーで暗号化
        const encrypted = CryptoJS.AES.encrypt(text, key, {
          iv: iv,
        });

        return {
          salt: salt,
          iv: iv,
          encrypted: encrypted,
        };
      }

      // 復号
      function decrypt(encryptedData, pass) {
        // AESキーの生成(128bit、5万回)
        const key = CryptoJS.PBKDF2(pass, encryptedData.salt, {
          keySize: 128 / 32,
          iterations: 50000,
          hasher: CryptoJS.algo.SHA256,
        });

        // AESキーで復号
        const decrypted = CryptoJS.AES.decrypt(encryptedData.encrypted, key, {
          iv: encryptedData.iv,
        });

        return decrypted.toString(CryptoJS.enc.Utf8);
      }

      const targetText = "暗号化したいテキスト";
      const passPhrase = "password123";

      // 暗号化
      const encryptedData = encrypt(targetText, passPhrase);

      // 復号
      const decrypted = decrypt(encryptedData, passPhrase);

      // 復号されたテキスト
      console.log(decrypted.toString(CryptoJS.enc.Utf8));
    </script>
  </head>
  <body></body>
</html>

テキストをパスフレーズで暗号化しています。
また、暗号化された情報とパスフレーズで復号しています。

TXT-Crypter

今回解説した仕組みと同じですが、暗号・復号を簡単に行うことができるサービスを作成しました。

TXT-Crypter
簡単にテキストを暗号・復号でき、秘密情報を守ります

パスワードなど、見られたくない情報を手軽に暗号・復号することができます。
パスフレーズをもとに暗号化し、URLを生成します。
そのURLにアクセスし、パスフレーズを入力することによりいつでも復号できます。

Notionを使ってパスワード管理を行う例は、以下の記事を参考にしてください。

さいごに

今回はJavaScriptを使って、AESで暗号化・復号を行いました。
暗号・復号の仕組みについて参考にしてみてください。

\オススメ/

コメント

タイトルとURLをコピーしました