web-dev-qa-db-ja.com

明白な方法で文字列を匿名化する暗号アルゴリズム?

NB:私は最初にこれをSO( link )に投稿しましたが、Cryptoに関する既存の質問があるので、Security SEがより適切であることを理解します-PAn、これはここに似ています

匿名化したいデータベースクエリのログファイルがあります。これらはクライアントから取得され、外部で分析されます。クライアントは、これらを識別情報を保護するのに十分匿名化し、それでも有用な分析を可能にするのに十分なままにしたいと考えています。

一部の行にはIPアドレス(ソースIPなど)が含まれている可能性があります- Crypto-PAn のようなものを使用してそれらを匿名化できると思います。私の理解では、この匿名化は単射(1:1)であり、反復可能ですが、不可逆的でもあります。

同様に、行にはフィールドと値を含めることもできます。 { "name.first": "John" }

値については、まっすぐなMD5(または内容が類似)を使用するだけで満足です。それらが何であるかを確認することはそれほど重要ではありません。

ただし、データベースフィールドについては、人間が読める形式でこれらを保持したいと考えています。これは、これらのフィールドに基づいてパフォーマンス分析を行うためです(たとえば、フィールドごとにクエリをグループ化するなど)。

たとえば、name.firstTree.Blackboardになる可能性があります。

制約は次のとおりです。

  • 各入力Wordは1つのハッシュにマップする必要があり、その逆も同様です(衝突が発生することは理解していますが、十分にまれであることを願っています)。
  • 繰り返し可能-複数のログファイルがある場合、毎回同じハッシュを生成したい-これにより、ログファイル間で比較できるようになります。
  • 元に戻せない-理想的には、ハッシュを元に戻して元のフィールド名を取得する簡単な方法はないはずです。
  • 人間が読み取り可能-ハッシュは人間が読み取り可能/発音可能である必要がありますが、必ずしも有効な英語の単語である必要はありません(例:Flertiは受け入れられ、037751d79d1ebfdd0664b2c66b8d66d1は受け入れられません)

私は同僚と話し合いました、そして私たちが考えた一つの方法は:

  • フィールド名を取得し、それを標準の一方向ハッシュ(MD5など)に渡します。
  • 結果のハッシュから十分な下位ビットを取得して、英語の単語の辞書にマッピングします(例:1,000,000の有効な単語)。これらのビットに相当する整数を使用し、modを実行してその辞書のWordにインデックスを付けます。

つまり、単語は読みやすく、かつ常に一貫性があります(辞書が同じままであると仮定した場合)。

辞書攻撃を心配している人がいる場合(つまり、フィールド名「firstname」は常に「Blackboard」とマップされます)、その人はハッシュをソルトするために使用される独自の特定のキーファイルを持つことができます。これは、匿名化されたログファイルについては繰り返し可能であることを意味します(つまり、「firstname」は常に「Billion」にマップされる可能性があります)が、他のキーファイルを使用する他の人々とは同じではありません。

質問1-いくつかの発音可能/読み取り可能な方法で文字列を匿名化するために使用できる既存の暗号化アルゴリズム(Crypto-PAnに類似)はすでにありますか?

質問2-そうでない場合、上記の単純化したアプローチに明白な穴がありますか?

7
victorhooi

音節ハッシュを試してみてください。

個々のデータ識別子をダイジェストする基本的なハッシュアルゴリズムから始めます。それは本当に暗号強度である必要はありません、そして私はお勧めしません。ほとんどの実装は、完璧なバイト配列を生成します。いくつかは、単一の大きなプリミティブまたは大きなプリミティブの配列を生成します。その場合、それらをバイトに分割する必要があります。

次に、単純な子音と値のペア(Ba、Be、Bi、Bo、Bu、Cha、Che、Chi、Cho、Chu、Da、De、Di、Do、Duなど)にマップされる可能なバイト値のルックアップを検索または作成します)。音節の順序とバイト値へのマッピングは関係ありません。ハッシュは操作の不可逆部分であり、音節マッピングではありません。 256しか取得しないことを覚えておいてください。安全なハッシュを使用する場合は、音節(ハイフン、または前の音節の母音に追加されてディプトンを作成する母音)を追加せずに情報を追加するいくつかのマッピングを含めることも賢明かもしれません。ダイグラフ)。

FNV-1やMurmurのような基本的な32ビットチェックサムハッシュを使用すると、2〜4音節の範囲で一見ランダムな構造の単語が得られ、平均的な傾向が高くなります(特に、認識可能な単一音節の単語がほとんど存在しない可能性があります)先頭のゼロがバイト配列のインライン化されたゼロまたは末尾のゼロと同じように扱われる場合)。暗号ハッシュを使用する場合、SHA-1のようなものが10音節の単語を提供するため、おそらくバイトをXOR折りたたむ必要があります。これが私が暗号ハッシュに対して推奨する理由です。

おそらく別の現実の日本語のように聞こえるかもしれませんが、結果の識別子を発音できます。より英語に似せるには、 this one のような、最も一般的な英語の音節のリストから始めます。ただし、このリストにはWordのルートのプレフィックスまたはサフィックスであるため、一般的な音節が含まれますが、Wordのランダムな場所に挿入されます。

4
KeithS

何を達成しようとしていますか?コンテンツを危険にさらすことなく外部のQAテストチームに安全に提供できるように、機密データでデータベースを匿名化しますか?この場合、データの残りの部分にもデータの所有者に結論を導き出すことのできるフットプリントがあるため、個人名と会社名を匿名化するだけでは不十分です。また、各データはハッシュにマッピングする必要があり、その逆も同様ですが、元に戻せないようにする必要があります。これは矛盾しており、両方を達成することはできません。

アルゴリズムについては、PGPがフィンガープリントを作成する方法を見てください。それらは発音可能でハッシュであり、英語の単語のシーケンスで構成されています。

ハッシュ関数自体は元に戻せませんが、ハッシュを使用すると、このハッシュに属するレコードを一意に識別できます。

PGPのオープンソースクローンが利用できるので、ソースコードを入手できるはずです。

ハッシュの代わりに、次のようなアルゴリズムによって生成されたランダムな文字列で埋めるフィールドを追加できます。

void Main()
{
    MakeRandomString(4).Dump();
}


private string MakeRandomString(int n)  
{  
    var bits = new List<string>()  
    {  
            "na",  "bla",  "chee",  "dee",  "ay",              
            "tree", "th",  "goo",  "foo",              
            "ook",  "ta",  "bee",              
            "Zoo",  "ai",  "kawee",  "jam",  "ya"            
    };  

    StringBuilder sb = new StringBuilder();  
    Random r = new Random();  
    for (int i = 0; i < n; i++)  
    {  
        sb.Append(bits[r.Next(bits.Count)]);  
    }  

    return sb.ToString();  
}  

これにより、次のようなランダムなファンタジーの単語が作成されます。

cheekaweefoobla
yataaitree
deetreenana

here から少し変更したコードです。エクスポートの場合は、そのフィールドを参照として使用できます。元の行をマップできます。暗号化ランダムジェネレーターを使用して、上記のコードを改善できます。

2
Matt