EncryptedPackage.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Base / System / IO / Packaging / EncryptedPackage.cs / 1 / EncryptedPackage.cs

                            //------------------------------------------------------------------------------ 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: 
//  This class represents an OLE compound file that contains an encrypted package. 
//
// History: 
//  06/06/2005: LGolding:    Initial implementation.
//
//-----------------------------------------------------------------------------
 
using System;
using System.Diagnostics; 
using System.IO; 
using System.IO.Packaging;
using System.Runtime.InteropServices; 
using System.Security.RightsManagement;
using System.Windows;
using System.Collections;
using System.Collections.Generic; 

using MS.Internal;                  // Invariant.Assert 
using MS.Internal.IO.Packaging; 
using MS.Internal.IO.Packaging.CompoundFile;    // RightsManagementEncryptionTransform
 
namespace System.IO.Packaging
{
    /// 
    /// This class represents an OLE compound file that contains an encrypted package. 
    /// 
    public class EncryptedPackageEnvelope : IDisposable 
    { 
        //-----------------------------------------------------
        // 
        //  Constructors
        //
        //-----------------------------------------------------
 
        #region Constructors
 
        ///  
        /// Constructor. Creates an EncryptedPackageEnvelope on a new compound file. The file
        /// is overwritten if it already exists, and it is opened for read-write access 
        /// with no sharing.
        /// 
        /// 
        /// The path name of the compound file being created to hold the encrypted package. 
        /// 
        ///  
        /// The publish license to be embedded in the compound file. 
        /// 
        ///  
        /// The object that determines what operations the current user is allowed to perform
        /// on the encrypted content.
        /// 
        internal 
        EncryptedPackageEnvelope(
            string envelopeFileName, 
            PublishLicense publishLicense, 
            CryptoProvider cryptoProvider
            ) 
        {
            if (envelopeFileName == null)
                throw new ArgumentNullException("envelopeFileName");
 
            ThrowIfRMEncryptionInfoInvalid(publishLicense, cryptoProvider);
 
 
            _root = StorageRoot.Open(
                                    envelopeFileName, 
                                    _defaultFileModeForCreate,
                                    _defaultFileAccess,
                                    _defaultFileShare
                                    ); 

            InitializeRMForCreate(publishLicense, cryptoProvider); 
            EmbedPackage(null); 
        }
 
        /// 
        /// Constructor. Creates an EncryptedPackageEnvelope on the specified stream.
        /// 
        ///  
        /// The stream on which to create the compound file that will hold the
        /// encrypted package. 
        ///  
        /// 
        /// The publish license to be embedded in the compound file. 
        /// 
        /// 
        /// The object that determines what operations the current user is allowed
        /// to perform on the encrypted content. 
        /// 
        internal 
        EncryptedPackageEnvelope( 
            Stream envelopeStream,
            PublishLicense publishLicense, 
            CryptoProvider cryptoProvider
            )
        {
            if (envelopeStream == null) 
                throw new ArgumentNullException("envelopeStream");
 
            ThrowIfRMEncryptionInfoInvalid(publishLicense, cryptoProvider); 

            _root = StorageRoot.CreateOnStream(envelopeStream, _defaultFileModeForCreate); 

            //
            // CreateOnStream opens the stream for read access if it's readable, and for
            // read/write access if it's writable. We're going to need it to be writable, 
            // so check that it is.
            // 
            if (_root.OpenAccess != FileAccess.ReadWrite) 
            {
                throw new NotSupportedException(SR.Get(SRID.StreamNeedsReadWriteAccess)); 
            }

            InitializeRMForCreate(publishLicense, cryptoProvider);
            EmbedPackage(null); 
        }
 
        ///  
        /// Constructor. Create an EncryptedPackageEnvelope on the compound file, using
        /// an existing package as the content. 
        /// 
        /// 
        /// The path name of the compound file being created to hold the encrypted package.
        ///  
        /// 
        /// A stream containing an unencrypted package which is to be stored in 
        /// the compound file being created in . 
        /// 
        ///  
        /// The publish license to be embedded in the compound file.
        /// 
        /// 
        /// The object that determines what operations the current user is allowed 
        /// to perform on the encrypted content.
        ///  
        internal 
        EncryptedPackageEnvelope(
            string envelopeFileName, 
            Stream packageStream,
            PublishLicense publishLicense,
            CryptoProvider cryptoProvider
            ) 
        {
            if (envelopeFileName == null) 
                throw new ArgumentNullException("envelopeFileName"); 

            if (packageStream == null) 
                throw new ArgumentNullException("packageStream");

            ThrowIfRMEncryptionInfoInvalid(publishLicense, cryptoProvider);
 
            _root = StorageRoot.Open(
                                    envelopeFileName, 
                                    _defaultFileModeForCreate, 
                                    _defaultFileAccess,
                                    _defaultFileShare 
                                    );

            InitializeRMForCreate(publishLicense, cryptoProvider);
            EmbedPackage(packageStream); 
        }
 
        ///  
        /// Constructor. Create an EncryptedPackageEnvelope on the specified stream, using
        /// an existing package as the content. 
        /// 
        /// 
        /// The stream on which to create the compound file that will hold the
        /// encrypted package. 
        /// 
        ///  
        /// A stream containing an unencrypted package which is to be stored in 
        /// the compound file being created on .
        ///  
        /// 
        /// The publish license to be embedded in the compound file.
        /// 
        ///  
        /// The object that determines what operations the current user is allowed
        /// to perform on the encrypted content. 
        ///  
        internal
        EncryptedPackageEnvelope( 
            Stream envelopeStream,
            Stream packageStream,
            PublishLicense publishLicense,
            CryptoProvider cryptoProvider 
            )
        { 
            if (envelopeStream == null) 
                throw new ArgumentNullException("envelopeStream");
 
            if (packageStream == null)
                throw new ArgumentNullException("packageStream");

            ThrowIfRMEncryptionInfoInvalid(publishLicense, cryptoProvider); 

            _root = StorageRoot.CreateOnStream(envelopeStream, _defaultFileModeForCreate); 
 
            //
            // CreateOnStream opens the stream for read access if it's readable, and for 
            // read/write access if it's writable. We're going to need it to be writable,
            // so check that it is.
            //
            if (_root.OpenAccess != FileAccess.ReadWrite) 
            {
                throw new NotSupportedException(SR.Get(SRID.StreamNeedsReadWriteAccess)); 
            } 

            InitializeRMForCreate(publishLicense, cryptoProvider); 
            EmbedPackage(packageStream);
        }

        ///  
        /// Constructor. Create an EncryptedPackageEnvelope object by opening the specified
        /// file, which must contain an RM-protected package. 
        ///  
        /// 
        /// The path name of the compound file being created to hold the encrypted package. 
        /// 
        /// 
        /// Specifies whether the package is to be opened for read, write, or
        /// read/write access. 
        /// 
        ///  
        /// Specifies whether another process can have the file open simultaneously. 
        /// 
        internal 
        EncryptedPackageEnvelope(
            string envelopeFileName,
            FileAccess access,
            FileShare sharing 
            )
        { 
            if (envelopeFileName == null) 
                throw new ArgumentNullException("envelopeFileName");
 
            _root = StorageRoot.Open(
                                    envelopeFileName,
                                    _defaultFileModeForOpen,
                                    access, 
                                    sharing
                                    ); 
 
            InitForOpen();
        } 

        /// 
        /// Constructor. Create an EncryptedPackageEnvelope object by opening the specified
        /// stream, which must contain an RM-protected package. 
        /// 
        ///  
        /// A stream containing an RM-protected package. 
        /// 
        internal 
        EncryptedPackageEnvelope(
            Stream envelopeStream
            )
        { 
            if (envelopeStream == null)
                throw new ArgumentNullException("envelopeStream"); 
 
            _root = StorageRoot.CreateOnStream(envelopeStream, _defaultFileModeForOpen);
 
            InitForOpen();
        }

        #endregion Constructors 

        //------------------------------------------------------ 
        // 
        //  Public Methods
        // 
        //-----------------------------------------------------

        #region Public Methods
 
