SRM
SRM

Reputation: 1377

Bouncy Castle Diffie-Hellman DHParams Issue

I am trying to use the bouncy castle .net libraries to perform Diffie-Hellman key exchange and am running into a problem when generating the DHParams object.

My solution will include a central authority which will generate a separate DH key/pair for each client that connects. The idea is that I will keep a separate DH key agreement for each client that connects. I will then send the p,g value to the client where the client will calculate it's dh key agreement. I want to generate different p,g values for each client. I am using BigInteger for that but am running into some problems.

When I try to create a new DHParameters object it throws the following exception whenever I use a bit length other than 768:

System.ArgumentException was unhandled
  Message="generator must in the range [2, p - 2]\r\nParameter name: g"
  Source="BouncyCastle.Crypto"
  ParamName="g"
  StackTrace:
       at Org.BouncyCastle.Crypto.Parameters.DHParameters..ctor(BigInteger p, BigInteger g, BigInteger q, Int32 m, Int32 l, BigInteger j, DHValidationParameters validation)
       at Org.BouncyCastle.Crypto.Parameters.DHParameters..ctor(BigInteger p, BigInteger g, BigInteger q, Int32 l)
       at TestDH.Program.Main(String[] args) in C:\dev\source\TestDH\TestDH\Program.cs:line 30
       at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 
  "generator must in the range [2, p - 2]" 

I'm not sure if it matters but I've tried all kinds of different values for certainty in the BigInteger constructor.

Here is my code:

        SecureRandom sr = new SecureRandom();

        // p,g generation, done by central authority
        BigInteger g512 = new BigInteger(512, 30, sr);
        BigInteger p512 = new BigInteger(512, 30, sr);

        // p,g is then sent to client from central authority

        // common - performed by both server and client sides
        IAsymmetricCipherKeyPairGenerator keyGen = GeneratorUtilities.GetKeyPairGenerator("DH");
        DHParameters dhParams = new DHParameters(p512, g512, null, 512); // Here is where I get the exception if the first parameter if BigInteger is not 768 or lager

The issue is that it takes too long to generate the 768 bit prime number - upwards of 5 seconds on a dual core 2.1Ghz processor with no other processes running. That's just too big of a penalty to incur with each client that initiates a connection. I would like to use smaller bit lengths for the BigInteger.

I'm probably doing this completely wrong - there is scant documentation on how to do DH with bouncy castle and the test/examples just don't match my usage case. I don't want to have pre-generated p,g values.

EDIT It seems even the 768 bit length gives errors once in awhile. After restarting my machine I could get no bit lengths other than 1024 to work, and even then only about 80% of the time. I think I'm doing something wrong.

Upvotes: 0

Views: 2191

Answers (1)

SRM
SRM

Reputation: 1377

I figured it out. You shouldn't use the constructor for the DHParameters. Use the generator utility to obtain your parameters. Here is the code that works:

        const int DefaultPrimeProbability = 30;

        DHParametersGenerator generator = new DHParametersGenerator();
        generator.Init(512, DefaultPrimeProbability, new SecureRandom());
        DHParameters parameters = generator.GenerateParameters();

        KeyGenerationParameters kgp = new DHKeyGenerationParameters(new SecureRandom(), parameters);
        keyGen.Init(kgp);

        AsymmetricCipherKeyPair aliceKeyPair = keyGen.GenerateKeyPair();
        IBasicAgreement aliceKeyAgree = AgreementUtilities.GetBasicAgreement("DH");
        aliceKeyAgree.Init(aliceKeyPair.Private);

        AsymmetricCipherKeyPair bobKeyPair = keyGen.GenerateKeyPair();
        IBasicAgreement bobKeyAgree = AgreementUtilities.GetBasicAgreement("DH");
        bobKeyAgree.Init(bobKeyPair.Private);

        BigInteger aliceAgree = aliceKeyAgree.CalculateAgreement(bobKeyPair.Public);
        BigInteger bobAgree = bobKeyAgree.CalculateAgreement(aliceKeyPair.Public);

        if (!aliceAgree.Equals(bobAgree))
        {
            throw new Exception("Keys do not match.");
        }

        // generate key from prime integers generated above

Upvotes: 3

Related Questions