/// <summary>
        /// Creates the association at the provider side after the association request has been received.
        /// </summary>
        /// <param name="request">The association request.</param>
        /// <param name="associationStore">The OpenID Provider's association store or handle encoder.</param>
        /// <param name="securitySettings">The security settings of the Provider.</param>
        /// <returns>
        /// The newly created association.
        /// </returns>
        /// <remarks>
        /// The response message is updated to include the details of the created association by this method,
        /// but the resulting association is <i>not</i> added to the association store and must be done by the caller.
        /// </remarks>
        public Association CreateAssociationAtProvider(AssociateRequest request, IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings)
        {
            var diffieHellmanRequest = request as AssociateDiffieHellmanRequest;

            ErrorUtilities.VerifyInternal(diffieHellmanRequest != null, "Expected a DH request type.");

            this.SessionType = this.SessionType ?? request.SessionType;

            // Go ahead and create the association first, complete with its secret that we're about to share.
            Association association = HmacShaAssociationProvider.Create(this.Protocol, this.AssociationType, AssociationRelyingPartyType.Smart, associationStore, securitySettings);

            // We now need to securely communicate the secret to the relying party using Diffie-Hellman.
            // We do this by performing a DH algorithm on the secret and setting a couple of properties
            // that will be transmitted to the Relying Party.  The RP will perform an inverse operation
            // using its part of a DH secret in order to decrypt the shared secret we just invented
            // above when we created the association.
            using (DiffieHellman dh = new DiffieHellmanManaged(
                       diffieHellmanRequest.DiffieHellmanModulus ?? AssociateDiffieHellmanRequest.DefaultMod,
                       diffieHellmanRequest.DiffieHellmanGen ?? AssociateDiffieHellmanRequest.DefaultGen,
                       AssociateDiffieHellmanRequest.DefaultX)) {
                HashAlgorithm hasher = DiffieHellmanUtilities.Lookup(this.Protocol, this.SessionType);
                this.DiffieHellmanServerPublic = DiffieHellmanUtilities.EnsurePositive(dh.CreateKeyExchange());
                this.EncodedMacKey             = DiffieHellmanUtilities.SHAHashXorSecret(hasher, dh, diffieHellmanRequest.DiffieHellmanConsumerPublic, association.SecretKey);
            }
            return(association);
        }
        /// <summary>
        /// Creates the association at relying party side after the association response has been received.
        /// </summary>
        /// <param name="request">The original association request that was already sent and responded to.</param>
        /// <returns>The newly created association.</returns>
        /// <remarks>
        /// The resulting association is <i>not</i> added to the association store and must be done by the caller.
        /// </remarks>
        public Association CreateAssociationAtRelyingParty(AssociateRequest request)
        {
            var diffieHellmanRequest = request as AssociateDiffieHellmanRequest;

            ErrorUtilities.VerifyArgument(diffieHellmanRequest != null, OpenIdStrings.DiffieHellmanAssociationRequired);

            HashAlgorithm hasher = DiffieHellmanUtilities.Lookup(Protocol, this.SessionType);

            byte[] associationSecret = DiffieHellmanUtilities.SHAHashXorSecret(hasher, diffieHellmanRequest.Algorithm, this.DiffieHellmanServerPublic, this.EncodedMacKey);

            Association association = HmacShaAssociation.Create(Protocol, this.AssociationType, this.AssociationHandle, associationSecret, TimeSpan.FromSeconds(this.ExpiresIn));

            return(association);
        }