        /// 
        /// Create an encrypted package in the specified file with the specified license 
        /// information. The file is created if it does not exist and overwritten 
        /// if it does exist, it is opened for read/write, and it is opened with
        /// no sharing. 
        /// 
        /// 
        /// The path name of the compound file being created to hold the encrypted package.
        ///  
        /// 
        /// The publish license to be embedded in the compound file. 
        ///  
        /// 
        /// The object that determines what operations the current user is allowed to perform 
        /// on the encrypted content.
        /// 
        public static EncryptedPackageEnvelope
        Create( 
            string envelopeFileName,
            PublishLicense publishLicense, 
            CryptoProvider cryptoProvider 
            )
        { 
            return new EncryptedPackageEnvelope(envelopeFileName, publishLicense, cryptoProvider);
        }

        ///  
        /// Create an encrypted package on the specified stream with the specified license
        /// information. The stream  opened for read/write. 
        ///  
        /// 
        /// The stream on which to create the compound file that will hold the 
        /// encrypted package.
        /// 
        /// 
        /// The publish license to be embedded in the compound file. 
        /// 
        ///  
        /// The object that determines what operations the current user is allowed to perform 
        /// on the encrypted content.
        ///  
        public static EncryptedPackageEnvelope
        Create(
            Stream envelopeStream,
            PublishLicense publishLicense, 
            CryptoProvider cryptoProvider
            ) 
        { 
            return new EncryptedPackageEnvelope(envelopeStream, publishLicense, cryptoProvider);
        } 

        /// 
        /// Create an encrypted package from an existing package.
        ///  
        /// 
        /// The path name of the compound file being created to hold the encrypted package. 
        ///  
        /// 
        /// A stream from which to obtain the clear-text contents of an existing package. 
        /// 
        /// 
        /// The publish license to be embedded in the compound file.
        ///  
        /// 
        /// The object that determines what operations the current user is allowed to perform 
        /// on the encrypted content. 
        /// 
        public static EncryptedPackageEnvelope 
        CreateFromPackage(
            string envelopeFileName,
            Stream packageStream,
            PublishLicense publishLicense, 
            CryptoProvider cryptoProvider
            ) 
        { 
            return new EncryptedPackageEnvelope(
                            envelopeFileName, 
                            packageStream,
                            publishLicense,
                            cryptoProvider
                            ); 
        }
 
        ///  
        /// Create an encrypted package from an existing package.
        ///  
        /// 
        /// The stream on which to create the compound file that will hold the
        /// encrypted package.
        ///  
        /// 
        /// A stream from which to obtain the clear-text contents of an existing package. 
        ///  
        /// 
        /// The publish license to be embedded in the compound file. 
        /// 
        /// 
        /// The object that determines what operations the current user is allowed to perform
        /// on the encrypted content. 
        /// 
        public static EncryptedPackageEnvelope 
        CreateFromPackage( 
            Stream envelopeStream,
            Stream packageStream, 
            PublishLicense publishLicense,
            CryptoProvider cryptoProvider
            )
        { 
            return new EncryptedPackageEnvelope(
                            envelopeStream, 
                            packageStream, 
                            publishLicense,
                            cryptoProvider 
                            );
        }

        ///  
        /// Open the encrypted package in the specified compound file. The file
        /// must already exist. The file is opened read-only with no sharing. 
        ///  
        /// 
        /// The path name of the compound file being opened. 
        /// 
        public static EncryptedPackageEnvelope
        Open(
            string envelopeFileName 
            )
        { 
            return Open(envelopeFileName, _defaultFileAccess, _defaultFileShare); 
        }
 
        /// 
        /// Open the encrypted package in the specified compound file. The file
        /// must already exist. The file is opened for the specified access,
        /// with no sharing. 
        /// 
        ///  
        /// The path name of the compound file being opened. 
        /// 
        ///  
        /// Specifies whether the file is to be opened for read, write, or
        /// read/write access.
        /// 
        public static EncryptedPackageEnvelope 
        Open(
            string envelopeFileName, 
            FileAccess access 
            )
        { 
            return Open(envelopeFileName, access, _defaultFileShare);
        }

        ///  
        /// Open the encrypted package in the specified compound file. The file
        /// must already exist. 
        ///  
        /// 
        /// The path name of the compound file being opened. 
        /// 
        /// 
        /// Specifies whether the file is to be opened for read, write, or
        /// read/write access. 
        /// 
        ///  
        /// Specifies whether another process can have the file open simultaneously. 
        /// 
        public static EncryptedPackageEnvelope 
        Open(
            string envelopeFileName,
            FileAccess access,
            FileShare sharing 
            )
        { 
            return new EncryptedPackageEnvelope(envelopeFileName, access, sharing); 
        }
 
        /// 
        /// Open the encrypted package in the specified stream, which must
        /// contain an RM-protected package.
        ///  
        /// 
        /// A stream containing an RM-protected package. 
        ///  
        public static EncryptedPackageEnvelope
        Open( 
            Stream envelopeStream
            )
        {
            return new EncryptedPackageEnvelope(envelopeStream); 
        }
 
 
        /// 
        /// Probe to see if a file is an RM-protected file. Returns true if the file 
        /// is an OLE compound file with the well-known "EncryptedPackage" stream.
        /// 
        /// 
        /// The name of the file being probed. 
        /// 
        ///  
        /// If  is null. 
        /// 
        ///  
        /// If the file specified by  does not exist.
        /// 
        public static bool
        IsEncryptedPackageEnvelope( 
            string fileName
            ) 
        { 
            bool retval = false;
 
            if (fileName == null)
                throw new ArgumentNullException("fileName");

            StorageRoot root = null; 

            try 
            { 
                //
                // When StorageRoot.Open is called on a file that is not a compound file, 
                // it throws an IOException whose inner exception is a COMException whose
                // error code is 0x80030050, STG_E_FILEALREADYEXISTS. Check for that case
                // and return false because that means that this is not an RM-protected file.
                // 
                // Any other exception is a real error. For example, StorageRoot.Open
                // throws FileNotFoundException if path does not exist, and we let that 
                // flow through. 
                //
                root = StorageRoot.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read); 

                //
                // It's a compound file. Does it contain an "EncryptedPackage" stream?
                // 
                retval = ContainsEncryptedPackageStream(root);
            } 
            catch (IOException ex) 
            {
                COMException comException = ex.InnerException as COMException; 
                if (comException != null && comException.ErrorCode == STG_E_FILEALREADYEXISTS)
                    return false;

                throw;  // Any other kind of IOException is a real error. 
            }
            finally 
            { 
                if (root != null)
                { 
                    root.Close();
                }
            }
 
            return retval;
        } 
 
        /// 
        /// Probe to see if a stream is an RM-protected file. Returns true if the 
        /// stream is an OLE compound file with the well-known "EncryptedPackage" stream.
        /// 
        /// 
        /// The stream being probed. 
        /// 
        ///  
        /// If  is null. 
        /// 
        public static bool 
        IsEncryptedPackageEnvelope(
            Stream stream
            )
        { 
            if (stream == null)
                throw new ArgumentNullException("stream"); 
 
            bool retval = false;
            StorageRoot root = null; 

            try
            {
                // 
                // When StorageRoot.CreateOnStream is called on a stream that is not
                // a storage object, it throws an IOException whose inner exception is 
                // a COMException whose error code is 0x80030050, STG_E_FILEALREADYEXISTS. 
                // Check for that case and return false because that means that this
                // stream is not an RM-protected file. 
                //
                // Any other exception is a real error.
                //
                root = StorageRoot.CreateOnStream(stream, FileMode.Open); 

                // 
                // It's a compound file. Does it contain an "EncryptedPackage" stream? 
                //
                retval = ContainsEncryptedPackageStream(root); 
            }
            catch (IOException ex)
            {
                COMException comException = ex.InnerException as COMException; 
                if (comException != null && comException.ErrorCode == STG_E_FILEALREADYEXISTS)
                    return false; 
 
                throw;  // Any other kind of IOException is a real error.
            } 
            finally
            {
                if (root != null)
                { 
                    root.Close();
                } 
            } 

            return retval; 
        }

