はじめに
Evernoteには、テキストを暗号化する機能があります。
今回は暗号化された情報を、JavaScriptとPythonで復号してみます。
Evernoteの暗号化の仕組みを知りながら、暗号・復号について学びましょう。
テキスト暗号化
Evernoteには、一部のテキストを暗号化する機能があります。
使い方は簡単で、暗号化したいテキストを選択し、右クリックメニューから「選択したテキストを暗号化」をクリックします。
パスフレーズを入力することにより、暗号化できます。
これで暗号化は完了です。
パスフレーズを知られない限り、暗号化したテキストを表示することができません。
復号する際は以下のように「暗号化されたコンテンツを表示」をクリックし、正しいパスフレーズを入力することにより表示できます。
Evernoteのテキスト暗号化の仕組み
Evernoteのテキスト暗号化の仕組みは以下の記事に記載してあります。
AES-128bitで暗号化されています。
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を使用します。
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,
});
AESキーが生成できますので、復号を行います。
// AESキーで復号
const decrypted = CryptoJS.AES.decrypt({ ciphertext: ciphertext }, key, {
iv: iv,
});
以下がソースコードの全容です。
<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>
ブラウザで開き、開発ツールで確認してみましょう。
復号された情報が表示されました。
Pythonで復号
Pythonでも同じように復号することができます。
AESを使うためにPyCryptodomeを使用します。
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による暗号・復号は、以下の記事でも解説していますので参考にしてください。
Notionを使った暗号化
Notionそのものにはテキスト暗号化の仕組みはありません。
私が作成したTXT-Crypterを利用すると、同様のことができます。
Notionを使ってパスワード管理を行う例は、以下の記事を参考にしてください。
さいごに
今回はEvernoteの暗号化されたテキストを、プログラミングで復号してみました。
暗号・復号の仕組みについて参考にしてみてください。
コメント