2

我有一个规定。

使用静态统一模型、C(0e, 2s, ECC CDH)Key Agreement 技术(如 NIST 特别出版物 800-56Ar214 中的规定,除了将共享秘密归零的要求外)计算共享秘密 Z:

  • NIST 特别出版物 800-56Ar2 中规定的基于 SHA-256 的单步密钥导出函数 (KDF);和

  • 椭圆曲线操作的 P-256 曲线

我已经阅读并尝试实现我在这里找到的内容,但它不起作用。

此时,我可以验证共享密钥是否正确,但我无法获得正确的密钥,也无法(不编辑 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();
    }

我很难过,如果我做错了什么,我将不胜感激。谢谢

4

1 回答 1

2

解决方案是我编写单步 KDF 代码而不使用 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();
}
于 2016-09-23T13:34:34.477 回答