public override Symmetric.SymmetricKeyPair Exchange(System.IO.Stream stream) { BinaryReader binaryReader = new BinaryReader(stream); BinaryWriter binaryWriter = new BinaryWriter(stream); //Write our local RSA public key. WritePublicParameters(binaryWriter, localRsa.ExportParameters(false)); binaryWriter.Flush(); //Read the RSA public key of the remote party. RSAParameters remoteParameters = ReadPublicParameters(binaryReader); //Verify the remote party's public key. if (identityVerifier.VerifyIdentity(new RSAIdentity(remoteParameters))) { binaryWriter.Write(true); binaryWriter.Flush(); } else { binaryWriter.Write(false); binaryWriter.Flush(); throw new SecurityException("The remote party's RSA public key was denied by the local identifier."); } //Read the status code from the remote party, and ensure our local public key wasn't denied. if (!binaryReader.ReadBoolean()) { throw new SecurityException("The local RSA public key was denied by the remote party's identifier."); } //Construct an RSA instance and import the remote public key. RSACryptoServiceProvider remoteRsa = new RSACryptoServiceProvider(); remoteRsa.ImportParameters(remoteParameters); //Generate an AES key for ourselves. This will be sent to the remote party. RandomNumberGenerator rng = RandomNumberGenerator.Create(); byte[] localCipherKey = new byte[factory.BlockSize / 8]; rng.GetBytes(localCipherKey); //Encrypt and send the generated AES key using remote party's public key using PKCS#1 v1.5 padding. Packet.WriteBytes(binaryWriter, remoteRsa.Encrypt(localCipherKey, false)); //Read the remote party's generated AES key, recovering the original byte size using the padding. byte[] remoteCipherKey = localRsa.Decrypt(Packet.ReadBytes(binaryReader), false); //Construct the symmetric key pair and return the value to the upper-level. return(new SymmetricKeyPair( factory.CreateKey(factory.CreateIV(localCipherKey), localCipherKey), factory.CreateKey(factory.CreateIV(remoteCipherKey), remoteCipherKey) )); }
public override SymmetricKeyPair Exchange(System.IO.Stream stream) { //Construct a binary stream around the underlying stream. BinaryWriter binaryWriter = new BinaryWriter(stream); BinaryReader binaryReader = new BinaryReader(stream); //Generate an elliptic-curve Diffie-Hellman key for private use. ECDiffieHellmanCng local = new ECDiffieHellmanCng(keySize); local.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash; local.HashAlgorithm = symmetricKeyHashAlgorithm; //Send our ECDH public key to the other party. Packet.WriteBytes(binaryWriter, local.PublicKey.ToByteArray()); binaryWriter.Flush(); //Recieve the ECDH public key from the other party. ECDiffieHellmanCng remote = new ECDiffieHellmanCng( CngKey.Import( Packet.ReadBytes(binaryReader), CngKeyBlobFormat.EccPublicBlob ) ); //Compute the shared secret using the ECDH keys transmitted. byte[] sharedSecret = local.DeriveKeyMaterial(remote.PublicKey); SymmetricKey sharedKey = factory.CreateKey(factory.CreateIV(sharedSecret), sharedSecret); //Return a keypair to the upper level, using the shared key for both directions. return(new SymmetricKeyPair(sharedKey, sharedKey)); }