I2Pの署名の種類
現在、I2Pには9種類の署名があり、署名の種類、ハッシュの種類、必要に応じて曲線またはそのパラメーターのセットを示します。
- ECDSA_SHA256_P256
- ECDSA_SHA384_P384
- ECDSA_SHA512_P521
- RSA_SHA256_2048
- RSA_SHA384_3072
- RSA_SHA512_4096
- EdDSA_SHA512_Ed25519
- 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 R 34.10-2001から借用した256ビットキー用のGostR3410_2001_CryptoPro_A_ParamSet(OID 1.2.643.2.2.35.1)。
- id-tc26-gost-3410-12-512-paramSetA(OID 1.2.643.7.1.2.1.2.1)、GOST R 34.10-2012用にTK26(tc26.ru)によって開発された512ビットキー用。
曲線とは異なり、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で規定されている標準を使用します。 署名とは異なり、ハッシュははるかに簡単です。
詳細な説明と例 。 主な点に注意してください。
- 元のメッセージは64バイトのブロックに分割されます。 メッセージが64の倍数でない場合、最初のブロックの左側にゼロとシングルバイトが埋め込まれます。
- 前のブロックのハッシュを考慮して、各ブロックは個別にハッシュされます。 最初のブロックでは、初期化ベクトル(iv)が以前のハッシュとして設定されます。 ブロックの通過は、最後から最初の逆の順序で実行されます。
- 各ブロックは、指定されたキーを使用して12ラウンド「暗号化」されます。各ラウンドは、指定されたテーブルとラウンドキーを使用したXORを使用した3つの変換S、P、Lの適用です。
- Sはバイト置換、Pは8x8マトリックスとしてのハッシュ転置、Lは特定のマトリックスの乗算です。
- 256ビットハッシュは512ビットハッシュの左半分を表しますが、別のivが使用されるため、同時に計算することはできません。
I2CPプロトコルを使用した外部暗号プロバイダーによる署名
アドレスがI2CPプロトコルを使用してルーターに接続されている場合、ルーターの秘密署名キーの知識は必要ありません。
代わりに、ルーターはRequestLeaseSetMessageメッセージ(またはRequestVariableLeaseSetMessage)を送信し、応答でアドレス秘密鍵で署名されたLeaseSetを含むCreateLeaseSetMessageメッセージを待ちます。 プロトコルの説明からわかるように、古いバージョンのI2Pでは、メッセージでこのキーを送信する必要がありましたが、これは不要になりました。
したがって、I2Pアドレスを実装するアプリケーションは、GOSTで既存の暗号プロバイダーの1つを使用してAPIに署名し、I2Pソリューションを既存のインフラストラクチャに効果的に統合できます。
実装
現在、 i2pdは署名タイプ9および10を完全にサポートしています。すべてのクライアントアドレスはi2pdのアドレスで機能します。 使用例 サーバーアドレスが機能するには、floodfillsの側からのサポートが必要です。または、メインI2Pから独立したネットワークを2以外のnetidで構築できます。メインネットワークでは、Javaまたはfloodfillsの追加パラメーターで 実装されるまで待つ必要があります 。