Reputation: 1377
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
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