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

【Evernote】暗号化テキストを復号【JavaScript/Python】

JavaScript
スポンサーリンク

はじめに

Evernoteには、テキストを暗号化する機能があります。
今回は暗号化された情報を、JavaScriptPythonで復号してみます。

Evernoteの暗号化の仕組みを知りながら、暗号・復号について学びましょう

例えばEvernoteのノートをエクスポートし、別なノートにインポートする際、暗号化されたテキストを復号して平文に変換したいといった使い方にも応用できます。

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

テキスト暗号化

Evernoteには、一部のテキストを暗号化する機能があります。

Evernote ノート内のテキスト暗号化
Evernote でテキストの一部または全体を暗号化する方法。

例えばパスワードや、機密情報などを暗号化しておくと安全です。

使い方は簡単で、暗号化したいテキストを選択し、右クリックメニューから「選択したテキストを暗号化」をクリックします。

パスフレーズを入力することにより、暗号化できます。

これで暗号化は完了です。
パスフレーズを知られない限り、暗号化したテキストを表示することができません。

復号する際は以下のように「暗号化されたコンテンツを表示」をクリックし、正しいパスフレーズを入力することにより表示できます。

私はパスワードの管理をEvernoteで行っていたことがあり、パスワード自体は暗号化して保存していました。
もちろんEvernoteのサーバーとクライアントの通信は暗号化されていますが、ノートに平文で機密情報を保存するよりは、テキスト暗号化を利用した方が安全です。
(クライアントで暗号化し同期されるため)

スポンサーリンク

Evernoteのテキスト暗号化の仕組み

Evernoteのテキスト暗号化の仕組みは以下の記事に記載してあります。
AES-128bitで暗号化されています。

Security check

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

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

AESキーの生成にはパスフレーズをもとに、PBKDF2を利用しソルトでHMAC/SHA-256 ハッシュ関数を 50,000 回通して行われます。
生成されたAESキーで暗号化を行っています。

暗号化されているテキストはどのように保存されているか確認しましょう。
ノートをエクスポートして確認します。

