こんにちは親愛なる読者。 序文として、ハイブリッド暗号化システムとは何か、なぜ普及しているのかを思い出させてください。
そのため、ハイブリッド暗号システムを大量の暗号化されたデータを送信する方法と呼ぶのが通例です。データは対称アルゴリズム(AESやDESなど)を使用して秘密鍵で暗号化され、鍵自体は暗号化された非対称暗号(RSAなど)で送信されます。 この方法は、対称暗号と非対称暗号の両方の利点を取り入れているため、広く使用されています。 大きなデータブロックは非常に高速な対称アルゴリズムで暗号化され(これにより深刻な時間コストが削減されます)、暗号化キーは非対称アルゴリズムを使用して確実に暗号化されて送信されます(これにより、対称メソッドのみに特徴的なキー配布の問題が解決されます)。 これらはすべて広く知られているので、最も重要なこと、つまり実装の問題に進みます。 そして、ここから多くの興味深いことが始まります。
一般について少し
一見したところ、最も最適なソリューションはRSA +ブロック暗号の組み合わせです。 ただし、この方法には落とし穴がないわけではありません。
その中で最も明らかなのは、RSAアルゴリズムのセマンティックの弱点です。 したがって、RSAアルゴリズムは、RSA-OAEPなどのアドオンスキームを使用してのみ適用できます(これについては、
こちらを参照してください )。 RSA-OAEPは、2つの暗号的に強力なハッシュ関数と、メッセージ行に特定の数のゼロビットを追加するなどの方法を使用することを簡単に思い出します。 RSA-OAEPスキームが実装に関して最も効率的な非対称アルゴリズムではない理由。 この制限のため、最も単純なオプションとしてRSAを使用すると、その魅力がすべて失われます。
RSAとブロック暗号を共有することのもう1つの欠点は、送信されるデータの整合性制御の欠如です。 そして、これはすでに非対称暗号の庭の石です;それにもかかわらず、RSA-OAEPは受信したデータの整合性をチェックするタスクに対処します。 ここで、ブロックアルゴリズムについて直接話しています。
このトラブルについてもっと話したいです。 ご存知のように、すべてのブロック暗号はいくつかの動作モードをサポートしています。 最も一般的なモードはECBとCBCでした。 ECBモードでは、ソースデータは特定のサイズのブロックM
1 、M
2 、...、M
nに分割されます。 また、暗号文はブロックC
1 、C
2 、...、C
nで構成されます。ここで、C
i = E(M
i )、E(M
i )はブロックM
iに適用される暗号化関数です。 実際、このような体制の欠点はすぐに明らかになります。 攻撃者は、ブロックC
iをブロックC
oに自由に置き換えることができます。 T.O. データ送信中に1つのキーが複数回使用されると、攻撃者は新しいメッセージを傍受し、一部のデータを古いメッセージに置き換える可能性があり、正当な受信者はキャッチに気付かないでしょう。
多くによると、CBCモードはブロック暗号のこの欠点を排除することができますが、実際にはそうではありません。 CBCモードでは、暗号化は次のとおりです。 ソースデータは
、特定のサイズのブロックM
1 、M
2 、M
nに分割されます。 また、暗号文はブロックC
1 、C
2 、C
nで構成されます。ここで、C
i = E(M i⊕C
i-1 )です。 この方法では、すべての暗号文ブロックが接続されているという錯覚が生じ、1つのブロックを置き換えると残りのブロックが失われます。 これは実際にはそうではありません。 単一のブロックを置き換えると、それに続く1つ(!)ブロックの復号化に影響します。 したがって、攻撃者はいくつかのブロックを正常に置き換えることができ、このデータを受信し、1つのブロックのみが誤って受信されたことに気付いた正当な受信者は、これを重要視できません。
したがって、ハイブリッド暗号化について言えば、この方法で送信される情報は2つのブロックではなく、3つのE
asy (K)|| E
sym (M)|| MAC
K (M)である必要があることを理解する必要があります。 -非対称アルゴリズム、E
sym (M)で暗号化-鍵K、データM、MAC
K (M)を使用して対称アルゴリズムで暗号化-鍵Kを使用して受信したメッセージMの認証コード
この点で、ハイブリッドスキームでのRSAのような非対称暗号システムの使用に関連するもう1つのわずかな不便さがあります。 これは冗長データです。 メッセージMを送信するには、暗号テキストにMAC
K (M)ビットの追加の文字列を追加する必要があります。 さらに、RSAは暗号化モジュールのサイズが大きいため(現在は2048ビットが推奨されています)、暗号化されたキーの元のサイズを数倍に増やします。 もちろん、冗長性は2048ビット(MAC機能を考慮に入れる)だけであるため重要ではありませんが、RSA-OAEPの背後にある実装の難しさとともに、これはすべて、別のハイブリッド暗号化方式を探す理由となり、そのような方式があります。 そして、それはDHIESと呼ばれます。
主なものについて簡単に
DHIESハイブリッド暗号化スキーム(Diffie-Hellman統合暗号化スキーム)は、2001年にMichel Abdalla、Mihir Bellare、Phillip Rogawayの3人の著者によって提案されました。 スキームの根底にある考え方は、離散対数問題を解決する難しさに基づいています。 暗号化スキーム自体は次のとおりです。
アリスが対称アルゴリズムで暗号化されたメッセージとこのメッセージのキーをボブに送信するとします。 Bobに公開/秘密キーのペア(x、G、P、Y = G
x mod P)を持たせます。G、P、Yは公開データであり、Bobのx秘密キーです。 つまり Bobのキーセットは、DSAおよびGOST R 34.10-2001標準に準拠しています(追加のキーペアを生成する必要がないため、これは重要です)。
メッセージを送信するために、Aliceは次のアクションを実行します。
- 乱数kを生成します。
- U = G kおよびV = Y k = G kxを計算します。
- ペア(K1、K2)= H(V || U)を定義します。ここで、H()は暗号的に強力なハッシュ関数です。
- C = E K1 (M)およびT = MAC K2 (C)を見つける
- U || C || Tという形式のメッセージをボブに送信します。
アリスからメッセージを受信した後、ボブはプライベートキーxを使用してV = U
xを計算できます。 VとUを知っているボブは、キーペア(K1、K2)= H(V || U)を取得できます。 キーK2を使用して、受信した暗号T = MAC
K2 (C)の整合性をチェックし、結果が正しい場合、キーK1、M = D
K1 (C)を使用してテキストを復号化します。
DHIESスキームの利点は、非対称暗号化の実装が容易なことです。 したがって、安全に暗号化された対称キーを取得して渡すには、2つの指数のみが必要です。 RSAのようなシステムを使用している場合でも、サプリメントスキームに注意する必要があります。
第二に、スキームは離散対数問題に基づいているため、楕円曲線に簡単に変換できます。 楕円曲線でDHIESを使用することの唯一のニュアンスは、G
xを計算することは実際に点x * Gを見つけることを意味することですが、他のすべては同じままです。 楕円暗号は、はるかに小さいサイズのスペース(たとえば、2048ではなく256ビット)で機能することが知られています。 したがって、EC-DHIESスキームを使用すると、冗長ビットを取り除くことができます(もちろん、ここではトラフィックの節約についてではなく、冗長性をわずかに減らすことは名誉なことです)。
第三に、暗号化されたデータ送信のために追加の公開/秘密キーペアを作成する必要はありません。 受信者がDSAアルゴリズムまたはGOST R 34.10-2001でデジタル署名を使用する場合、署名を検証するために使用される公開キーを使用してメッセージを送信できます。
そしてほんの少しのコード
そして最後に、EC-DHIESを実装できる楕円曲線のポイントで数学演算を実行するための小さなクラス。
//
public class ECPoint
{
public BigInteger x;
public BigInteger y;
public BigInteger a;
public BigInteger b;
public BigInteger FieldChar;
public ECPoint(ECPoint p)
{
x = px;
y = py;
a = pa;
b = pb;
FieldChar = p.FieldChar;
}
public ECPoint()
{
x = new BigInteger();
y = new BigInteger();
a = new BigInteger();
b = new BigInteger();
FieldChar = new BigInteger();
}
// P1 P2
public static ECPoint operator +(ECPoint p1, ECPoint p2)
{
ECPoint p3 = new ECPoint();
p3.a = p1.a;
p3.b = p1.b;
p3.FieldChar = p1.FieldChar;
BigInteger dy = p2.y - p1.y;
BigInteger dx = p2.x - p1.x;
if (dx < 0)
dx += p1.FieldChar;
if (dy < 0)
dy += p1.FieldChar;
BigInteger m = (dy * dx.modInverse(p1.FieldChar)) % p1.FieldChar;
if (m < 0)
m += p1.FieldChar;
p3.x = (m * m - p1.x - p2.x) % p1.FieldChar;
p3.y = (m * (p1.x - p3.x) - p1.y) % p1.FieldChar;
if (p3.x < 0)
p3.x += p1.FieldChar;
if (p3.y < 0)
p3.y += p1.FieldChar;
return p3;
}
// P c
public static ECPoint Double(ECPoint p)
{
ECPoint p2 = new ECPoint();
p2.a = pa;
p2.b = pb;
p2.FieldChar = p.FieldChar;
BigInteger dy = 3 * px * px + pa;
BigInteger dx = 2 * py;
if (dx < 0)
dx += p.FieldChar;
if (dy < 0)
dy += p.FieldChar;
BigInteger m = (dy * dx.modInverse(p.FieldChar)) % p.FieldChar;
p2.x = (m * m - px - px) % p.FieldChar;
p2.y = (m * (px - p2.x) - py) % p.FieldChar;
if (p2.x < 0)
p2.x += p.FieldChar;
if (p2.y < 0)
p2.y += p.FieldChar;
return p2;
}
// x, x
public static ECPoint multiply(BigInteger x, ECPoint p)
{
ECPoint temp = p;
while (x != 0)
{
if ((x % 2) != 0)
{
if ((temp.x==px)||(temp.y==py))
temp=Double(temp);
else
temp = temp + p;
x = x - 1;
}
x = x / 2;
p = Double(p);
}
return temp;
}
}
* This source code was highlighted with Source Code Highlighter .
おわりに
もちろん、誰もが彼にとって個人的に最も便利であると思われる方法を選択する必要がありますが、別のオプションの知識は決して不必要ではありません。 この記事がお役に立てば幸いであり、データの秘密を守る別の方法(利便性と信頼性の最良の組み合わせ)を見つける助けになれば幸いです。 そして、この方法を適用するか、他の何かを選択するかは、もちろんあなただけに決定されます。
参照資料
- DHIESメソッドの説明(pdf) 。
- BigIntegerライブラリはここからダウンロードできます 。
- 推奨される楕円曲線のリスト 。