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) )); }
protected override void HandleIdentityResponse(Packet3IdentityResponse response) { //Ensure the identity has not already been received, and this is not duplicate. if (receivedIdentity) { Disconnect(Packet255Disconnect.DisconnectReason.UnexpectedPacket); return; } //Set the identity received flag to true to prevent future identities from being read. receivedIdentity = true; //Ensure the signed data matches our salt, and we've sent a request. if (!requestedIdentity || salt == null || !response.Signature.Data.SequenceEqual(salt)) { Disconnect(Packet255Disconnect.DisconnectReason.AuthenticationFailed); return; } //Ensure the identity is not ours, which would mean we're connecting to ourselves. if (response.SignatureAlgorithm.Identity.Equals(signatureAlgorithm.Identity)) { Disconnect(Packet255Disconnect.DisconnectReason.AuthenticationFailed); return; } //Ensure the identity matches the expected identity. if (!identityVerifier.VerifyIdentity(response.SignatureAlgorithm.Identity)) { Disconnect(Packet255Disconnect.DisconnectReason.AuthenticationFailed); return; } //Ensure the signature created by the remote party is valid. if (!response.SignatureAlgorithm.Verify(response.Signature)) { Disconnect(Packet255Disconnect.DisconnectReason.AuthenticationFailed); return; } /* * ================== WARNING ================== * * Beyond this point, the peer is trusted to be * a valid recipient of data destined to his * identity (see: Identity class). The actual * authentication process occurs in the * implementation of the signature algorithm the * endpoint has chosen, which may be faulty or * have a vulnerability. It is up to the peer who * requests the identity to ensure the algorithm * chosen by the endpoint is safe to use for * identity authentication. * * Should an issue be discovered in a signature * algorithm, when used it should always throw a * SecurityException, detailing the vulnerability * present by using its standard for * authentication. This exception will be caught * by the PacketHandler processing the handshake * and by specification should disconnect. * * ============================================= */ //Initialize the new authorized handler. Stream.PacketHandler = new RimPacketHandlerAuthorized(Stream, new Contact.Contact(response.SignatureAlgorithm, null), signatureAlgorithm); }