I2Pのインポート置換:GOST R 34.10-2012に基づく署名

楕円暗号は、高い強度と広さを備えており、さまざまな曲線や署名スキームのブックマークについて、常に多くの論争と憶測を引き起こしました。 同時に、誰もそのようなブックマークの例を挙げたり、彼らの不在を証明することはできませんでした。 そのため、AESがリーダーシップを無条件に所有する対称暗号化とは異なり、非対称暗号化は、好み、技術的または法的要件に応じてさまざまな方法で使用されます。 I2Pの追加タイプのアドレス署名は、アプリケーションの選択肢と柔軟性を高めます。 GOSTは、EVPインターフェースを介してopensslでサポートされますが、バージョン1.1では標準配信から除外されます。さらに、既存の実装には、DER形式での公開鍵と署名の保存と転送が含まれます。

I2Pの署名の種類


現在、I2Pには9種類の署名があり、署名の種類、ハッシュの種類、必要に応じて曲線またはそのパラメーターのセットを示します。

  1. ECDSA_SHA256_P256
  2. ECDSA_SHA384_P384
  3. ECDSA_SHA512_P521
  4. RSA_SHA256_2048
  5. RSA_SHA384_3072
  6. RSA_SHA512_4096
  7. EdDSA_SHA512_Ed25519
  8. EdDSA_SHA512_Ed25519ph

また、古いアドレスはタイプ0-DSA_SHA1を使用しますが、これは廃止と見なされます。
タイプ1と7が推奨されます。

GOSTの場合、私の要求に応じて、2つのタイプが割り当てられます。
9-GOSTR3410_GOSTR3411_256_CRYPTO_PRO_A
10-GOSTR3410_GOSTR3411_512_TC26_A
それぞれ256ビットおよび512ビットキー用。

9の公開キーの長さは64バイト(ポイント座標あたり32バイト)および10の場合は128バイトです。

署名の実装GOST R 34.10


256または512ビットのハッシュが署名および検証されると想定されます。 詳細と例はここで説明されます

通常の楕円曲線が使用されるため、暗号化ライブラリの関数を使用して操作できます。 特に、これらはopensslのEC_GROUP_ *およびEC_POINT_ *であり、その主なものは次のとおりです。

int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *n, const EC_POINT *q, const BIGNUM *m, BN_CTX *ctx) 

パラメータに応じて、基点に数値と任意の点を乗算するために使用されます。

曲線の場合、6つのパラメーターが指定されます:pはモジュラス、aとbは曲線の方程式の係数、P(x、y)は基点、qは素数、基点のどれがゼロになるかを乗算します。

pとqは大きく、最大に近い値である必要があります。これは、pがすべての数値の範囲を制限し、qが秘密鍵の範囲を制限するためです。 基点とqは同時に計算されます。
原則として、よく知られ、十分にテストされたパラメーターセットが使用されます。

実装では、2セットのパラメーターを使用します。


曲線とは異なり、GOSTの署名スキームは異なるため、ECDSA_signおよびECDSA_verify関数は使用できず、コードに署名および署名検証を実装する必要があります。

署名(r、s)については、乱数kが選択され、点R = k * Pが計算されます。そのx座標は署名の成分rになります。 コンポーネントs = r * d + h * k、ここでdは秘密鍵、hはビッグエンディアンのメッセージの署名のハッシュです。

署名を検証するには、等式の両側に基点Pを掛けます。

実際、s * P = r * d * P + h * k * P = r * Q + h * R、ここでQは公開鍵です。 この等式では、ポイントRはわかりません。rからy座標を復元することは可能ですが、これは非常に遅い操作です。 したがって、等式をh * R = s * P-r * Qの形式に書き換えてから、
R =(s * P -r * Q)/ hおよびx座標のみを比較します。

i2pdコードでは、次のようになります
 bool GOSTR3410Curve::Verify (const EC_POINT * pub, const BIGNUM * digest, const BIGNUM * r, const BIGNUM * s) { BN_CTX * ctx = BN_CTX_new (); BN_CTX_start (ctx); BIGNUM * q = BN_CTX_get (ctx); EC_GROUP_get_order(m_Group, q, ctx); BIGNUM * h = BN_CTX_get (ctx); BN_mod (h, digest, q, ctx); // h = digest % q BN_mod_inverse (h, h, q, ctx); // 1/h mod q BIGNUM * z1 = BN_CTX_get (ctx); BN_mod_mul (z1, s, h, q, ctx); // z1 = s/h BIGNUM * z2 = BN_CTX_get (ctx); BN_sub (z2, q, r); // z2 = -r BN_mod_mul (z2, z2, h, q, ctx); // z2 = -r/h EC_POINT * C = EC_POINT_new (m_Group); EC_POINT_mul (m_Group, C, z1, pub, z2, ctx); // z1*P + z2*pub BIGNUM * x = BN_CTX_get (ctx); GetXY (C, x, nullptr); // Cx BN_mod (x, x, q, ctx); // Cx % q bool ret = !BN_cmp (x, r); // Cx = r ? EC_POINT_free (C); BN_CTX_end (ctx); BN_CTX_free (ctx); return ret; } 


ハッシュ関数GOST R 34.11-2012(stribog)


メッセージの署名には、SHA256 / SHA512など、適切なサイズのハッシュを計算する任意の関数を使用できますが、既存の実装との互換性を含め、GOST R 34.11-2012で規定されている標準を使用します。 署名とは異なり、ハッシュははるかに簡単です。

詳細な説明と例 。 主な点に注意してください。


I2CPプロトコルを使用した外部暗号プロバイダーによる署名


アドレスがI2CPプロトコルを使用してルーターに接続されている場合、ルーターの秘密署名キーの知識は必要ありません。

代わりに、ルーターはRequestLeaseSetMessageメッセージ(またはRequestVariableLeaseSetMessage)を送信し、応答でアドレス秘密鍵で署名されたLeaseSetを含むCreateLeaseSetMessageメッセージを待ちます。 プロトコルの説明からわかるように、古いバージョンのI2Pでは、メッセージでこのキーを送信する必要がありましたが、これは不要になりました。
したがって、I2Pアドレスを実装するアプリケーションは、GOSTで既存の暗号プロバイダーの1つを使用してAPIに署名し、I2Pソリューションを既存のインフラストラクチャに効果的に統合できます。

実装


現在、 i2pdは署名タイプ9および10を完全にサポートしています。すべてのクライアントアドレスはi2pdのアドレスで機能します。 使用 サーバーアドレスが機能するには、floodfillsの側からのサポートが必要です。または、メインI2Pから独立したネットワークを2以外のnetidで構築できます。メインネットワークでは、Javaまたはfloodfillsの追加パラメーターで 実装されるまで待つ必要があります

Source: https://habr.com/ru/post/J325666/


All Articles