        /// 
        /// Flush the package and the underlying compound file. 
        /// 
        public void Flush() 
        { 
            CheckDisposed();
 
            //
            // Since _package is only initialized when the client calls GetPackage, it might
            // not be set when the client calls Flush, so we have to check.
            // 
            if (_package != null)
            { 
                _package.Flush(); 
            }
 
            if (_packageStream != null)
            {
                _packageStream.Flush();
            } 

            Invariant.Assert(_root != null, "The envelope cannot be null"); 
 
            _root.Flush();
        } 

        /// 
        /// Close the package and the underlying compound file.
        ///  
        public void Close()
        { 
            Dispose(); 
        }
 
        #endregion Public Methods

        //------------------------------------------------------
        // 
        //  IDisposable
        // 
        //------------------------------------------------------ 

        ///  
        /// Clean up all resources held by this object (both managed and
        /// unmanaged), and ensure that the resources won't be released a
        /// second time by removing it from the finalization queue.
        /// For this class, Dispose() ensures that the encrypted package 
        /// is flushed and closed.
        ///  
        public void Dispose() 
        {
            Dispose(true); 

            GC.SuppressFinalize(this);
        }
 
        //-----------------------------------------------------
        // 
        //  Public Properties 
        //
        //------------------------------------------------------ 

        #region Public Properties

        ///  
        /// An object representing the rights-management information stored in
        /// the EncryptedPackageEnvelope, specifically, the PublishLicense and the 
        /// UseLicenses stored in the compound file that embodies the RM protected Package. 
        /// 
        public RightsManagementInformation RightsManagementInformation 
        {
            get
            {
                CheckDisposed(); 
                return _rmi;
            } 
        } 

        ///  
        /// An object representing the core properties (such as Title and Subject)
        /// of the RM-protected document.
        /// 
        ///  
        /// These core properties are stored in the standard OLE property streams
        /// \005SummaryInformation and \005DocumentSummaryInformation, not the ones 
        /// that are stored in the package itself. It is the responsibility 
        /// of the application to keep the two sets of properties synchronized.
        /// properties. 
        /// 
        public PackageProperties PackageProperties
        {
            get 
            {
                CheckDisposed(); 
                if (_packageProperties == null) 
                {
                    _packageProperties = new StorageBasedPackageProperties(_root); 
                }
                return _packageProperties;
            }
        } 

        ///  
        /// Access with which the compound file was opened. 
        /// 
        public FileAccess FileOpenAccess 
        {
            get
            {
                CheckDisposed(); 
                return _root.OpenAccess;
            } 
        } 

        ///  
        /// Retrieve the package contained in the compound file.
        /// 
        public Package GetPackage()
        { 
            CheckDisposed();
 
            Invariant.Assert(!_handedOutPackageStream, "Copy of package stream has been already handed out"); 

            if (_package == null) 
            {
                //
                // Open the package on the package stream, again with the same level
                // of access. 
                // NOTE: The _packageStream must remain open as long as the _package
                // is open, that is to say, for the life of the EncryptedPackageEnvelope object. 
                // Dispose takes care of flushing and closing the stream. 
                //
                EnsurePackageStream(); 

                //We need to inspect the package stream's CanRead and CanWrite properties
                //to determine if we can open the package with the same access mode as
                //that of the EncryptedPackage. 
                //We will try to open the package with the max possible permissions based
                //on the current EncryptedPackage access and the stream read/write properties. 
 
                FileAccess fileAccessForPackage = 0 ;
 
                //Convert CanRead to FileAccess.Read
                if (_packageStream.CanRead)
                    fileAccessForPackage |= FileAccess.Read;
                //Convert CanWrite to FileAccess.Write 
                if (_packageStream.CanWrite)
                    fileAccessForPackage |= FileAccess.Write; 
 
                //check it against the mode of EncryptedPackage
                fileAccessForPackage &= this.FileOpenAccess; 

                 _package = Package.Open(
                    _packageStream,
                    FileMode.Open, 
                    fileAccessForPackage);
            } 
 
            _handedOutPackage = true;
 
            return _package;
        }

        ///  
        /// Provides access to compound file streams outside of the encrypted package.
        ///  
        public StorageInfo StorageInfo 
        {
            get 
            {
                CheckDisposed();
                return (StorageInfo)_root;
            } 
        }
 
        #endregion Public Properties 

        //----------------------------------------------------- 
        //
        //   Internal Methods
        //
        //----------------------------------------------------- 

        #region Internal Methods 
 
        /// 
        /// Retrieve the package stream contained in the compound file. 
        /// 
        internal Stream GetPackageStream()
        {
            CheckDisposed(); 

            Invariant.Assert(!_handedOutPackage, "Copy of package has been already handed out"); 
 
            EnsurePackageStream();
            _handedOutPackageStream = true; 

            if (_package != null)
            {
                try 
                {
                    _package.Close(); 
                } 
                finally
                { 
                    _package = null;
                }
            }
 
            return _packageStream;
        } 
 
        #endregion
 

        //-----------------------------------------------------
        //
        //   Internal Methods 
        //
        //------------------------------------------------------ 
 
        #region Internal Properties
 
        //
        // Instance name for the encryption transform. This is used in StorageInfo as well.
        //
        internal static string EncryptionTransformName 
        {
            get 
            { 
                return _encryptionTransformName;
            } 
        }

        //
        // Name of the stream containing the encrypted content. This is used in StorageInfo as well. 
        //
        internal static string PackageStreamName 
        { 
            get
            { 
                return _packageStreamName;
            }
        }
 
        //Name of the dataspace label. This is used in StorageInfo as well.
        internal static string DataspaceLabelRMEncryptionNoCompression 
        { 
            get
            { 
                return _dataspaceLabelRMEncryptionNoCompression;
            }
        }
 
        #endregion Internal Properties
 
        //----------------------------------------------------- 
        //
        //  Private Methods 
        //
        //------------------------------------------------------

        #region Private Methods 

        private void 
        InitializeRMForCreate( 
            PublishLicense publishLicense,
            CryptoProvider cryptoProvider 
            )
        {
            //
            // Define a data space consisting of a single transform, namely the 
            // RightsManagementEncryptionTransform.
            // 
            DataSpaceManager dsm = _root.GetDataSpaceManager(); 

            dsm.DefineTransform( 
                    RightsManagementEncryptionTransform.ClassTransformIdentifier,
                    EncryptionTransformName
                    );
 
            string[] transformStack = new string[1];
            transformStack[0] = EncryptionTransformName; 
            _dataSpaceName = DataspaceLabelRMEncryptionNoCompression; 
            dsm.DefineDataSpace(transformStack, _dataSpaceName);
 
            //
            // The call to DefineTransform created a RightsManagementEncryptionTransform
            // object. Obtain this object from the DataSpaceManager, and wrap it in a
            // RightsManagementInformation object. This makes the RM information in the 
            // compound file available to the application (through the RightsManagementInformation
            // property), without exposing to the application the implementation detail 
            // that there -is- such a thing as a "transform". 
            //
            RightsManagementEncryptionTransform rmet = 
                dsm.GetTransformFromName(EncryptionTransformName) as RightsManagementEncryptionTransform;

            //
            // We just defined this transform, so it must exist. 
            //
            Debug.Assert( 
                rmet != null, 
                "RightsManagementEncryptionTransform not found"
                ); 

            _rmi = new RightsManagementInformation(rmet);

            // 
            // Prepare the transform object for use.
            // 
            rmet.SavePublishLicense(publishLicense); 
            rmet.CryptoProvider = cryptoProvider;
 
            //
            // The transform object is now ready for use. When the data space manager
            // queries the transform's IsReady property, it will return true. So there
            // is no need to sign up for the TransformInitializationEvent. 
            //
        } 
 
