これは興味深いオンライン チャット サービスで、メッセージをキーで暗号化できるため、同じキーを持つ人だけがメッセージを読むことができます。このサービスの興味深い点 (私の意見では) は、使用しているキー以外のキーを使用して暗号化されたテキストが、大量の不要な暗号テキストではなく、単に「[encrypted]」と表示されるという事実です。私の質問は、Python で、特定のテキストが暗号テキストかどうかを判断する良い方法はありますか? この例では RC4 を使用しています。これは、実装できる最速のものだったからです ( Wikipediaの疑似コードに基づいています。ありがとう。
3 に答える
確実な方法はありませんが、実際には次の 2 つのことを行うことができます。
多くの非ASCII文字をチェックしてください(人々が英語のテキストを送信することを期待している場合).
値の分布を確認します。通常のテキストでは、一部の文字が他の文字よりもはるかに一般的です。しかし、暗号化されたテキストでは、すべての文字の可能性がほぼ等しくなります。
後者を行う簡単な方法は、任意の文字が (N/256) + 5 * sqrt(N/256) 回 (合計 N 文字) を超えて出現するかどうかを確認することです。この場合、それはおそらく自然言語です。 (暗号化されていません)。
Pythonで(上記のロジックを逆にして、暗号化されたときに「true」を返します):
def encrypted(text):
scores = defaultdict(lambda: 0)
for letter in text: scores[letter] += 1
largest = max(scores.values())
average = len(text) / 256.0
return largest < average + 5 * sqrt(average)
数学は、平均に等しい分散を持つ、平均の周りのガウス分布である平均数から得られます-それは完全ではありませんが、おそらく十分に近いです. デフォルトでは(少量のテキストで、信頼できない場合)、これはfalseを返します(申し訳ありませんが、以前は、小さな数値のロジックが間違った方法である「max()」を使用した誤ったバージョンがありました)。
その名前に値するすべての暗号は、完全にランダムに見える出力を生成します。この事実を利用して、暗号化されたテキストを扱っているのか、未知のプロトコルに従うデータを扱っているのかを簡単にテストできます。データが暗号化されている場合、盗聴できるバイト ストリーム内のバイト値の分布を確認できます。すべての値が均一に分布している場合は、暗号化されたテキストを扱っている可能性が高くなります。
決定にますます自信を持たせるために、バイトのペアまたはトリプレットの分布などを分析するなど、テストをより洗練されたものに広げることができます。
一方、関心のある特定の言語のディグラムとトライグラムに関する統計データを、観察したデータの出現と比較することもできます (こちらも参照)。データが同様に動作する場合は、プレーン テキストを観察している可能性が高くなります。
見分ける 1 つの方法は、パディングです。メッセージの末尾に標準パディングを追加します。復号化されたメッセージが標準のパディングで終わらない場合は、間違ったキーで復号化されています。逆は保証されていませんが、多くの場合真です。