エディタで開いてみると、「en-crypt」タグ部分が暗号化されたテキストなのが分かります。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE en-export SYSTEM "http://xml.evernote.com/pub/evernote-export4.dtd">
<en-export export-date="20230204T051520Z" application="Evernote" version="10.49.4">
  <note>
    <title>無題のノート</title>
    <created>20230104T045120Z</created>
    <updated>20230104T051504Z</updated>
    <note-attributes>
      <author>XXXX</author>
    </note-attributes>
    <content>
      <![CDATA[<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd"><en-note><div><br /></div><en-crypt cipher="AES" length="128">RU5DMGJB7kWEtOaNC742Ob6mQr2Ktr/ztfba/yzwYgzH+OtfoBiHRwdjr9RdqNkkp5x5Z5aNGPENo1cUbGnKcJRUkS8zDdNaT2v5kFAeish8YjTmI5BEeJBQWwZqpGPTBFAI6xLpcqmNulq+rQ8V84/RbpdtiQggwx990jiwSaWi+AUY</en-crypt><div><br /></div></en-note>      ]]>
    </content>
  </note>
</en-export>

暗号化情報を抜き出してみました。

RU5DMGJB7kWEtOaNC742Ob6mQr2Ktr/ztfba/yzwYgzH+OtfoBiHRwdjr9RdqNkkp5x5Z5aNGPENo1cUbGnKcJRUkS8zDdNaT2v5kFAeish8YjTmI5BEeJBQWwZqpGPTBFAI6xLpcqmNulq+rQ8V84/RbpdtiQggwx990jiwSaWi+AUY

JavaScriptで復号

ここまで、Evernoteの暗号化の仕組みを解説しました。
本当にその通りの暗号化が行われているのかどうか、実際に復号して確認してみましょう。

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

CryptoJS - CryptoJS
Original documentation:

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

JavaScriptによる暗号・復号は、以下の記事でも解説していますので参考にしてください。

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>

暗号化された文字列は、Base64でエンコードされているため、デコードを行います。

encText = "RU5DMGJB7kWEtOaNC742Ob6mQr2Ktr/ztfba/yzwYgzH+OtfoBiHRwdjr9RdqNkkp5x5Z5aNGPENo1cUbGnKcJRUkS8zDdNaT2v5kFAeish8YjTmI5BEeJBQWwZqpGPTBFAI6xLpcqmNulq+rQ8V84/RbpdtiQggwx990jiwSaWi+AUY";

b64 = atob(encText);

暗号・復号を行うには、ソルトと初期ベクトルが必要です。
Evernoteの場合、この暗号化された情報に保持されているため、以下のように取り出します。

      // ソルト・初期ベクトル
      // バイナリをWordArrayに変換
      const salt = CryptoJS.enc.Hex.parse(binaryToHex(b64.substr(4, 16)));
      const iv = CryptoJS.enc.Hex.parse(binaryToHex(b64.substr(36, 16)));

      // 暗号化されたデータ
      let ciphertext = b64.substr(52, b64.length - 32 - 52);
      ciphertext = CryptoJS.enc.Hex.parse(binaryToHex(ciphertext));

AESキーを生成します。PBKDF2を使用し、ハッシュ関数を5万回通します

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

「password123」は入力したパスフレーズですので、適宜変更してください。

AESキーが生成できますので、復号を行います。

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

以下がソースコードの全容です。

dec.html
<html>
  <head>

    <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>
      // バイナリ文字列をHEX文字列に変換
      function binaryToHex(str) {
        const raw = str;
        let result = "";
        for (let i = 0; i < raw.length; i++) {
          const hex = raw.charCodeAt(i).toString(16);
          result += hex.length === 2 ? hex : "0" + hex;
        }
        return result.toUpperCase();
      }

      encText =
        "RU5DMGJB7kWEtOaNC742Ob6mQr2Ktr/ztfba/yzwYgzH+OtfoBiHRwdjr9RdqNkkp5x5Z5aNGPENo1cUbGnKcJRUkS8zDdNaT2v5kFAeish8YjTmI5BEeJBQWwZqpGPTBFAI6xLpcqmNulq+rQ8V84/RbpdtiQggwx990jiwSaWi+AUY";

      b64 = atob(encText);

      // ソルト・初期ベクトル
      // バイナリをWordArrayに変換
      const salt = CryptoJS.enc.Hex.parse(binaryToHex(b64.substr(4, 16)));
      const iv = CryptoJS.enc.Hex.parse(binaryToHex(b64.substr(36, 16)));

      // 暗号化されたデータ
      let ciphertext = b64.substr(52, b64.length - 32 - 52);
      ciphertext = CryptoJS.enc.Hex.parse(binaryToHex(ciphertext));

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

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

      console.log(decrypted.toString(CryptoJS.enc.Utf8));
    </script>
  </head>
  <body></body>
</html>

ブラウザで開き、開発ツールで確認してみましょう。
復号された情報が表示されました。

これでEvernoteが公開している情報が正しいことが確認できました。

Pythonで復号

Pythonでも同じように復号することができます。

AESを使うためにPyCryptodomeを使用します。

Welcome to PyCryptodome’s documentation — PyCryptodome 3.15.0 documentation

pipコマンドでインストールします。

pip install pycryptodome

要領はJavaScriptと同様ですので、ここではソースコードの全容を掲載します。

import base64
from Crypto.Cipher import AES
from hashlib import pbkdf2_hmac

keyLen = 128
iterations = 50000

encText = "RU5DMGJB7kWEtOaNC742Ob6mQr2Ktr/ztfba/yzwYgzH+OtfoBiHRwdjr9RdqNkkp5x5Z5aNGPENo1cUbGnKcJRUkS8zDdNaT2v5kFAeish8YjTmI5BEeJBQWwZqpGPTBFAI6xLpcqmNulq+rQ8V84/RbpdtiQggwx990jiwSaWi+AUY"
b64 = base64.b64decode(encText)

salt = b64[4:20]
iv = b64[36:52]
cipherText = b64[52:-32]

key = pbkdf2_hmac('sha256', b'password123', salt, iterations, int(keyLen / 8))

aes = AES.new(key, AES.MODE_CBC, iv)
plaintext = aes.decrypt(cipherText)
print(plaintext.decode(encoding='utf-8'))

実行してみると、以下のように復号された情報が取得できました。

<div>テキストを暗号化します</div>

Pythonによる暗号・復号は、以下の記事でも解説していますので参考にしてください。

暗号化の仕組みが分かれば、JavaScriptでもPythonでも同様に復号できます。

Notionを使った暗号化

Notionそのものにはテキスト暗号化の仕組みはありません

私が作成したTXT-Crypterを利用すると、同様のことができます。

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

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

さいごに

今回はEvernoteの暗号化されたテキストを、プログラミングで復号してみました。
暗号・復号の仕組みについて参考にしてみてください。

\オススメ/

コメント

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