        private void
        InitForOpen() 
        {

            StreamInfo siPackage = new StreamInfo(_root, PackageStreamName);
            if (!siPackage.InternalExists()) 
            {
                throw new FileFormatException(SR.Get(SRID.PackageNotFound)); 
            } 

            //If the StreamInfo exists we go on to check if correct transform has been 
            //applied to the Stream

            DataSpaceManager dsm = _root.GetDataSpaceManager();
 
            List transforms = dsm.GetTransformsForStreamInfo(siPackage);
 
            RightsManagementEncryptionTransform rmet = null; 

            foreach (IDataTransform dataTransform in transforms) 
            {
                string id = dataTransform.TransformIdentifier as string;
                if (id != null &&
                        String.CompareOrdinal(id.ToUpperInvariant(), 
                            RightsManagementEncryptionTransform.ClassTransformIdentifier.ToUpperInvariant()) == 0)
                { 
                    // Do not allow more than one RM Transform 
                    if (rmet != null)
                    { 
                        throw new FileFormatException(SR.Get(SRID.MultipleRightsManagementEncryptionTransformFound));
                    }

                    rmet = dataTransform as RightsManagementEncryptionTransform; 
                }
            } 
 
            if (rmet == null)
            { 
                throw new FileFormatException(SR.Get(SRID.RightsManagementEncryptionTransformNotFound));
            }

            // 
            //  There is no reason to further push initialization of the Rights Management
            //  data (parsing publish / use license). It will add unnecessary costs to the 
            //  scenarios where RM license are not relevant, for example indexing and 
            //  working with document properties
            // 

            //
            // Make the rights management information stored in the compound file
            // available to the application through the RightsManagementInformation 
            // property.
            // 
            _rmi = new RightsManagementInformation(rmet); 
        }
 
        /// 
        /// Determine if the specified StorageRoot contains a stream with the well-
        /// known name that denotes the encrypted package.
        ///  
        /// 
        /// The root storage or a compound file. 
        ///  
        private static bool
        ContainsEncryptedPackageStream( 
            StorageRoot root
            )
        {
            return ((new StreamInfo(root, PackageStreamName)).InternalExists()); 
        }
 
        ///  
        /// Retrieve the package stream contained in the compound file.
        ///  
        private void EnsurePackageStream()
        {
            if (_packageStream == null)
            { 
                StreamInfo siPackage = new StreamInfo(_root, PackageStreamName);
                if (siPackage.InternalExists()) 
                { 
                    //
                    // Open the existing package stream with the same level of access 
                    // that the compound file is open.
                    //
                    _packageStream = siPackage.GetStream(FileMode.Open, this.FileOpenAccess);
                } 
                else
                { 
                    //Error. This package is created in InitForCreate while creating EncryptedPackageEnvelope. 
                    //If it does not exist, throw an error.
                    throw new FileFormatException(SR.Get(SRID.PackageNotFound)); 
                }
            }
        }
 
        /// 
        /// Dispose(bool disposing) executes in two distinct scenarios. 
        /// If disposing equals true, the method has been called directly 
        /// or indirectly by a user's code. Managed and unmanaged resources
        /// can be disposed. 
        ///
        /// If disposing equals false, the method has been called by the
        /// runtime from inside the finalizer and you should not reference
        /// other objects. Only unmanaged resources can be disposed. 
        ///
        /// This class has no unmanaged resources, so it has no finalizer, 
        /// so this method will only ever be called with disposing=true, 
        /// -unless- a subclass overrides Dispose(bool) and calls the
        /// base class method. 
        /// 
        /// 
        /// true if called from Dispose(); false if called from the finalizer.
        ///  
        protected virtual void
        Dispose( 
            bool disposing 
            )
        { 
            try
            {
                //
                // If disposing is true, dispose all managed and unmanaged 
                // resources. This class has managed resources _package, _root,
                // and _packageProperties that need to be cleaned up. 
                // 
                if (disposing)
                { 
                    try
                    {
                        //
                        // Close the package, if we had it open. It might not be open because we 
                        // might have opened the compound file just to look at the properties, and
                        // never even opened the package. 
                        // 
                        if (_package != null)
                        { 
                            _package.Close();
                        }
                    }
                    finally 
                    {
                        _package = null; 
 
                        try
                        { 
                            if (_packageStream != null)
                            {
                                _packageStream.Close();
                            } 
                        }
                        finally 
                        { 
                            _packageStream = null;
 
                            try
                            {
                                if (_packageProperties != null)
                                { 
                                    _packageProperties.Dispose();
                                } 
                            } 
                            finally
                            { 
                                _packageProperties = null;

                                try
                                { 
                                    if (_root != null)
                                    { 
                                        _root.Close(); 
                                    }
                                } 
                                finally
                                {
                                    _root = null;
                                } 
                            }
                        } 
                    } 
                }
 
                //
                // If disposing is false, only clean up unmanaged resources.
                // This class has no unmanaged resources.
                // 
            }
            finally 
            { 
                //
                // By setting _disposed = true, we ensure that all future accesses to 
                // this object will fail (because all public methods and property accessors
                // call CheckDisposed). Note that we do -not- wrap the entire body of
                // Dispose(bool) (this method) in an "if (!_disposed)". This is safe
                // because we set each reference to null immediately after attempting 
                // to release it, so we never attempt to release any reference more
                // than once. 
                // 
                _disposed = true;
            } 
        }

        private void
        CheckDisposed() 
        {
            if (_disposed) 
                throw new ObjectDisposedException(null, SR.Get(SRID.EncryptedPackageEnvelopeDisposed)); 
        }
 
        /// 
        /// Create a stream in the "encrypted" data space to hold the package
        /// contents, and copy the package into that stream.
        ///  
        /// 
        /// A stream containing an unencrypted package which is to be stored in 
        /// the compound file. 
        /// 
        private void 
        EmbedPackage(Stream packageStream)
        {
            StreamInfo siPackage = new StreamInfo(_root, PackageStreamName);
 
            Debug.Assert(!siPackage.InternalExists());
 
            // 
            // Create a stream to hold the document content. Create it in the
            // dataspace containing the RightsManagementEncryptionTransform. This 
            // will cause the compound file code (specifically, the DataSpaceManager)
            // to create a RightsManagementEncryptionTransform object, and then
            // to trigger the TransformInitializationEvent, which will allow us to
            // retrieve the transform object. 
            //
             _packageStream = siPackage.Create( 
                                                FileMode.Create, 
                                                _root.OpenAccess,
                                                _dataSpaceName 
                                                );

            if (packageStream != null)
            { 
                //copy the stream
 
                PackagingUtilities.CopyStream(packageStream, _packageStream, 
                                                Int64.MaxValue, /*bytes to copy*/
                                                4096 /*buffer size */); 
                _package = Package.Open(_packageStream, FileMode.Open, this.FileOpenAccess);
            }
            else
            { 
                //
                // Create the package on the package stream 
                // 
                _package = Package.Open(_packageStream, FileMode.Create, FileAccess.ReadWrite);
                _package.Flush(); 
                _packageStream.Flush();
            }
        }
 
        private void ThrowIfRMEncryptionInfoInvalid(
            PublishLicense publishLicense, 
            CryptoProvider cryptoProvider) 
        {
            if (publishLicense == null) 
                throw new ArgumentNullException("publishLicense");

            if (cryptoProvider == null)
                throw new ArgumentNullException("cryptoProvider"); 

        } 
 
        #endregion Private Methods
 
        //------------------------------------------------------
        //
        //  Private Fields
        // 
        //-----------------------------------------------------
 
        #region Private Fields 

        private bool _disposed; 
        private bool _handedOutPackage;
        private bool _handedOutPackageStream;

        // Resources managed by this class. 
        private StorageRoot                     _root;
        private Package                         _package; 
 
        private string                          _dataSpaceName;
        private Stream                          _packageStream; 
        private StorageBasedPackageProperties   _packageProperties;
        private RightsManagementInformation     _rmi;

        // 
        // Instance name for the encryption transform. This is used in StorageInfo as well.
        // 
        private const string _encryptionTransformName = "EncryptionTransform"; 

        // 
        // Name of the stream containing the encrypted content. This is used in StorageInfo as well.
        //
        private const string _packageStreamName = "EncryptedPackage";
 
        //Name of the dataspace label. This is used in StorageInfo as well.
        private const string _dataspaceLabelRMEncryptionNoCompression = "RMEncryptionNoCompression"; 
 
        private const int STG_E_FILEALREADYEXISTS = unchecked((int)0x80030050);
 
        private const FileMode   _defaultFileModeForCreate   = FileMode.Create;
        private const FileAccess _defaultFileAccess = FileAccess.ReadWrite;
        private const FileShare  _defaultFileShare  = FileShare.None;
 
