パスワードハッシュ関数は、入力を大きな空間から固定された集中出力にマッピングする純粋な決定論的関数です。これらの出力は通常、入力の要約と呼ばれます。たとえば、入力はこの本の序文の全テキストであり、その要約は 128 ビットの値空間からの 16 進数である可能性があります。
形式的なものを使用せずに、安全なハッシュ関数を使用する必要があります。これは、同じ要約を生成する 2 つの異なる入力を見つけることがほぼ不可能であることを意味します。ハッシュ関数はまた、不可逆であるべきです。要約だけが与えられた場合、要約を生成する入力を見つけることは不可能です。同様に、入力のわずかな変更は出力の要約に大きな変化をもたらすべきです。2 つの類似した入力は非常に異なる要約を持つべきです。ハッシュ関数はまた、入力から比較的迅速に計算されるべきであり、したがって、入力が一致するかどうかを検証し、その要約が簡単なタスクであるべきです。
ハッシュ値はブロックチェーンの完全性を維持する核心であり、プルーフ・オブ・ワークのコンセンサスメカニズムの基礎です。これらの 2 つの用途は、いくつかのページで見ることができます。
公開鍵暗号
公開鍵暗号は、多くの異なるアルゴリズムによって実現できますが、その中で最も人気のあるアルゴリズムの 1 つはリベスト - シャミール - アデルマン(より有名な名前は RSA)ですが、これは楕円曲線デジタル署名アルゴリズム(ECDSA)に依存しています。このアルゴリズムは、メッセージとその署名が与えられたときに公開鍵を復元することも可能です。
これらの 2 つの暗号学的概念を持って、私たちはついにブロックチェーンの構築方法を学び始めることができます。
ブロックチェーンは、分散型で不変の公共デジタル台帳です。私たちはブロックチェーンを分散データベースとして見ることができ、このデータベースでは、レコードが確認されると、それは永久に削除または変更されることはなく、権威機関がこのデータベースを制御することはできず、このデータベースはピアツーピアネットワーク内のすべてのノードに複製されます。実際にデータベースに保存される内容は異なる場合があります。それは通貨、資産登録、さらには実行可能なコードである可能性があります。
ブロックチェーンでは、各状態変更はトランザクションの一部です。トランザクションは、グローバルデータベース内のユーザーからの解剖的な書き込み操作と見なされ、1 つまたは複数の配列を変更する可能性があります。ネットワーク内の任意のユーザーが実行されるトランザクションを提出できます。
転送を処理する方法は、ブロックチェーンの状態伝達関係の一部であり、受信した各トランザクションを処理することによって、ブロックチェーンはある状態から別の状態に移行します。たとえば、通貨を管理するブロックチェーンは、2 つのアカウント間の通貨移転を処理する可能性があります:それは送信者の残高を減少させ、受取人の残高を同じ金額だけ増加させます。他のブロックチェーンは、トランザクションをチェーン上で作成および実行することを許可する場合さえあります。
ブロックがブロックチェーンに追加されると、それはピアツーピアネットワークを介してすべてのノードに広がります。各ノードは、ブロック内のすべてのトランザクションを再実行して、それらが有効であるかどうかを確認し、違法な変更を発見した場合はそのブロックを拒否します。これは、各トランザクションが実際にネットワーク全体で 1 バイトずつ実行されることを意味します。これにより、ブロックチェーンは完全に分散されます。なぜなら、各ノードがすべての実行中のトランザクションをチェックするからですが、これはコストがかかります:混合オーバーヘッドは、実行できるトランザクションの数を制限します。
注意:公共ブロックチェーンは、ユーザーの登録を要求しません。彼らは単に新しいキー対を作成するだけで、トランザクションに署名してネットワークに参加できますが、彼らはトランザクションを処理するためにブロックチェーンに関連付けられた通貨を持つことを要求される場合があります。
トランザクションはブロックの形式でバッチ処理され、次にそれらをリンクして実際のブロックチェーンを形成します。これらのブロックはブロックチェーンの歴史を構成し、各ブロックはその状態を変更するトランザクションのセットをパッケージ化します。各ブロック内のトランザクションの選択と順序の方法は、ブロックチェーンの合意ルールに依存し、これらのルールは後のページで見ることができます。
ブロックがブロックチェーンに追加されると、それはピアツーピアネットワークを介してすべてのノードに広がります。各ノードは、ブロック内のすべてのトランザクションを再実行して、それらが有効であるかどうかを確認し、違法な変更を発見した場合はそのブロックを拒否します。これは、各トランザクションが実際にネットワーク全体で 1 バイトずつ実行されることを意味します。これにより、ブロックチェーンは完全に分散されます。なぜなら、各ノードがすべての実行中のトランザクションをチェックするからですが、これはコストがかかります:混合オーバーヘッドは、実行できるトランザクションの数を制限します。
トランザクションはブロックの形式でバッチ処理され、次にそれらをリンクして実際のブロックチェーンを形成します。これらのブロックはブロックチェーンの歴史を構成し、各ブロックはその状態を変更するトランザクションのセットをパッケージ化します。各ブロック内のトランザクションの選択と順序の方法は、ブロックチェーンの合意ルールに依存し、これらのルールは後のページで見ることができます。
ブロックがブロックチェーンに追加されると、それはピアツーピアネットワークを介してすべてのノードに広がります。各ノードは、ブロック内のすべてのトランザクションを再実行して、それらが有効であるかどうかを確認し、違法な変更を発見した場合はそのブロックを拒否します。これは、各トランザクションが実際にネットワーク全体で 1 バイトずつ実行されることを意味します。これにより、ブロックチェーンは完全に分散されます。なぜなら、各ノードがすべての実行中のトランザクションをチェックするからですが、これはコストがかかります:混合オーバーヘッドは、実行できるトランザクションの数を制限します。
ネットワークは毎秒処理します。言い換えれば、ブロックはトランザクションの数に基づいて交換されます。
この高コストのため、ブロックチェーンの変更にはすべての取引手数料が支払われる必要があります。この手数料は通常、ブロックチェーンに固有の通貨(ビットコインネットワークのビットコイン、またはイーサリアムのイーサ)で支払われます。この手数料の受益者が誰であるかにかかわらず、数ページ後に見るように、この手数料の目的は、攻撃者が各ノードによって処理される必要があるトランザクションでネットワークを圧倒するのを防ぎ、新しいブロックをチェーンに追加するノードに報酬を提供することです。
ブロックチェーンは、各ブロックにその全履歴の要約を保存することによって変更に抵抗します。チェーン内の各ブロックは、その自身のトランザクションのハッシュと前のブロックのハッシュを計算することによって識別されます。
このスキームを使用すると、チェーン内の任意のブロックの任意のトランザクションの変更は、すべての後続のハッシュの変更を引き起こし、したがって、任意の変更を無意味にします。たとえば、攻撃者が 10 ブロック前に発生したトランザクションを変更しようとすると、そのブロックの要約が変更されるだけでなく、次のブロックの要約も変更されます(それは前のブロックのハッシュに基づいて計算されるため)、そしてチェーンの先頭まで続きます。しかし、攻撃者がブロックチェーンを変更し、ネットワークに偽のコピーを配布するのを防ぐために、このメカニズムは攻撃者がすべてのブロックを再生成することを区別する必要があります。これがプルーフ・オブ・ワークの由来です。
トランザクションは順序付けられ、ブロックチェーンのブロックに含まれるものは、衰退の Igorifhn のネットワークに依存します。私たちが扱っているのは分散型データベースであるため、すべての参加者がどのようにチョークの変化を与えるかに同意する方法が必要です。たとえば、売り手がブロックチェーン上で資産を提供し、2 人のバイヤーがそれを争っている場合、分散ネットワークは誰が最初であるかをどのように決定できますか?さらに悪いことに、売り手がこの 2 人の売り手に対して彼らが 2 回購入し、現金取引を行ったと伝えることをどのように防ぐことができますか?「私たちは、トランザクションがどのように選択され、順序付けられるかを決定する方法が必要です。これにより、ブロックチェーンの単一の状態を維持します。言い換えれば、どのブロックにブロックを追加するかを決定する方法が必要です。」
ビットコインやイーサリアムなどの多くの公共ブロックは、「プルーフ・オブ・ワーク」と呼ばれるコンセンサスアルゴリズムに依存しています。プルーフ・オブ・ワークは、計算を実行するための大量の CPU ループの暗号証明です。この場合、ブロックに基づいて困難な数値を計算します。ブロックをブロックチェーンに追加するには、それに伴って証明を得る必要があり、追加されたブロックのノードはその努力に対して報酬を得ます。この役割を果たすノードは「マイナー」と呼ばれ、新しいブロックが追加されるたびに、彼らは次のブロックを追加して適切な報酬を得るために競争します。注意すべきは、これらの証明のメカニズムは実際には非常に単純です。チェーン内の識別子の前のブロックは、前のブロックの識別子、ブロック内のすべてのトランザクション、および非 ct を含むハッシュです。現在の値を変更することにより、ブロックの要約は完全に異なります。チェーンに新しいブロックを追加するには、泥棒は特定の構造を持っている必要があります(N 個のゼロから始まります)。予測要約がどのようになるかを知ることは受動的ではないため、マイナーは値を変更しながらブロックを繰り返し計算するまで、要求される要約を見つけることができません。これには多くの試行が必要であるため、作業の証明と見なされます。
全体のインフラストラクチャは、ピアツーピア分散ネットワークの上で動作します。これにより、ノードは自分の意志でネットワークに参加したり離れたりでき、集中型サーバーを要求することはありません。ここで、プルーフ・オブ・ワークアルゴリズムは、新しいノードが実際のチェーンがどれであるかを知る方法を提供します:彼らは単に最大の累積計算能力を持つチェーンを探す必要があります。
これにより、悪意のある参加者が単にチェーン上の記録を変更し、すべての後続のブロックハッシュを再計算することを防ぎます。これを行うには、攻撃者は攻撃されたブロックからのすべての作業の証拠を解決する必要があり、これはネットワーク内の他のマイナーよりも強力な計算能力を必要とします。
注:プルーフ・オブ・ワークの他にも、他の合意メカニズムがあります。… 内部では、権威の証明と利害関係の証明が、より速く、より小さなチェーンを構築するための代替案として存在します。
衰退アルゴリズムはネットワークの最終性に密接に関連しています。私たちがブロックチェーンに含まれており、変更されないことがわかっているとき、私たちは反交換が最終的であると言います。最近のブロックに追加されたトランザクションは、最終的なものとは見なされません:マイナーが行に沿って 2 つのブロックを掘り出すことができた場合、最初のブロックから最後まで、新しいチェーンを生成し、トランザクションを含めない可能性があります。
これは再構成と呼ばれ、作業証明チェーンでは珍しくありません。トランザクションが最終的であることを知るには、それを含むトランザクションの上に数ブロックが採掘されるのを待つ必要があります。ブロックの数は特定のチェーンと、どれだけの信頼が必要かによって異なります。スループットに関しては、設計によって作業の証明が計算的に高価であることを解決します。これは、ブロックチェーンのスループットに依存することを強制し、各回の大量のトランザクションを追加するたびに、困難な問題を解決することを強制します。しかし、チェーンに毎秒追加されるトランザクションの数を制限するもう 1 つの理由があります:検証可能性。ブロックチェーンの分散性を維持するために、ネットワーク内の各ノードは、各トランザクションが合法であることを検証し、既定のルールに従って実行する必要があります。ネットワークが毎秒大量のトランザクションを受け入れる場合、強力なデバイスのみがそのチェーンを検証できるようになります。したがって、低スループットはブロックチェーンへの公共アクセスの保証に関連しています。
特に、イーサリアムは毎秒約 15 のトランザクションを処理するように設計されています。イーサリアムでは、トランザクションが任意の計算を実行できるため、この上限は実際に必要な努力の量に関連しています。各トランザクションは、ネットワーク内のすべてのユーザーとアプリケーション間で共有されます。従来の Web アプリケーションにとっても、これは非常に低い制限です。この制限に関するいくつかの方法は、第 8 章で見ることができます。
ビットコインからイーサリアムまで、これまでのところ、WWE はブロックデータを公共データベースとして扱っていますが、私たちはまだそのデータベースに含まれる可能性のある内容について深く掘り下げていません。最初の有名なブロックチェーンは、所有されているデジタル通貨を追跡するために使用されました。私たちが今日理解しているブロックチェーンの大部分は、2008 年にサトシ・ナカモトによって「ビットコイン:ピアツーピア電子現金システム」という論文で紹介されました。この論文は短く、読みやすく、今日使用されているブロックチェーンの概念の大部分を包み込んでいます。これは、集中所有者や発行者なしの「純粋なピアツーピア版の電子現金」を導入しました。
要するに、ビットコインブロックチェーンは、ユーザーのビットコインの残高を追跡し、資金を 1 つの監査機関から別の監査機関に移転するトランザクションをサポートする公共の分散データベースであり、深く集中した電子決済プラットフォームの実現です。通常の転送に加えて、ビットコインは制限されたスクリプト言語もサポートしています。この言語は、たとえば、将来の特定の期間まで実行を制限する Timeelocks や、資産を移動するために複数のアカウントの同意が必要なマルチシグネチャを構築することを許可します。この言語で構築できるものは依然として限られています。これは、ネットワーク内の仲裁計算をサポートするために提案されました。
暗号学の歴史は長く、古代には主に軍事機密の伝送に使用されていました。「パスワード」、「暗号」など。1970 年以前、暗号学の適用範囲はほとんど政府レベルにあり、標準暗号システムであるデータ暗号化標準と非対称暗号アルゴリズムの発明により、暗号学はさまざまな分野で徐々に深く適用されるようになりました。
暗号学の発展の歴史#
暗号学の発展は大きく 3 つの段階に分けられます:古典暗号学→現代暗号学→公開鍵暗号学
- 古典暗号学:この段階の核心的な暗号学の思想は、主に置換と置換です。置換は、平文の各文字を別の文字に置き換えて暗号文を生成することを意味し、受信者は対応する文字を置き換えることで暗号文から平文を得ることができます。置換は、平文の文字の順序を特定のルールに従って混乱させることを意味します。
- 現代暗号学:この段階の発展は主に対称暗号アルゴリズムです。対称暗号は、送信者が公開されたアルゴリズムを使用して平文を暗号化するためにキーを使用し、受信者が以前に送信者から与えられたキーを使用して暗号文を復号して平文を得ることを意味します。
- 公開鍵暗号学:この段階の発展は主に非対称暗号アルゴリズムです。非対称暗号の原理は、公開鍵で暗号化し、秘密鍵で復号化することです。その実装プロセスは、A が特定のアルゴリズムを使用して一対のキーを生成し、公開鍵と秘密鍵をそれぞれ生成し、公開鍵を公開することです。B が A に情報を送信したい場合、A の公開鍵を使用して平文を暗号化し、暗号文を A に送信します。A は暗号文を受信した後、自分の秘密鍵を使用して暗号文を復号し、平文を得ます。
非対称暗号復号の示意図は以下の通りです。
非対称暗号には、公開鍵と秘密鍵が含まれます。
特徴は:
-
特徴 1:公開鍵で暗号化されたデータは、秘密鍵でのみ復号化でき、公開鍵自体では復号化できません。
-
特徴 2:秘密鍵で暗号化されたデータは、公開鍵でのみ復号化でき、秘密鍵自体では復号化できません。
-
サーバーは同時に公開鍵と秘密鍵を保持します(誰にも渡さない)。
-
サーバーが通信したい相手には、自分の公開鍵を渡します。
非対称暗号を使用したインタラクションのプロセスは次のようになります:クライアントは最初にサーバーの公開鍵を取得し、その公開鍵を使用してデータを暗号化し、暗号化されたデータをサーバーに送信します。上記の特徴 1、2 により、この時点でサーバーのみがデータを正しく復号化できます。
暗号学はブロックチェーンで非常に広く使用されており、3 つのカテゴリに分けられます:対称暗号アルゴリズム、非対称暗号アルゴリズム、ハッシュハッシュアルゴリズム。一般的な方法には、Merkle tree ハッシュツリーアルゴリズム、楕円曲線アルゴリズム、SHA-256 アルゴリズム、Base58 エンコーディングがあります。役割には、ハッシュアルゴリズムを使用して迅速に検索すること、平文を暗号化および復号化すること、情報に署名および検証すること、デジタル証明書を生成すること、アカウントアドレスを生成することなどがあります。
対称暗号アルゴリズムは、最も早く使用される暗号アルゴリズムであり、技術が成熟しています。
1 対称暗号の使用プロセス
対称暗号アルゴリズムでは、データの送信者は平文(元のデータ)と暗号化キーを特別な暗号化アルゴリズムで処理し、複雑な暗号化暗号文を生成して送信します。受信者が暗号文を受信した場合、元の文を解読するには、暗号化に使用されたキーと同じアルゴリズムの逆アルゴリズムを使用して暗号文を復号化する必要があります。対称暗号アルゴリズムでは、使用されるキーは 1 つだけであり、送信者と受信者の両方がこのキーを使用してデータを暗号化および復号化するため、復号化側は事前に暗号化キーを知っている必要があります。
2 対称暗号の特徴
対称暗号アルゴリズムの特徴は、アルゴリズムが公開されていること、計算量が少ないこと、暗号化速度が速いこと、暗号化効率が高いことです。欠点は、取引の両方の当事者が同じキーを使用するため、安全性が保証されないことです。さらに、ユーザーが対称暗号アルゴリズムを使用するたびに、他の人が知らない一意のキーを使用する必要があるため、送信者と受信者が持つキーの数が幾何級数的に増加し、キー管理がユーザーの負担となります。たとえば、2 人のユーザーが対称暗号方式でデータを暗号化して交換する必要がある場合、ユーザーは少なくとも 2 つのキーを必要とし、交換して使用する必要があります。企業内のユーザーが n 人いる場合、企業全体で n×(n-1) 個のキーが必要となり、キーの生成と配布は企業の情報部門の悪夢となります。対称暗号アルゴリズムの安全性は、暗号化キーの保存状況に依存しますが、企業内のすべてのキーを持つ人が秘密を守ることは不可能であり、彼らは通常意図せずにキーを漏洩します。— もしユーザーが使用しているキーが侵入者によって取得された場合、侵入者はそのユーザーのキーで暗号化されたすべての文書を読み取ることができます。企業全体が同じ暗号化キーを共有している場合、企業全体の文書の機密性は失われます。
対称暗号アルゴリズムは分散ネットワークシステムでの使用が難しく、主にキー管理が難しく、使用コストが高いためです。公開鍵暗号アルゴリズム、つまり非対称暗号アルゴリズムと比較すると、対称暗号アルゴリズムは暗号化と認証を提供できますが、署名機能が欠けているため、使用範囲が制限されます。
3 対称暗号の分類
対称暗号はストリーム暗号とブロック暗号に分けられます。
ストリーム暗号は、平文の各バイトを順次暗号化します。暗号化は、ユーザーのキーを使用して、特定の複雑な演算(暗号アルゴリズム)を生成し、平文ストリームを暗号化します。復号化は、同じキーと暗号アルゴリズムを使用し、暗号化と同じ擬似ランダムストリームを使用して平文ストリームを復元します。
ブロック暗号は、平文の 1 ブロックを一度に暗号化します。平文を特定のビット長に分割し、平文グループを暗号化演算に通して暗号文グループを得ます。暗号文グループは、復号化演算(暗号化演算の逆演算)を通して平文グループに戻されます。
ストリーム暗号は、シードキーを使用して、キー流生成器を介して平文の長さに一致する擬似ランダムシーケンスを生成する暗号アルゴリズムです。
ストリーム暗号を使用して特定のメッセージ m を暗号化する場合、すべての単語が暗号化されます。一般的には、m を連続する文字に分割し、m=m1m2m3…; 次に、キー流 k=k1k2k3... の i 番目の文字 ki を使用して平文メッセージの i 番目の文字 mi に対して暗号化変換を実行します。i=1,2,3...; すべての暗号化出力を接続すると、m を暗号化した後の暗号文が構成されます。復号化は、暗号化と同時に行う必要があるため、ストリーム暗号を使用する場合、送信者と受信者は平文または暗号文の同じ位置で操作を行う必要があります。
暗号化および復号化プロセスの示意図は以下の通りです。
ストリーム暗号は、実装が簡単で、ハードウェアの実装が容易で、暗号化および復号化処理速度が速く、エラー伝播がないか、限られているなどの特徴がありますが、この種の暗号は主に軍事、政治機密機関で使用されているため、その研究成果は公開されているものが少ないです。現在、他の分野で公開されているアルゴリズムには RC4、SEAL、A5 などがあります。
一度一密暗号#
一度一密暗号は、1917 年にマウボルヌとヴェルナムによって共同で提案された理想的な暗号化スキームであり、平文メッセージを文字ごとに暗号化することを要求し、各文字の暗号化は独立しており、暗号化のキーは平文の長さに一致する無秩序なランダムキーシーケンスです。このキーシーケンスは一度一密の乱数本です。使用時、暗号文の送信者と受信者は、同じ乱数本を持っており、この乱数本は両者が協議して決定した十分に長いランダムキーシーケンスです。送信者が平文を暗号化する際に使用するキーシーケンスは、乱数本のメッセージの長さの最初の部分から取得され、暗号化が完了した後、使用されたキーシーケンスは直ちに破棄されます。受信者は、乱数本のキーシーケンスを使用して順次暗号文を復号化し、元の文を得るとともに、使用されたキーシーケンスを破棄し、再利用しません。
一度一密の乱数本は無条件で安全な暗号システムと見なされ、つまり破られない暗号システムです。盗聴者が暗号文情報を取得しても、復号化する可能性は全くありません。なぜなら、暗号化のキーは完全にランダムであり、規則性がないため、攻撃者はそれを暗号文分析するための情報を持っていないからです。しかし、一度一密の乱数本が漏洩しないことが前提です。
一度一密の概念の提案は、ストリーム暗号の生成に方向性を提供しました。この概念に基づいて、ますます多くのストリーム暗号アルゴリズムが次々と生まれています。
ストリーム暗号の構造#
ストリーム暗号の構造は、同期ストリーム暗号と自己同期ストリーム暗号に細分されます。同期ストリーム暗号は、そのキー流の生成が平文とは無関係であり、独立したランダムな方法で生成された擬似ランダム数字流によって生成されます。自己同期ストリーム暗号は、同期ストリーム暗号とは反対に、キー流の生成が平文流および暗号文流に関連しており、具体的には、i 番目のキー単語の生成が前の平文の暗号化後の単語に関連しています。この特性により、自己同期暗号は非常に研究が難しく、ほとんどのストリーム暗号の研究は同期暗号に集中しています。
同期ストリーム暗号#
同期ストリーム暗号の暗号流生成プロセスは 2 つの部分に分かれます。1 つはキー流生成器、もう 1 つは暗号化変換器です。
暗号化プロセスの式は:ci=E (ki,mi)、パラメータはすべてバイト配列の単一要素です。復号化プロセスは暗号化プロセスと同期する必要があり、式は 1 つです。キー流の生成は毎回異なるため、暗号化時には、生成されたキー流要素をレジスタにキャッシュし、復号化に使用した後に次の暗号化を続行します。全体のプロセスは tcp プロトコルに似ています。現在最も一般的なストリーム暗号体制は、有限体 GF (2) 上の二元加法ストリーム暗号であり、その暗号化変換は ci=ki⊕mi として表されます。
特徴:
同期ストリーム暗号では、送信者と受信者は同期する必要があります。つまり、両者が同じキーを使用し、同じ位置で操作を行う必要があります。暗号文の文字が転送中に失われたり、損傷したり、削除された場合、復号化は失敗します。
2)エラー伝播がない
暗号文の文字が転送中に変更されても、その文字にのみ影響を与え、他の暗号文の文字の復号化には影響を与えません。
3)能動的攻撃による同期性の破壊
同期要件の結果として、能動的攻撃者が転送中の暗号文の文字を再生、挿入、削除などの破壊操作を行うと、暗号化および復号化プロセスの同期性が直接損なわれます。したがって、使用時には、他の暗号学的技術を借りて、転送された暗号文の認証と完全性の検証操作を行う必要があります。
2.2 自己同期ストリーム暗号
自己同期暗号のキー流の生成は、平文流および暗号文流に独立していません。通常、i 番目のキー単語の生成は、主キーに関連するだけでなく、すでに生成されたいくつかの暗号文の単語にも関連しています。
特徴:
1)自己同期
送信者が暗号文流を転送する際に、いくつかの暗号文の文字が攻撃されると、受信者の復号化は、攻撃された暗号文と送信者の同期が異なるだけであり、他の暗号文流の復号化の同期には問題がありません。
2)限られたエラー伝播
受信者の復号化は、攻撃された i 個の暗号文の文字にのみ影響を与え、他の暗号文流には問題がありません。したがって、生成される平文には最大 i 個のエラーがあります。
3)能動的攻撃による現在の同期性の破壊
4)平文統計拡張
各平文の文字は、その後のすべての暗号文に影響を与え、すなわち平文の統計的特性が暗号文に拡散します。したがって、自己同期ストリーム暗号は、平文の冗長性を利用した攻撃に対しては、同期ストリーム暗号よりも強いです。
2.3 キー流生成器
ストリームキーの重要な部分はキー流生成器です。理想的なキー流生成器は完全にランダムなキー流を生成しますが、実際にはユーザーの秘密鍵に基づいて特定のアルゴリズムによって生成されるため、真のランダム性を実現することは不可能であり、生成されるキー流は擬似ランダムシーケンスです。
キー流生成器は通常、線形フィードバックシフトレジスタ(LFSR)と非線形組み合わせ部分で構成されます。線形フィードバックシフトレジスタは駆動部分と呼ばれます。その動作原理は、駆動部分の j 時点の状態変数 x を入力として、非線形組み合わせ部分 f に入力し、f(x)を現在の時点の kj として出力します。駆動部分は非線形組み合わせ部分で使用されるシーケンスを提供し、非線形部分は各時点のシフトレジスタの状態を組み合わせて、キーシーケンス j 時点の値 kj を生成します。簡単に言えば、駆動部分内部の変数は絶えず変化し、各時点の値は異なり、非線形組み合わせ部分に異なる時点の x の値を入力し、非線形組み合わせ部分はこの時点の x を受け取り、関数 f を介して現在のキー流バイトを生成します。
2.4 フィードバックシフトレジスタ
フィードバックシフトレジスタは、ストリーム暗号のキー流を生成する重要な構成要素です。GF (2) 上の n 次フィードバックシフトレジスタは n 個の二元ストレージと 1 つのフィードバック関数 f (a1,a2,a3,a4,...,an) で構成され、n 次フィードバックシフトレジスタは以下の図のようになります。
各ストレージはシフトレジスタの 1 次と呼ばれ、任意の時点でこれらのレベルの内容はフィードバックシフトレジスタの状態を構成し、各状態は GF (2) 上の 1 次元ベクトルに対応し、合計で 2^n の可能な状態があります。各時点の状態は、長さ n のシーケンス a1、a2、a3、...、an または n 次元ベクトル(a1、a2、a3、...、an)で表され、ここで ai は現在の時点の i 次ストレージの内容です。初期状態はユーザーによって決定され、i 番目のシフトクロックパルスが到着すると、各レベルのストレージ ai はその内容を次のレベル ai-1 に渡し、フィードバック関数 f (a1,a2,a3,a4,...,an) はレジスタの現在の状態に基づいて次の時点の an を計算します。フィードバック関数は n 元のブール関数であり、すなわち n 個の変数 a1、a2、a3、...、an はそれぞれ独立して 0 と 1 の 2 つの可能な値を取ることができ、関数内の演算には論理和、論理積、論理補完などの演算が含まれ、最終的な関数値は 0 または 1 になります。
RC4 アルゴリズム#
RC4 暗号アルゴリズムは、RSA 三人組の中のロン・リベストが 1987 年に設計した、可変長のストリーム暗号アルゴリズムのクラスです。このアルゴリズムの速度は DES 暗号の約 10 倍に達し、非常に高いレベルの非線形性を持っています。1994 年 9 月、アルゴリズムはインターネット上で公開されました。RC4 アルゴリズムの暗号化は XOR を使用しているため、サブキーシーケンスが繰り返されると、暗号文が破られる可能性があります。RC4 は古い検証および暗号化アルゴリズムであり、ハッカー攻撃を受けやすいため、現在は使用が推奨されなくなっています。
RC4 アルゴリズムの実装は非常に簡単で、1 から 256 バイト(8 から 2048 ビット)の可変長キーを使用して 256 バイトの状態ベクトル S を初期化します。S の要素は S [0]、S [1]、S [2]、...、S [255] と記述され、S は最初に S [i]=i として初期化されます。以降、常に 0 から 255 のすべての 8 ビット数を含みますが、置換操作が行われます。生成されるキーのバイト ki は、S の 256 個の要素から特定の方法で選択された要素によって生成されます。キーのバイトが生成されるたびに、S ベクトル内の要素は置換操作を行います。したがって、RC4 アルゴリズムは 2 つの部分に分かれます:S の初期化とキー流の生成であり、キー流の生成プロセスでは、生成されるキーのバイトと対応する平文の要素との間で XOR 演算が行われて暗号文が得られます。
1.1 S の初期化
S を生成する手順は以下の通りです:
1)長さ 256 のバイト配列を宣言し、S の要素に 0 から 255 までの昇順で埋め込みます。すなわち、S [0]=0、S [1]=1、S [2]=2、...、S [255]=255。
2)j:=0
3)0<=i<=255 の範囲で、以下の 2 つの方法をループします:
j = (j + S[i] + int(K[i%keylen])) % 256
S[i], S[j]=S[j], S[i]
1.2 キー流の生成
手順は以下の通りです:
1)i=0;j=0
2)i = (i + 1) % 256
3)j = (j + S[i]) % 256
4)S[i], S[j]=S[j], S[i]
5)出力キーのバイト key = S [(S [i]+S [j])%256]
1.3 RC4 の安全性
RC4 アルゴリズムの暗号化は XOR 方式を使用しているため、サブキーシーケンスが繰り返されると、暗号文が破られる可能性がありますが、現在、128 ビットの RC4 のキー長が繰り返される可能性は発見されていないため、RC4 は現在最も安全な暗号アルゴリズムの 1 つと見なされています。
1.4 RC4 暗号化プロセス
RC4 の暗号化プロセスを簡単に紹介します:
1)自分のキーを使用して、キー流生成器を生成します。
2)キー流生成器は平文の長さに基づいて擬似ランダムシーケンスを生成します。
3)擬似ランダムシーケンスの各ビット要素は、平文に対応するビット要素と XOR 演算を行い、暗号文を生成します。
示意図:
golang による RC4 暗号化の実装:#
package main
import "fmt
func main() {
data := []byte("helloworld");
output:=make([]byte,len(data))
fmt.Printf("平文:%s\n", data);
K := []byte("qwuoaknfabbalafbj");
keylen := len(K);
SetKey(K, keylen);
output=Transform(output, data, len(data));
fmt.Printf("暗号文: %x\n", output);
SetKey(K, keylen);
output1:=make([]byte,len(data))
output1=Transform(output1, output, len(data));
fmt.Printf("復号後の平文:%s", output1);
}
var S = [256]int{}
//Sボックスの初期化
func SetKey(K []byte, keylen int) {
for i := 0; i < 256; i++ {
S[i] = i;
}
j := 0;
for i := 0; i < 256; i++ {
j = (j + S[i] + int(K[i%keylen])) % 256;
S[i], S[j]=S[j], S[i];
}
}
//キー流を生成する
func Transform(output []byte, data []byte, lenth int)[]byte {
i := 0;
j := 0
output=make([]byte,lenth)
for k := 0; k < lenth; k++ {
i = (i + 1) % 256;
j = (j + S[i]) % 256;
S[i], S[j]=S[j], S[i];
key := S[(S[i]+S[j])%256];
//ビットごとのXOR操作
output[k] = uint8(key)^data[k];
}
return output
}
golang で封装された方法を使用して RC4 暗号化を実装しますが、復号化はありません。
package main
import (
"fmt"
"crypto/rc4"
)
func main() {
var key []byte = []byte("fd6cde7c2f4913f22297c948dd530c84") //暗号化に使用するKEYを初期化
rc4obj, _ := rc4.NewCipher(key) //Cipherを返す
str := []byte("helloworld") //暗号化する必要がある文字列
plaintext := make([]byte, len(str)) //
rc4obj.XORKeyStream(plaintext, str)
//XORKeyStreamメソッドは、srcのデータをキーで生成された擬似ランダムビットストリームとXORし、dstに書き込みます。
//plaintextは、あなたが暗号化した結果が返ってくるものであり、注意:plaintextはbase-16エンコードされた文字列であり、各バイトは2つの文字を使用して表現される必要があります。
stringinf := fmt.Sprintf("%x\n", plaintext) //文字列に変換
fmt.Println(stringinf)
}
ブロック暗号は、ブロック暗号とも呼ばれ、英語では Block Cypher と呼ばれ、一般的には平文 m をパディングして固定されたブロック長 s の整数倍の平文ストリング M を得ます。次に、M を長さ s のブロックに分割します。最後に、各ブロックに同じキーを使用して暗号化変換を実行します。一般的なアルゴリズムには AES、DES、3DES があります。
ブロック暗号では、平文ブロックと暗号文ブロックの間には論理演算関係があり、これらの関係は演算のモードです。
一般的なブロック暗号演算の 5 つのモード:
- 電子コードブック(ECB)モード
- 暗号ブロック連鎖(CBC)モード
- 暗号フィードバックモード(CFB)
- 出力フィードバックモード(OFB)
- カウンタモード(CTR)
現在推奨されているのは CBC モードと CTR モードであり、他のモードはあまり使用されていないか、推奨されていません。
- ECB モード
ECB は電子コードブックモードとも呼ばれ、英語では Electronic codebook と呼ばれ、最も基本的なブロック暗号化モードです。暗号化前に暗号化ブロックのサイズ(たとえば、AES は 128 ビット)に基づいていくつかのブロックに分割し、最後のブロックが 128 ビット未満の場合はパディング(具体的にはアルゴリズムによって異なり、デフォルトは 0x00)を使用し、各ブロックを同じキーで個別に暗号化して暗号文ブロックを得て、暗号文ブロックを連結して暗号文を得ます。復号化も同様です。
以下の図は、ECB モードの暗号化および復号化プロセスを示しています。
暗号化プロセス:
したがって、同じ平文内容は常に同じ暗号文に暗号化され、暗号文の形式は平文と同じです。これは非常に安全ではなく、特に画像や平文内容が多く繰り返される場合に問題となります。すべてのブロックの暗号化方式が一致しているため、平文内の繰り返し内容は暗号文に反映されるため、統計分析攻撃に対して抵抗するのが難しくなります。また、平文と暗号文の内容の順序が一致しているため、攻撃者は暗号文を破壊するのが非常に簡単です。攻撃者が暗号文の転送中に傍受し、暗号文の内容の順序を乱すと、受信者が得た暗号文は元の平文情報に復号化できなくなります。これが ECB モードがあまり使用されない理由です。
特徴:
- 操作が簡単で、実装が容易であり、並列計算に有利であり、エラーは転送されません。
- 平文のパターンを隠すことができません。
- 平文に対して能動的攻撃を行う可能性があります。
CBC モード#
CBC は暗号文ブロック連鎖モードとも呼ばれ、英語では Cipher Block Chaining と呼ばれ、この名前は暗号文ブロックが鎖のように互いに接続されていることに由来します。
CBC モードでは、各平文ブロックは最初に前の暗号文ブロックと XOR されてから暗号化されます。この方法では、各暗号文ブロックは前のすべての平文ブロックに依存します。同時に、各メッセージの一意性を保証するために、最初のブロックでは初期化ベクトルを使用する必要があります。
最初のブロックのインデックスが 1 の場合、CBC モードの暗号化プロセスは次のようになります:
Ci = Ek (P ⊕ Ci-1), C0 = IV。
その解読プロセスは次のようになります:
Pi = Dk (Ci) ⊕Ci-1, C0 = IV。
CBC モードの演算プロセスの示意図
CBC アルゴリズムの利点:
- 平文の繰り返し配置は暗号文に反映されません。
- 並列計算をサポートします(復号化のみ)。
- 任意の暗号文ブロックを復号化できます。
CBC アルゴリズムの欠点:
- 特定のエラービットを含む暗号文を復号化すると、最初のブロックのすべてのビットと次のブロックの対応するビットがエラーになります。
- 暗号化は並列計算をサポートしていません。
CFB は暗号フィードバックとも呼ばれ、英語では Cipher feedback と呼ばれ、モードは CBC に似ており、ブロック暗号を自己同期ストリーム暗号に変換できます。作業プロセスも非常に似ています。ブロックのサイズと同じシフトレジスタを使用し、IV でレジスタを初期化します。次に、レジスタの内容をブロック暗号で暗号化し、結果の上位 x ビットを平文の x と XOR して暗号文の x ビットを生成します。次に、生成された x ビットの暗号文をレジスタに移入し、次の x ビットの平文に対してこのプロセスを繰り返します。解読プロセスは暗号化プロセスに似ており、IV から始まり、レジスタを暗号化し、結果の高 x を暗号文と XOR して x ビットの平文を生成し、次の x ビットの暗号文をレジスタに移入します。
CBC と同様に、平文の変更は次のすべての暗号文に影響を与えるため、暗号化プロセスは並列化できません。同様に、CBC と同様に、復号化プロセスは並列化できます。
CFB モードの演算プロセスの示意図
CFB モードの利点:
- パディングは必要ありません。
- 並列計算をサポートします(復号化のみ)。
- 任意の暗号文ブロックを復号化できます。
CFB モードの欠点:
- 暗号化は並列計算をサポートしていません。
- 特定のエラービットを含む暗号文を復号化すると、最初のブロックのすべてのビットと次のブロックの対応するビットがエラーになります。
- 再生攻撃に対して抵抗できません。
OFB:ブロック暗号を同期シーケンス暗号として実行し、CFB に似ていますが、OFB は前の n ビットの暗号文出力ブロックをフィードバックしてシフトレジスタに戻します。OFB にはエラー拡散の問題はありません。
出力フィードバックモード(Output feedback, OFB)は、ブロック暗号を同期ストリーム暗号に変換できます。これは、キー流のブロックを生成し、それを平文ブロックと XOR して暗号文を得るものです。他のストリーム暗号と同様に、暗号文の 1 ビットの反転は、平文の同じ位置のビットも反転させます。この特性により、多くのエラー訂正コード、たとえばパリティビットは、暗号化前に計算され、暗号化後にチェックされても正しい結果を得ることができます。
OFB を使用する各出力ブロックは、すべての前の出力ブロックに関連しているため、並列処理はできません。ただし、平文と暗号文は最終的な XOR プロセスでのみ使用されるため、IV を事前に暗号化し、最後に平文または暗号文を並列に XOR 処理することができます。
全 0 の入力を使用して CBC モードから OFB モードのキー流を生成することができます。この方法は非常に実用的であり、CBC ハードウェア実装を利用して OFB モードの暗号化プロセスを加速することができます。
暗号化プロセス:
OFB モードの利点:
- パディングは必要ありません。
- 事前に暗号化、復号化の準備を行うことができます。
- 暗号化と復号化は同じ構造を使用します。
- 特定のエラービットを含む暗号文を復号化すると、暗号文中の対応するビットのみがエラーになります。
OFB モードの欠点:
- 並列計算をサポートしていません。
- 能動的攻撃者が暗号文ブロック内の特定のビットを反転させると、平文ブロック内の対応するビットも反転します。
CTR モード#
カウンタモード(CTR モード)暗号化は、一連の入力データブロック(カウンタと呼ばれる)を暗号化し、一連のストリーム暗号を生成し、ストリーム暗号と平文を XOR して暗号文を得るものです。同様に、復号化はストリーム暗号と暗号文を XOR して平文を得ることです。
データブロックは、逐次累積カウンタによって生成される異なるビットシーケンスを生成することによって暗号化される前に、カウンタによって生成されます。CTR カウンタの長さは 128 ビット(16 バイト)です。最初の 8 バイトは nonce と呼ばれる初期値であり、この値は毎回異なります。後の 8 バイトはブロック番号であり、これは継続的に + 1 されます。nonce の役割は、データブロックの内容を複雑にすることです。nonce がない場合、カウンタだけでは、データブロックが単純すぎます。Golang でのカウンタの実装は、ここで説明されているものとは少し異なり、最初に BLOCK.SIZE () の長さの初期ベクトル iv を初期化し、iv の最後のバイトはカウンタによって逐次増加します。同様に、暗号化される前に異なるデータブロックを生成します。
暗号化プロセスは、初期カウンタを生成することです。8 つのブロックがあると仮定すると、初期カウンタから + 1 を続けて 8 つのカウンタ値を得て、各カウンタ値を暗号化してキー流を生成し、各キー流と対応する平文を XOR して暗号文を得ます。したがって、その暗号化プロセスは一度一密に相当します。
CTR モードでは、ブロックを任意の順序で暗号化および復号化できます。なぜなら、暗号化と復号化の両方で必要な「カウンタ」の値は、nonce とブロック番号から直接計算できるからです。これは、並列計算を実現できることを意味します。並列計算をサポートするシステムでは、CTR モードの速度は非常に速いです。
以下の図は、CTR モードの暗号化および復号化プロセスを示しています。
暗号化プロセス:
unc AesCTR_Encrypt(plainText,key[]byte)[]byte{
//判断ユーザーが渡したkeyが16バイトに合致するかどうか、合致しない場合は16バイトに処理する
keylen:=len(key)
if keylen==0{ //ユーザーが渡したキーが空の場合はデフォルトキーを使用
key=[]byte("wumansgygoaescbc") //デフォルトキー
}else if keylen>0&&keylen<16{ //キーの長さが0から16の間の場合は、0で残りを埋める
key=append(key,bytes.Repeat([]byte{0},(16-keylen))...)
}else if keylen>16{
key=key[:16]
}
//1.指定する暗号aesアルゴリズムを使用
block, err := aes.NewCipher(key)
if err!=nil{
panic(err)
}
//2.パディングは必要なく、直接ctrブロックモードのstreamを取得
// カウンタモードの、基盤となるブロックがキー流を生成するStreamインターフェースを返し、初期化ベクトルivの長さはブロックのブロックサイズと等しくなければなりません。
iv := []byte("wumansgygoaesctr")
stream := cipher.NewCTR(block, iv)
//3.暗号化操作
cipherText := make([]byte,len(plainText))
stream.XORKeyStream(cipherText,plainText)
return cipherText
}
func AesCTR_Decrypt(cipherText,key []byte)[]byte{
//判断ユーザーが渡したkeyが16バイトに合致するかどうか、合致しない場合は16バイトに処理する
keylen:=len(key)
if keylen==0{ //ユーザーが渡したキーが空の場合はデフォルトキーを使用
key=[]byte("wumansgygoaescbc") //デフォルトキー
}else if keylen>0&&keylen<16{ //キーの長さが0から16の間の場合は、0で残りを埋める
key=append(key,bytes.Repeat([]byte{0},(16-keylen))...)
}else if keylen>16{
key=key[:16]
}
//1.指定するアルゴリズム:aes
block, err:= aes.NewCipher(key)
if err!=nil{
panic(err)
}
//2.カウンタモードの、基盤となるブロックがキー流を生成するStreamインターフェースを返し、初期化ベクトルivの長さはブロックのブロックサイズと等しくなければなりません。
iv := []byte("wumansgygoaesctr")
stream := cipher.NewCTR(block, iv)
//3.解読操作
plainText := make([]byte,len(cipherText))
stream.XORKeyStream(plainText,cipherText)
return plainText
}
//出力
40dbbf4ab999bb36d0d5
helloworld
非対称暗号は公開鍵暗号とも呼ばれます。
1976 年、ディフィーとヘルマンは、全く新しい暗号思想を初めて提案しました。公開鍵暗号体制の思想です。当時、ほとんどすべての暗号体制は対称暗号体制であり、その原理は置換や置換といった比較的単純な方法に基づいていました。公開鍵暗号体制は、これとは全く異なり、2 つの異なる鍵、すなわち公開鍵と秘密鍵を持ち、暗号化の原理も以前の単純な置換や置換ではなく、いくつかの複雑な数学関数に基づいています。これらの数学関数はすべて数学的難題に基づいています。その基礎となる難題は一般に 3 つのクラスに分けられます:大整数分解問題、離散対数問題、楕円曲線クラスです。時には、楕円曲線クラスを離散対数クラスに分類することもあります。公開鍵暗号体制は、革命的な変革であり、従来の暗号体制のモデルを打破し、従来の暗号体制の 2 つの大きな問題、すなわち鍵の配布とデジタル署名を解決しました。
1 非対称暗号の概要
従来の暗号体制はすべて 1 つの鍵を使用しており、送信者が受信者に鍵を渡すコストが非常に高く、リスクも大きいです。受信者が受け取った暗号文が転送中に変更された場合、受信者は暗号文の真偽を判断できません。公開鍵体制は、上記の問題を完璧に解決します。公開鍵は完全に公開されており、誰でもその鍵を受け取ることができます。一方、秘密鍵は自分で保持し、誰にも知らせる必要はありません。公開鍵を使用して暗号化することはできませんので、秘密鍵は安全です。送信者 A は公開鍵を使用して平文を暗号化し、受信者 B は対応する秘密鍵を使用して復号化します。メッセージの完全性と送信元の正確性を保証するために、暗号文にデジタル署名を行う必要があります。A は暗号文に自分の秘密鍵を使用して再度暗号化し、このプロセスをデジタル署名と呼びます。B は受信した暗号文をその秘密鍵に対応する公開鍵で復号化します。このプロセスを検証と呼びます。
したがって、公開鍵暗号体制は、暗号化解読モデルと署名検証モデルの 2 つのモデルに分けることができます。2 つのモデルは独立して使用することも、混合して使用することもできます。具体的には、通常、送信される暗号文はデジタル署名を行う必要があります。送信される内容には、暗号文と署名の 2 つの部分が含まれます。受信者は最初に検証を行い、検証が通過した後に復号化を行います。
非対称暗号の方法は多く、以下では RSA、DSA、ECDSA の 3 つの暗号方式を説明します。
公開鍵暗号体制の要件#
公開鍵暗号体制が実現するためには、以下の要件を満たす必要があります:
- 鍵対を生成すること、すなわち公開鍵と秘密鍵のペアを生成することが計算上容易であること;
- 公開鍵を使用して平文を暗号化することが計算上容易であること;
- 秘密鍵を使用して暗号文を復号化することが計算上容易であること;
- 公開鍵が知られている場合、秘密鍵を計算することができないこと;
- 公開鍵と暗号文が知られている場合、平文を計算することができないこと;
- 暗号化と復号化の順序を入れ替えることができること。
現在、これらの要件を満たす公開鍵暗号体制の基盤となる困難な問題は多くあります。以下の 2 つの一般的な問題を分析します:
- 大整数分解問題
p と q の 2 つの大素数が知られている場合、n=pq を求めることは容易ですが、n が知られている場合、p と q を求めることはほぼ不可能です。これが大整数分解問題です。 - 離散対数問題
まず、2 つの概念、階と原根を理解します。
m > 1 かつ (a, m) = 1 の場合、a^t ≡ 1 mod m が成り立つ最小の正整数 t を a の m に対する階と呼び、δm (a) と記述します。
原根は数学記号です。m が正の整数で、a が整数である場合、a が m の原根であるとは、a の m に対する階が φ(m) に等しいことを意味します。ここで、φ(m) は m の質因数の個数です。
与えられた式 a^t mod b ≡ c において、a は b の原根であり、b は非常に大きな