c# - ECDH 与充气城堡

标签 c# bouncycastle kdf

我有一个要求,其中指出。

使用静态统一模型 C(0e, 2s, ECC CDH) key 协议(protocol)技术(如 NIST 特别出版物 800-56Ar214 中指定,除了将共享 secret 归零的要求外)来计算共享 secret Z :

  • 基于 SHA-256 的单步 key 派生函数 (KDF),如 NIST 特别出版物 800-56Ar2;和

  • 椭圆曲线运算的 P-256 曲线

我已经阅读并尝试实现我发现的内容 here但它不起作用。

此时,我可以验证共享 secret 是否正确,但我无法获得正确的 key ,也无法(在不编辑 Bouncy CaSTLe 源代码的情况下)计算如何将 OtherInfo 引入计算中。我找啊找……

代码很简单

   private static Byte[] getSingleStepKDF_SHA256(  Byte[] OtherInfo, 
                                                    Byte[] PrivateKey, 
                                                    Byte[] PublicKey,
                                                    Int32  DesiredKeyBitLength
                                                 )
    {
      BigInteger                  bi              = null;
      X9ECParameters              curve           = null;
      ECDomainParameters          ecParam         = null;
      ECPrivateKeyParameters      privKey         = null;
      ECPublicKeyParameters       pubKey          = null;
      ECDHWithKdfBasicAgreement   agree           = null;
      ECPoint                     point           = null;
      ECDHKekGenerator            ecGen           = null;

      /***********************************************************************
       * 
       * I currently do not know how to include OtherInfo into the 
       * calculation.  I have tried actually modifying ECDHKekGenerator by
       * overloading CalculateAgreement to accept OtherInfo. This had no
       * affect on the resulting key.  I have tried using KdfParameters but
       * ECDHWithKdfBasicAgreement raises an exception when I do that.
       * 
       * The shared seceret is always correct.
       * 
       ************************************************************************/

      curve     = NistNamedCurves.GetByName( "P-256" );
      ecParam   = new ECDomainParameters( curve.Curve, curve.G, curve.N, curve.H, curve.GetSeed() );
      privKey   = new ECPrivateKeyParameters( new BigInteger( PrivateKey ), ecParam );            
      point     = ecParam.Curve.DecodePoint( PublicKey );   
      pubKey    = new ECPublicKeyParameters( point, ecParam );
      ecGen     = new ECDHKekGenerator( DigestUtilities.GetDigest( "SHA256" ) );
      agree     = new ECDHWithKdfBasicAgreement( NistObjectIdentifiers.IdAes256Cbc.ToString(), ecGen );

      agree.Init( privKey );

      //  The shared secret is calculated in this method as well as the key
      bi = agree.CalculateAgreement( pubKey );

      return bi.ToByteArrayUnsigned().Take( ( int )( DesiredKeyBitLength / 8 ) ).ToArray();
    }

我很困惑,希望能对我做错的事情提供帮助。谢谢

最佳答案

解决方案是我编写单步 KDF 代码,除了生成共享 key 之外不使用 Bouncy CaSTLe。希望这可以帮助其他努力实现这一目标的人

/// <summary>
/// Gets the single step KDF using Hash SHA256.
/// NIST SP800 56Ar2 Section 5.8.1.1
/// </summary>
/// <param name="OtherInfo">The other information.</param>
/// <param name="PrivateKey">The private key.</param>
/// <param name="PublicKey">The public key.</param>
/// <param name="DesiredKeyBitLength">Length of the desired key bit.</param>
/// <returns>Byte[].</returns>
private static Byte[] getSingleStepKDF_SHA256(  Byte[]  OtherInfo,
                                                Byte[]  PrivateKey,
                                                Byte[]  PublicKey,
                                                Int32   DesiredKeyBitLength
                                             )
{
  ByteAccumulator             ba                      = null;
  Byte[]                      data                    = null;
  Byte[]                      secret                  = null;
  int                         keyDataLenInBits        = 0;
  int                         keyLenInBytes           = 0;
  uint                        reps                    = 0;
  uint                        cntr                    = 0;

  secret = getSharedSecret( PrivateKey, PublicKey );

  if( secret != null )
  {
    #region Single-Step KDF
    keyDataLenInBits  = DesiredKeyBitLength;
    keyLenInBytes     = ( int )( DesiredKeyBitLength / 8 );

    reps = ( uint )( keyDataLenInBits / 128 ); //  Our hash length is 128 bytes

    if( reps > ( UInt32.MaxValue - 1 ) )
      new Exception( "reps too large" );

    cntr = 1;

    if( ( 4 + ( secret.Length * 8 ) + ( OtherInfo.Length * 8 ) ) > 256 )
      new Exception( "data is too large" );

    ba = new ByteAccumulator();
    ba.IsBigEndian = true;

    data = General.CatArray<Byte>( BitConverter.GetBytes( cntr ).Reverse().ToArray(),
                                    secret,
                                    OtherInfo );

    for( int i = 1; i <= reps; i++ )
    {
      ba.AddBlock( SecureHashAlgorithm.GetSha256_BouncyCastle( data ), 32 );

      //  Increment counter modulo 2^32
      cntr = ( uint )( cntr++ % 32 );

      data = General.CatArray<Byte>( BitConverter.GetBytes( cntr ).Reverse().ToArray(),
                                      secret,
                                      OtherInfo );
    }

    return ba.ToArray().Take( keyLenInBytes ).ToArray();
    #endregion Single-Step KDF
  }
  else
    return null;
}

/// <summary>
/// Gets the shared secret.
/// </summary>
/// <param name="PrivateKeyIn">The private key in.</param>
/// <param name="PublicKeyIn">The public key in.</param>
/// <returns>Byte[].</returns>
private static Byte[] getSharedSecret( Byte[] PrivateKeyIn, Byte[] PublicKeyIn )
{
  ECDHCBasicAgreement         agreement             = new ECDHCBasicAgreement();
  X9ECParameters              curve                 = null;
  ECDomainParameters          ecParam               = null;
  ECPrivateKeyParameters      privKey               = null;
  ECPublicKeyParameters       pubKey                = null;
  ECPoint                     point                 = null;

  curve     = NistNamedCurves.GetByName( "P-256" );
  ecParam   = new ECDomainParameters( curve.Curve, curve.G, curve.N, curve.H, curve.GetSeed() );
  privKey   = new ECPrivateKeyParameters( new BigInteger( PrivateKeyIn ), ecParam );
  point     = ecParam.Curve.DecodePoint( PublicKeyIn );
  pubKey    = new ECPublicKeyParameters( point, ecParam );

  agreement.Init( privKey );

  BigInteger secret = agreement.CalculateAgreement( pubKey );

  return secret.ToByteArrayUnsigned();
}

关于c# - ECDH 与充气城堡,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39648807/

相关文章:

c# - 检测添加到 ComboBox 的项目的事件

c# - 尝试为 SxS C#.NET COM DLL 调用 CoCreateInstance 时出现 HRESULT 0x80070002 (FILE_NOT_FOUND)

java - Bouncy CastLe Diffie-Hellman 与 KDF 的 key 协议(protocol) : What is user keying material?

java - 作为供应商的 Bouncy CaSTLe 与 Bouncy CaSTLe API

c# - LINQ 查询获取具有指定类型成员的所有实体

c# - String.format() DateTime 具有阿拉伯文化

Java 加密 NoSuchAlgorithmException

security - 我使用密码脚本加密的安全性如何? (Golang, AES256, pbkdf2, hmac)

c - 与 OpenSSL 命令兼容的关键功能的密码?