        private const FileMode   _defaultFileModeForOpen   = FileMode.Open;
 
        #endregion Private Fields 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------ 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: 
//  This class represents an OLE compound file that contains an encrypted package. 
//
// History: 
//  06/06/2005: LGolding:    Initial implementation.
//
//-----------------------------------------------------------------------------
 
using System;
using System.Diagnostics; 
using System.IO; 
using System.IO.Packaging;
using System.Runtime.InteropServices; 
using System.Security.RightsManagement;
using System.Windows;
using System.Collections;
using System.Collections.Generic; 

using MS.Internal;                  // Invariant.Assert 
using MS.Internal.IO.Packaging; 
using MS.Internal.IO.Packaging.CompoundFile;    // RightsManagementEncryptionTransform
 
namespace System.IO.Packaging
{
    /// 
    /// This class represents an OLE compound file that contains an encrypted package. 
    /// 
    public class EncryptedPackageEnvelope : IDisposable 
    { 
        //-----------------------------------------------------
        // 
        //  Constructors
        //
        //-----------------------------------------------------
 
        #region Constructors
 
        ///  
        /// Constructor. Creates an EncryptedPackageEnvelope on a new compound file. The file
        /// is overwritten if it already exists, and it is opened for read-write access 
        /// with no sharing.
        /// 
        /// 
        /// The path name of the compound file being created to hold the encrypted package. 
        /// 
        ///  
        /// The publish license to be embedded in the compound file. 
        /// 
        ///  
        /// The object that determines what operations the current user is allowed to perform
        /// on the encrypted content.
        /// 
        internal 
        EncryptedPackageEnvelope(
            string envelopeFileName, 
            PublishLicense publishLicense, 
            CryptoProvider cryptoProvider
            ) 
        {
            if (envelopeFileName == null)
                throw new ArgumentNullException("envelopeFileName");
 
            ThrowIfRMEncryptionInfoInvalid(publishLicense, cryptoProvider);
 
 
            _root = StorageRoot.Open(
                                    envelopeFileName, 
                                    _defaultFileModeForCreate,
                                    _defaultFileAccess,
                                    _defaultFileShare
                                    ); 

            InitializeRMForCreate(publishLicense, cryptoProvider); 
            EmbedPackage(null); 
        }
 
        /// 
        /// Constructor. Creates an EncryptedPackageEnvelope on the specified stream.
        /// 
        ///  
        /// The stream on which to create the compound file that will hold the
        /// encrypted package. 
        ///  
        /// 
        /// The publish license to be embedded in the compound file. 
        /// 
        /// 
        /// The object that determines what operations the current user is allowed
        /// to perform on the encrypted content. 
        /// 
        internal 
        EncryptedPackageEnvelope( 
            Stream envelopeStream,
            PublishLicense publishLicense, 
            CryptoProvider cryptoProvider
            )
        {
            if (envelopeStream == null) 
                throw new ArgumentNullException("envelopeStream");
 
            ThrowIfRMEncryptionInfoInvalid(publishLicense, cryptoProvider); 

            _root = StorageRoot.CreateOnStream(envelopeStream, _defaultFileModeForCreate); 

            //
            // CreateOnStream opens the stream for read access if it's readable, and for
            // read/write access if it's writable. We're going to need it to be writable, 
            // so check that it is.
            // 
            if (_root.OpenAccess != FileAccess.ReadWrite) 
            {
                throw new NotSupportedException(SR.Get(SRID.StreamNeedsReadWriteAccess)); 
            }

            InitializeRMForCreate(publishLicense, cryptoProvider);
            EmbedPackage(null); 
        }
 
        ///  
        /// Constructor. Create an EncryptedPackageEnvelope on the compound file, using
        /// an existing package as the content. 
        /// 
        /// 
        /// The path name of the compound file being created to hold the encrypted package.
        ///  
        /// 
        /// A stream containing an unencrypted package which is to be stored in 
        /// the compound file being created in . 
        /// 
        ///  
        /// The publish license to be embedded in the compound file.
        /// 
        /// 
        /// The object that determines what operations the current user is allowed 
        /// to perform on the encrypted content.
        ///  
        internal 
        EncryptedPackageEnvelope(
            string envelopeFileName, 
            Stream packageStream,
            PublishLicense publishLicense,
            CryptoProvider cryptoProvider
            ) 
        {
            if (envelopeFileName == null) 
                throw new ArgumentNullException("envelopeFileName"); 

            if (packageStream == null) 
                throw new ArgumentNullException("packageStream");

            ThrowIfRMEncryptionInfoInvalid(publishLicense, cryptoProvider);
 
            _root = StorageRoot.Open(
                                    envelopeFileName, 
                                    _defaultFileModeForCreate, 
                                    _defaultFileAccess,
                                    _defaultFileShare 
                                    );

            InitializeRMForCreate(publishLicense, cryptoProvider);
            EmbedPackage(packageStream); 
        }
 
        ///  
        /// Constructor. Create an EncryptedPackageEnvelope on the specified stream, using
        /// an existing package as the content. 
        /// 
        /// 
        /// The stream on which to create the compound file that will hold the
        /// encrypted package. 
        /// 
        ///  
        /// A stream containing an unencrypted package which is to be stored in 
        /// the compound file being created on .
        ///  
        /// 
        /// The publish license to be embedded in the compound file.
        /// 
        ///  
        /// The object that determines what operations the current user is allowed
        /// to perform on the encrypted content. 
        ///  
        internal
        EncryptedPackageEnvelope( 
            Stream envelopeStream,
            Stream packageStream,
            PublishLicense publishLicense,
            CryptoProvider cryptoProvider 
            )
        { 
            if (envelopeStream == null) 
                throw new ArgumentNullException("envelopeStream");
 
            if (packageStream == null)
                throw new ArgumentNullException("packageStream");

            ThrowIfRMEncryptionInfoInvalid(publishLicense, cryptoProvider); 

            _root = StorageRoot.CreateOnStream(envelopeStream, _defaultFileModeForCreate); 
 
            //
            // CreateOnStream opens the stream for read access if it's readable, and for 
            // read/write access if it's writable. We're going to need it to be writable,
            // so check that it is.
            //
            if (_root.OpenAccess != FileAccess.ReadWrite) 
            {
                throw new NotSupportedException(SR.Get(SRID.StreamNeedsReadWriteAccess)); 
            } 

            InitializeRMForCreate(publishLicense, cryptoProvider); 
            EmbedPackage(packageStream);
        }

        ///  
        /// Constructor. Create an EncryptedPackageEnvelope object by opening the specified
        /// file, which must contain an RM-protected package. 
        ///  
        /// 
        /// The path name of the compound file being created to hold the encrypted package. 
        /// 
        /// 
        /// Specifies whether the package is to be opened for read, write, or
        /// read/write access. 
        /// 
        ///  
        /// Specifies whether another process can have the file open simultaneously. 
        /// 
        internal 
        EncryptedPackageEnvelope(
            string envelopeFileName,
            FileAccess access,
            FileShare sharing 
            )
        { 
            if (envelopeFileName == null) 
                throw new ArgumentNullException("envelopeFileName");
 
            _root = StorageRoot.Open(
                                    envelopeFileName,
                                    _defaultFileModeForOpen,
                                    access, 
                                    sharing
                                    ); 
 
            InitForOpen();
        } 

        /// 
        /// Constructor. Create an EncryptedPackageEnvelope object by opening the specified
        /// stream, which must contain an RM-protected package. 
        /// 
        ///  
        /// A stream containing an RM-protected package. 
        /// 
        internal 
        EncryptedPackageEnvelope(
            Stream envelopeStream
            )
        { 
            if (envelopeStream == null)
                throw new ArgumentNullException("envelopeStream"); 
 
            _root = StorageRoot.CreateOnStream(envelopeStream, _defaultFileModeForOpen);
 
            InitForOpen();
        }

        #endregion Constructors 

        //------------------------------------------------------ 
        // 
        //  Public Methods
        // 
        //-----------------------------------------------------

        #region Public Methods
 
