KeyGenerator uses unseeded random number generator; generates identical key pairs (Bug #135)
The SecureRandom instance you are using in the KeyGenerator constructor does not self-initialise its seed. Thus every key pair generated is identical. And there is also no way to pass a seed into KeyGenerator.
In effect, anyone using Portable.Licensing to date will have identical key pairs. This basicly negates any security or integrity it provides. That is, you really need to fix this and get any developers using it to re-generate their key pairs!
To duplicate, run the following console app twice. You will get identical public and private keys.
var pass = "a"; var keygenerator = new KeyGenerator(521); var pair = keygenerator.GenerateKeyPair(); var privateKey = pair.ToEncryptedPrivateKeyString(pass); var publicKey = pair.ToPublicKeyString(); Console.WriteLine(privateKey); Console.WriteLine(publicKey);
I've worked around this by duplicating your code and calling Bouncy Castle directly. This now generates different key pairs.
var pass = "a"; // This is read from the console. // From KeyGenerator constructor / GenerateKeyPair(). var keySize = 521; var secureRandom = SecureRandom.GetInstance("SHA256PRNG"); // These 4 lines are the key to generating different keys! var rng = new RNGCryptoServiceProvider(); var seed = new byte; rng.GetBytes(seed); secureRandom.SetSeed(seed); var keyParams = new KeyGenerationParameters(secureRandom, keySize); var keyGenerator = new ECKeyPairGenerator() as IAsymmetricCipherKeyPairGenerator; keyGenerator.Init(keyParams); var pair = keyGenerator.GenerateKeyPair(); // From KeyFactory.ToEncryptedPrivateKeyString() var salt = new byte; secureRandom.NextBytes(salt); string keyEncryptionAlgorithm = PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc.Id; var privateKey = Convert.ToBase64String( PrivateKeyFactory.EncryptKey(keyEncryptionAlgorithm, pass.ToCharArray(), salt, 10, pair.Private) ); // From KeyFactory.ToPublicKeyString() var publicKey = Convert.ToBase64String( SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pair.Public) .ToAsn1Object() .GetDerEncoded() );
I'd recommend you initialise any instance of Bouncy Castle SecureRandom using RNGCryptoServiceProvider (I also found an instance of it KeyFactory.ToEncryptedPrivateKeyString()). And its probably worth allowing consumers to pass in their own SecureRandom instance (so they can control the random numbers entirely), or possibly their own seed. But I'll let you decide how you want to change your API, if at all.
Note: I have not tried duplicating this issue on other computers, so it may be environmental.
Initialize the SecureRandom generator with a seed
Also provide the ability to provide a custom seed.
Thank you for your complete bug report. I'll fix this as soon as possible.
As long as the BouncyCastle library is not available in version 1.8 with Portable Class Library support i can't open it to the public api. Currently its merged as internal. So maybe offer a method where you can pass your seed is also enough?
- Status changed from New to Assigned
- Assignee set to Daniel Nauck
- Target version set to 1.1.0
Thanks for the quick response, Daniel.
Not seeding the RNG in Bouncy Castle seems like a pretty big oversight to me. Oh well.
I presume you don't have access to RNGCryptoServiceProvider in the portable library world. If you can pass in a byte as a seed, that should cover most scenarios (and would allow callers to use whatever random generator they want as a seed). And the ThreadedSeedGenerator in Bouncy should be good enough if the developer supplies no seed.