/// <summary>
        ///     Create a SymmetricAlgorithm which logs the encryption operation of the input algorithm
        /// </summary>
        public static SymmetricAlgorithm EnableLogging(this SymmetricAlgorithm loggedAlgorithm,
                                                       SymmetricAlgorithmDiagnosticOptions options)
        {
            if (options == null)
            {
                throw new ArgumentNullException("options");
            }

#if !FXONLY_BUILD
            AuthenticatedSymmetricAlgorithm authenticatedLoggedAlgorithm =
                loggedAlgorithm as AuthenticatedSymmetricAlgorithm;

            if (authenticatedLoggedAlgorithm != null)
            {
                return(new AuthenticatedSymmetricAlgorithmLogger(authenticatedLoggedAlgorithm,
                                                                 options.CheckThreadSafety ? options.LockCheckCallback : null,
                                                                 options.CheckThreadSafety ? options.LockCheckParameter : null));
            }
            else
#endif // !FXONLY_BUILD
            {
                return(new SymmetricAlgorithmLogger(loggedAlgorithm,
                                                    options.CheckThreadSafety ? options.LockCheckCallback : null,
                                                    options.CheckThreadSafety ? options.LockCheckParameter : null));
            }
        }
        public static AuthenticatedSymmetricAlgorithm EnableLogging(this AuthenticatedSymmetricAlgorithm loggedAlgorithm,
                                                                    SymmetricAlgorithmDiagnosticOptions options)
        {
            AuthenticatedSymmetricAlgorithm wrappedAlgorithm =
                (loggedAlgorithm as SymmetricAlgorithm).EnableLogging(options) as AuthenticatedSymmetricAlgorithm;

            Debug.Assert(wrappedAlgorithm != null, "Logged authenticated algorithm did not wrap into an authenticated algortihm");
            return(wrappedAlgorithm);
        }
        public static AuthenticatedSymmetricAlgorithm EnableDecryptionVerification(this AuthenticatedSymmetricAlgorithm loggedAlgorithm,
                                                                                   AuthenticatedSymmetricEncryptionState encryptionState,
                                                                                   SymmetricAlgorithmDiagnosticOptions options)
        {
            AuthenticatedSymmetricAlgorithm wrappedAlgorithm =
                (loggedAlgorithm as SymmetricAlgorithm).EnableDecryptionVerification(encryptionState, options) as AuthenticatedSymmetricAlgorithm;

            Debug.Assert(wrappedAlgorithm != null, "Logged authenticated algorithm did not wrap into an authenticated algortihm");
            return(wrappedAlgorithm);
        }
        /// <summary>
        ///     Create a SymmetricAlgorithm which verifies the decryption operations done on it have state
        ///     which matches captured encryption state.
        /// </summary>
        public static SymmetricAlgorithm EnableDecryptionVerification(this SymmetricAlgorithm loggedAlgorithm,
                                                                      SymmetricEncryptionState encryptionState,
                                                                      SymmetricAlgorithmDiagnosticOptions options)
        {
            if (encryptionState == null)
            {
                throw new ArgumentNullException("encryptionState");
            }
            if (options == null)
            {
                throw new ArgumentNullException("options");
            }

#if !FXONLY_BUILD
            AuthenticatedSymmetricAlgorithm authenticatedLoggedAlgorithm =
                loggedAlgorithm as AuthenticatedSymmetricAlgorithm;

            if (authenticatedLoggedAlgorithm != null)
            {
                AuthenticatedSymmetricEncryptionState authenticatedEncryptionState =
                    encryptionState as AuthenticatedSymmetricEncryptionState;

                if (authenticatedEncryptionState == null)
                {
                    throw new ArgumentException(Resources.NeedAuthenticatedEncryptionState, "encryptionState");
                }

                return(new AuthenticatedSymmetricAlgorithmVerifier(authenticatedLoggedAlgorithm,
                                                                   authenticatedEncryptionState,
                                                                   options.CheckThreadSafety ? options.LockCheckCallback : null,
                                                                   options.CheckThreadSafety ? options.LockCheckParameter : null));
            }
            else
#endif // !FXONLY_BUILD
            {
                return(new SymmetricAlgorithmVerifier(loggedAlgorithm,
                                                      encryptionState,
                                                      options.CheckThreadSafety ? options.LockCheckCallback : null,
                                                      options.CheckThreadSafety ? options.LockCheckParameter : null));
            }
        }