        /// 
        /// Create an encrypted package in the specified file with the specified license 
        /// information. The file is created if it does not exist and overwritten 
        /// if it does exist, it is opened for read/write, and it is opened with
        /// no sharing. 
        /// 
        /// 
        /// The path name of the compound file being created to hold the encrypted package.
        ///  
        /// 
        /// The publish license to be embedded in the compound file. 
        ///  
        /// 
        /// The object that determines what operations the current user is allowed to perform 
        /// on the encrypted content.
        /// 
        public static EncryptedPackageEnvelope
        Create( 
            string envelopeFileName,
            PublishLicense publishLicense, 
            CryptoProvider cryptoProvider 
            )
        { 
            return new EncryptedPackageEnvelope(envelopeFileName, publishLicense, cryptoProvider);
        }

        ///  
        /// Create an encrypted package on the specified stream with the specified license
        /// information. The stream  opened for read/write. 
        ///  
        /// 
        /// The stream on which to create the compound file that will hold the 
        /// encrypted package.
        /// 
        /// 
        /// The publish license to be embedded in the compound file. 
        /// 
        ///  
        /// The object that determines what operations the current user is allowed to perform 
        /// on the encrypted content.
        ///  
        public static EncryptedPackageEnvelope
        Create(
            Stream envelopeStream,
            PublishLicense publishLicense, 
            CryptoProvider cryptoProvider
            ) 
        { 
            return new EncryptedPackageEnvelope(envelopeStream, publishLicense, cryptoProvider);
        } 

        /// 
        /// Create an encrypted package from an existing package.
        ///  
        /// 
        /// The path name of the compound file being created to hold the encrypted package. 
        ///  
        /// 
        /// A stream from which to obtain the clear-text contents of an existing package. 
        /// 
        /// 
        /// The publish license to be embedded in the compound file.
        ///  
        /// 
        /// The object that determines what operations the current user is allowed to perform 
        /// on the encrypted content. 
        /// 
        public static EncryptedPackageEnvelope 
        CreateFromPackage(
            string envelopeFileName,
            Stream packageStream,
            PublishLicense publishLicense, 
            CryptoProvider cryptoProvider
            ) 
        { 
            return new EncryptedPackageEnvelope(
                            envelopeFileName, 
                            packageStream,
                            publishLicense,
                            cryptoProvider
                            ); 
        }
 
        ///  
        /// Create an encrypted package from an existing package.
        ///  
        /// 
        /// The stream on which to create the compound file that will hold the
        /// encrypted package.
        ///  
        /// 
        /// A stream from which to obtain the clear-text contents of an existing package. 
        ///  
        /// 
        /// The publish license to be embedded in the compound file. 
        /// 
        /// 
        /// The object that determines what operations the current user is allowed to perform
        /// on the encrypted content. 
        /// 
        public static EncryptedPackageEnvelope 
        CreateFromPackage( 
            Stream envelopeStream,
            Stream packageStream, 
            PublishLicense publishLicense,
            CryptoProvider cryptoProvider
            )
        { 
            return new EncryptedPackageEnvelope(
                            envelopeStream, 
                            packageStream, 
                            publishLicense,
                            cryptoProvider 
                            );
        }

        ///  
        /// Open the encrypted package in the specified compound file. The file
        /// must already exist. The file is opened read-only with no sharing. 
        ///  
        /// 
        /// The path name of the compound file being opened. 
        /// 
        public static EncryptedPackageEnvelope
        Open(
            string envelopeFileName 
            )
        { 
            return Open(envelopeFileName, _defaultFileAccess, _defaultFileShare); 
        }
 
        /// 
        /// Open the encrypted package in the specified compound file. The file
        /// must already exist. The file is opened for the specified access,
        /// with no sharing. 
        /// 
        ///  
        /// The path name of the compound file being opened. 
        /// 
        ///  
        /// Specifies whether the file is to be opened for read, write, or
        /// read/write access.
        /// 
        public static EncryptedPackageEnvelope 
        Open(
            string envelopeFileName, 
            FileAccess access 
            )
        { 
            return Open(envelopeFileName, access, _defaultFileShare);
        }

        ///  
        /// Open the encrypted package in the specified compound file. The file
        /// must already exist. 
        ///  
        /// 
        /// The path name of the compound file being opened. 
        /// 
        /// 
        /// Specifies whether the file is to be opened for read, write, or
        /// read/write access. 
        /// 
        ///  
        /// Specifies whether another process can have the file open simultaneously. 
        /// 
        public static EncryptedPackageEnvelope 
        Open(
            string envelopeFileName,
            FileAccess access,
            FileShare sharing 
            )
        { 
            return new EncryptedPackageEnvelope(envelopeFileName, access, sharing); 
        }
 
        /// 
        /// Open the encrypted package in the specified stream, which must
        /// contain an RM-protected package.
        ///  
        /// 
        /// A stream containing an RM-protected package. 
        ///  
        public static EncryptedPackageEnvelope
        Open( 
            Stream envelopeStream
            )
        {
            return new EncryptedPackageEnvelope(envelopeStream); 
        }
 
 
        /// 
        /// Probe to see if a file is an RM-protected file. Returns true if the file 
        /// is an OLE compound file with the well-known "EncryptedPackage" stream.
        /// 
        /// 
        /// The name of the file being probed. 
        /// 
        ///  
        /// If  is null. 
        /// 
        ///  
        /// If the file specified by  does not exist.
        /// 
        public static bool
        IsEncryptedPackageEnvelope( 
            string fileName
            ) 
        { 
            bool retval = false;
 
            if (fileName == null)
                throw new ArgumentNullException("fileName");

            StorageRoot root = null; 

            try 
            { 
                //
                // When StorageRoot.Open is called on a file that is not a compound file, 
                // it throws an IOException whose inner exception is a COMException whose
                // error code is 0x80030050, STG_E_FILEALREADYEXISTS. Check for that case
                // and return false because that means that this is not an RM-protected file.
                // 
                // Any other exception is a real error. For example, StorageRoot.Open
                // throws FileNotFoundException if path does not exist, and we let that 
                // flow through. 
                //
                root = StorageRoot.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read); 

                //
                // It's a compound file. Does it contain an "EncryptedPackage" stream?
                // 
                retval = ContainsEncryptedPackageStream(root);
            } 
            catch (IOException ex) 
            {
                COMException comException = ex.InnerException as COMException; 
                if (comException != null && comException.ErrorCode == STG_E_FILEALREADYEXISTS)
                    return false;

                throw;  // Any other kind of IOException is a real error. 
            }
            finally 
            { 
                if (root != null)
                { 
                    root.Close();
                }
            }
 
            return retval;
        } 
 
        /// 
        /// Probe to see if a stream is an RM-protected file. Returns true if the 
        /// stream is an OLE compound file with the well-known "EncryptedPackage" stream.
        /// 
        /// 
        /// The stream being probed. 
        /// 
        ///  
        /// If  is null. 
        /// 
        public static bool 
        IsEncryptedPackageEnvelope(
            Stream stream
            )
        { 
            if (stream == null)
                throw new ArgumentNullException("stream"); 
 
            bool retval = false;
            StorageRoot root = null; 

            try
            {
                // 
                // When StorageRoot.CreateOnStream is called on a stream that is not
                // a storage object, it throws an IOException whose inner exception is 
                // a COMException whose error code is 0x80030050, STG_E_FILEALREADYEXISTS. 
                // Check for that case and return false because that means that this
                // stream is not an RM-protected file. 
                //
                // Any other exception is a real error.
                //
                root = StorageRoot.CreateOnStream(stream, FileMode.Open); 

                // 
                // It's a compound file. Does it contain an "EncryptedPackage" stream? 
                //
                retval = ContainsEncryptedPackageStream(root); 
            }
            catch (IOException ex)
            {
                COMException comException = ex.InnerException as COMException; 
                if (comException != null && comException.ErrorCode == STG_E_FILEALREADYEXISTS)
                    return false; 
 
                throw;  // Any other kind of IOException is a real error.
            } 
            finally
            {
                if (root != null)
                { 
                    root.Close();
                } 
            } 

            return retval; 
        }

        /// 
        /// Flush the package and the underlying compound file. 
        /// 
        public void Flush() 
        { 
            CheckDisposed();
 
            //
            // Since _package is only initialized when the client calls GetPackage, it might
            // not be set when the client calls Flush, so we have to check.
            // 
            if (_package != null)
            { 
                _package.Flush(); 
            }
 
            if (_packageStream != null)
            {
                _packageStream.Flush();
            } 

            Invariant.Assert(_root != null, "The envelope cannot be null"); 
 
            _root.Flush();
        } 

        /// 
        /// Close the package and the underlying compound file.
        ///  
        public void Close()
        { 
            Dispose(); 
        }
 
        #endregion Public Methods

        //------------------------------------------------------
        // 
        //  IDisposable
        // 
        //------------------------------------------------------ 

        ///  
        /// Clean up all resources held by this object (both managed and
        /// unmanaged), and ensure that the resources won't be released a
        /// second time by removing it from the finalization queue.
        /// For this class, Dispose() ensures that the encrypted package 
        /// is flushed and closed.
        ///  
        public void Dispose() 
        {
            Dispose(true); 

            GC.SuppressFinalize(this);
        }
 
        //-----------------------------------------------------
        // 
        //  Public Properties 
        //
        //------------------------------------------------------ 

        #region Public Properties

        ///  
        /// An object representing the rights-management information stored in
        /// the EncryptedPackageEnvelope, specifically, the PublishLicense and the 
        /// UseLicenses stored in the compound file that embodies the RM protected Package. 
        /// 
        public RightsManagementInformation RightsManagementInformation 
        {
            get
            {
                CheckDisposed(); 
                return _rmi;
            } 
        } 

        ///  
        /// An object representing the core properties (such as Title and Subject)
        /// of the RM-protected document.
        /// 
        ///  
        /// These core properties are stored in the standard OLE property streams
        /// \005SummaryInformation and \005DocumentSummaryInformation, not the ones 
        /// that are stored in the package itself. It is the responsibility 
        /// of the application to keep the two sets of properties synchronized.
        /// properties. 
        /// 
        public PackageProperties PackageProperties
        {
            get 
            {
                CheckDisposed(); 
                if (_packageProperties == null) 
                {
                    _packageProperties = new StorageBasedPackageProperties(_root); 
                }
                return _packageProperties;
            }
        } 

        ///  
        /// Access with which the compound file was opened. 
        /// 
        public FileAccess FileOpenAccess 
        {
            get
            {
                CheckDisposed(); 
                return _root.OpenAccess;
            } 
        } 

        ///  
        /// Retrieve the package contained in the compound file.
        /// 
        public Package GetPackage()
        { 
            CheckDisposed();
 
            Invariant.Assert(!_handedOutPackageStream, "Copy of package stream has been already handed out"); 

            if (_package == null) 
            {
                //
                // Open the package on the package stream, again with the same level
                // of access. 
                // NOTE: The _packageStream must remain open as long as the _package
                // is open, that is to say, for the life of the EncryptedPackageEnvelope object. 
                // Dispose takes care of flushing and closing the stream. 
                //
                EnsurePackageStream(); 

                //We need to inspect the package stream's CanRead and CanWrite properties
                //to determine if we can open the package with the same access mode as
                //that of the EncryptedPackage. 
                //We will try to open the package with the max possible permissions based
                //on the current EncryptedPackage access and the stream read/write properties. 
 
                FileAccess fileAccessForPackage = 0 ;
 
                //Convert CanRead to FileAccess.Read
                if (_packageStream.CanRead)
                    fileAccessForPackage |= FileAccess.Read;
                //Convert CanWrite to FileAccess.Write 
                if (_packageStream.CanWrite)
                    fileAccessForPackage |= FileAccess.Write; 
 
                //check it against the mode of EncryptedPackage
                fileAccessForPackage &= this.FileOpenAccess; 

                 _package = Package.Open(
                    _packageStream,
                    FileMode.Open, 
                    fileAccessForPackage);
            } 
 
            _handedOutPackage = true;
 
            return _package;
        }

        ///  
        /// Provides access to compound file streams outside of the encrypted package.
        ///  
        public StorageInfo StorageInfo 
        {
            get 
            {
                CheckDisposed();
                return (StorageInfo)_root;
            } 
        }
 
        #endregion Public Properties 

        //----------------------------------------------------- 
        //
        //   Internal Methods
        //
        //----------------------------------------------------- 

        #region Internal Methods 
 
        /// 
        /// Retrieve the package stream contained in the compound file. 
        /// 
        internal Stream GetPackageStream()
        {
            CheckDisposed(); 

            Invariant.Assert(!_handedOutPackage, "Copy of package has been already handed out"); 
 
            EnsurePackageStream();
            _handedOutPackageStream = true; 

            if (_package != null)
            {
                try 
                {
                    _package.Close(); 
                } 
                finally
                { 
                    _package = null;
                }
            }
 
            return _packageStream;
        } 
 
        #endregion
 

        //-----------------------------------------------------
        //
        //   Internal Methods 
        //
        //------------------------------------------------------ 
 
        #region Internal Properties
 
        //
        // Instance name for the encryption transform. This is used in StorageInfo as well.
        //
        internal static string EncryptionTransformName 
        {
            get 
            { 
                return _encryptionTransformName;
            } 
        }

        //
        // Name of the stream containing the encrypted content. This is used in StorageInfo as well. 
        //
        internal static string PackageStreamName 
        { 
            get
            { 
                return _packageStreamName;
            }
        }
 
        //Name of the dataspace label. This is used in StorageInfo as well.
        internal static string DataspaceLabelRMEncryptionNoCompression 
        { 
            get
            { 
                return _dataspaceLabelRMEncryptionNoCompression;
            }
        }
 
        #endregion Internal Properties
 
        //----------------------------------------------------- 
        //
        //  Private Methods 
        //
        //------------------------------------------------------

        #region Private Methods 

        private void 
        InitializeRMForCreate( 
            PublishLicense publishLicense,
            CryptoProvider cryptoProvider 
            )
        {
            //
            // Define a data space consisting of a single transform, namely the 
            // RightsManagementEncryptionTransform.
            // 
            DataSpaceManager dsm = _root.GetDataSpaceManager(); 

            dsm.DefineTransform( 
                    RightsManagementEncryptionTransform.ClassTransformIdentifier,
                    EncryptionTransformName
                    );
 
            string[] transformStack = new string[1];
            transformStack[0] = EncryptionTransformName; 
            _dataSpaceName = DataspaceLabelRMEncryptionNoCompression; 
            dsm.DefineDataSpace(transformStack, _dataSpaceName);
 
            //
            // The call to DefineTransform created a RightsManagementEncryptionTransform
            // object. Obtain this object from the DataSpaceManager, and wrap it in a
            // RightsManagementInformation object. This makes the RM information in the 
            // compound file available to the application (through the RightsManagementInformation
            // property), without exposing to the application the implementation detail 
            // that there -is- such a thing as a "transform". 
            //
            RightsManagementEncryptionTransform rmet = 
                dsm.GetTransformFromName(EncryptionTransformName) as RightsManagementEncryptionTransform;

            //
            // We just defined this transform, so it must exist. 
            //
            Debug.Assert( 
                rmet != null, 
                "RightsManagementEncryptionTransform not found"
                ); 

            _rmi = new RightsManagementInformation(rmet);

            // 
            // Prepare the transform object for use.
            // 
            rmet.SavePublishLicense(publishLicense); 
            rmet.CryptoProvider = cryptoProvider;
 
            //
            // The transform object is now ready for use. When the data space manager
            // queries the transform's IsReady property, it will return true. So there
            // is no need to sign up for the TransformInitializationEvent. 
            //
        } 
 
        private void
        InitForOpen() 
        {

            StreamInfo siPackage = new StreamInfo(_root, PackageStreamName);
            if (!siPackage.InternalExists()) 
            {
                throw new FileFormatException(SR.Get(SRID.PackageNotFound)); 
            } 

            //If the StreamInfo exists we go on to check if correct transform has been 
            //applied to the Stream

            DataSpaceManager dsm = _root.GetDataSpaceManager();
 
            List transforms = dsm.GetTransformsForStreamInfo(siPackage);
 
            RightsManagementEncryptionTransform rmet = null; 

            foreach (IDataTransform dataTransform in transforms) 
            {
                string id = dataTransform.TransformIdentifier as string;
                if (id != null &&
                        String.CompareOrdinal(id.ToUpperInvariant(), 
                            RightsManagementEncryptionTransform.ClassTransformIdentifier.ToUpperInvariant()) == 0)
                { 
                    // Do not allow more than one RM Transform 
                    if (rmet != null)
                    { 
                        throw new FileFormatException(SR.Get(SRID.MultipleRightsManagementEncryptionTransformFound));
                    }

                    rmet = dataTransform as RightsManagementEncryptionTransform; 
                }
            } 
 
            if (rmet == null)
            { 
                throw new FileFormatException(SR.Get(SRID.RightsManagementEncryptionTransformNotFound));
            }

            // 
            //  There is no reason to further push initialization of the Rights Management
            //  data (parsing publish / use license). It will add unnecessary costs to the 
            //  scenarios where RM license are not relevant, for example indexing and 
            //  working with document properties
            // 

            //
            // Make the rights management information stored in the compound file
            // available to the application through the RightsManagementInformation 
            // property.
            // 
            _rmi = new RightsManagementInformation(rmet); 
        }
 
        /// 
        /// Determine if the specified StorageRoot contains a stream with the well-
        /// known name that denotes the encrypted package.
        ///  
        /// 
        /// The root storage or a compound file. 
        ///  
        private static bool
        ContainsEncryptedPackageStream( 
            StorageRoot root
            )
        {
            return ((new StreamInfo(root, PackageStreamName)).InternalExists()); 
        }
 
        ///  
        /// Retrieve the package stream contained in the compound file.
        ///  
        private void EnsurePackageStream()
        {
            if (_packageStream == null)
            { 
                StreamInfo siPackage = new StreamInfo(_root, PackageStreamName);
                if (siPackage.InternalExists()) 
                { 
                    //
                    // Open the existing package stream with the same level of access 
                    // that the compound file is open.
                    //
                    _packageStream = siPackage.GetStream(FileMode.Open, this.FileOpenAccess);
                } 
                else
                { 
                    //Error. This package is created in InitForCreate while creating EncryptedPackageEnvelope. 
                    //If it does not exist, throw an error.
                    throw new FileFormatException(SR.Get(SRID.PackageNotFound)); 
                }
            }
        }
 
        /// 
        /// Dispose(bool disposing) executes in two distinct scenarios. 
        /// If disposing equals true, the method has been called directly 
        /// or indirectly by a user's code. Managed and unmanaged resources
        /// can be disposed. 
        ///
        /// If disposing equals false, the method has been called by the
        /// runtime from inside the finalizer and you should not reference
        /// other objects. Only unmanaged resources can be disposed. 
        ///
        /// This class has no unmanaged resources, so it has no finalizer, 
        /// so this method will only ever be called with disposing=true, 
        /// -unless- a subclass overrides Dispose(bool) and calls the
        /// base class method. 
        /// 
        /// 
        /// true if called from Dispose(); false if called from the finalizer.
        ///  
        protected virtual void
        Dispose( 
            bool disposing 
            )
        { 
            try
            {
                //
                // If disposing is true, dispose all managed and unmanaged 
                // resources. This class has managed resources _package, _root,
                // and _packageProperties that need to be cleaned up. 
                // 
                if (disposing)
                { 
                    try
                    {
                        //
                        // Close the package, if we had it open. It might not be open because we 
                        // might have opened the compound file just to look at the properties, and
                        // never even opened the package. 
                        // 
                        if (_package != null)
                        { 
                            _package.Close();
                        }
                    }
                    finally 
                    {
                        _package = null; 
 
                        try
                        { 
                            if (_packageStream != null)
                            {
                                _packageStream.Close();
                            } 
                        }
                        finally 
                        { 
                            _packageStream = null;
 
                            try
                            {
                                if (_packageProperties != null)
                                { 
                                    _packageProperties.Dispose();
                                } 
                            } 
                            finally
                            { 
                                _packageProperties = null;

                                try
                                { 
                                    if (_root != null)
                                    { 
                                        _root.Close(); 
                                    }
                                } 
                                finally
                                {
                                    _root = null;
                                } 
                            }
                        } 
                    } 
                }
 
                //
                // If disposing is false, only clean up unmanaged resources.
                // This class has no unmanaged resources.
                // 
            }
            finally 
            { 
                //
                // By setting _disposed = true, we ensure that all future accesses to 
                // this object will fail (because all public methods and property accessors
                // call CheckDisposed). Note that we do -not- wrap the entire body of
                // Dispose(bool) (this method) in an "if (!_disposed)". This is safe
                // because we set each reference to null immediately after attempting 
                // to release it, so we never attempt to release any reference more
                // than once. 
                // 
                _disposed = true;
            } 
        }

        private void
        CheckDisposed() 
        {
            if (_disposed) 
                throw new ObjectDisposedException(null, SR.Get(SRID.EncryptedPackageEnvelopeDisposed)); 
        }
 
        /// 
        /// Create a stream in the "encrypted" data space to hold the package
        /// contents, and copy the package into that stream.
        ///  
        /// 
        /// A stream containing an unencrypted package which is to be stored in 
        /// the compound file. 
        /// 
        private void 
        EmbedPackage(Stream packageStream)
        {
            StreamInfo siPackage = new StreamInfo(_root, PackageStreamName);
 
            Debug.Assert(!siPackage.InternalExists());
 
            // 
            // Create a stream to hold the document content. Create it in the
            // dataspace containing the RightsManagementEncryptionTransform. This 
            // will cause the compound file code (specifically, the DataSpaceManager)
            // to create a RightsManagementEncryptionTransform object, and then
            // to trigger the TransformInitializationEvent, which will allow us to
            // retrieve the transform object. 
            //
             _packageStream = siPackage.Create( 
                                                FileMode.Create, 
                                                _root.OpenAccess,
                                                _dataSpaceName 
                                                );

            if (packageStream != null)
            { 
                //copy the stream
 
                PackagingUtilities.CopyStream(packageStream, _packageStream, 
                                                Int64.MaxValue, /*bytes to copy*/
                                                4096 /*buffer size */); 
                _package = Package.Open(_packageStream, FileMode.Open, this.FileOpenAccess);
            }
            else
            { 
                //
                // Create the package on the package stream 
                // 
                _package = Package.Open(_packageStream, FileMode.Create, FileAccess.ReadWrite);
                _package.Flush(); 
                _packageStream.Flush();
            }
        }
 
        private void ThrowIfRMEncryptionInfoInvalid(
            PublishLicense publishLicense, 
            CryptoProvider cryptoProvider) 
        {
            if (publishLicense == null) 
                throw new ArgumentNullException("publishLicense");

            if (cryptoProvider == null)
                throw new ArgumentNullException("cryptoProvider"); 

        } 
 
        #endregion Private Methods
 
        //------------------------------------------------------
        //
        //  Private Fields
        // 
        //-----------------------------------------------------
 
        #region Private Fields 

        private bool _disposed; 
        private bool _handedOutPackage;
        private bool _handedOutPackageStream;

        // Resources managed by this class. 
        private StorageRoot                     _root;
        private Package                         _package; 
 
        private string                          _dataSpaceName;
        private Stream                          _packageStream; 
        private StorageBasedPackageProperties   _packageProperties;
        private RightsManagementInformation     _rmi;

        // 
        // Instance name for the encryption transform. This is used in StorageInfo as well.
        // 
        private const string _encryptionTransformName = "EncryptionTransform"; 

        // 
        // Name of the stream containing the encrypted content. This is used in StorageInfo as well.
        //
        private const string _packageStreamName = "EncryptedPackage";
 
        //Name of the dataspace label. This is used in StorageInfo as well.
        private const string _dataspaceLabelRMEncryptionNoCompression = "RMEncryptionNoCompression"; 
 
        private const int STG_E_FILEALREADYEXISTS = unchecked((int)0x80030050);
 
        private const FileMode   _defaultFileModeForCreate   = FileMode.Create;
        private const FileAccess _defaultFileAccess = FileAccess.ReadWrite;
        private const FileShare  _defaultFileShare  = FileShare.None;
 
        private const FileMode   _defaultFileModeForOpen   = FileMode.Open;
 
        #endregion Private Fields 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK