CryptoProvider.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Base / System / Security / RightsManagement / CryptoProvider.cs / 1305600 / CryptoProvider.cs

                            //------------------------------------------------------------------------------ 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description:  Crypto provider class which is a wrapper around unmanaged DRM SDK Bound License handle 
//   provides ability to Encryt/Decrypt protected content, and enumerate granted rights. 
//
// History: 
//  06/01/2005: IgorBel :   Initial Implementation
//
//-----------------------------------------------------------------------------
 
using System;
using System.Collections; 
using System.Collections.Generic; 
using System.Diagnostics;
using System.Globalization; 
using System.Security;
using System.Security.Permissions;
using System.Windows;
using System.Collections.ObjectModel; 
using MS.Internal.Security.RightsManagement;
using MS.Internal; 
using SecurityHelper=MS.Internal.WindowsBase.SecurityHelper; 

using MS.Internal.WindowsBase; 

namespace System.Security.RightsManagement
{
    ///  
    /// CryptoProvider class is built as a result of UseLicense.Bind call. This class represents a successful RightsManagement
    /// Initialization, and as a result provides Encryption/Decryption services, and exposes list of Bound Grants, which are rights 
    /// that have been given by the publisher to the user, and were properly validated (expiration checks, secure environment, and so on) 
    /// 
    ///  
    ///     Critical:    This class expose access to methods that eventually do one or more of the the following
    ///             1. call into unmanaged code
    ///             2. affects state/data that will eventually cross over unmanaged code boundary
    ///             3. Return some RM related information which is considered private 
    ///
    ///     TreatAsSafe: This attrbiute automatically applied to all public entry points. All the public entry points have 
    ///     Demands for RightsManagementPermission at entry to counter the possible attacks that do 
    ///     not lead to the unamanged code directly(which is protected by another Demand there) but rather leave
    ///     some status/data behind which eventually might cross the unamanaged boundary. 
    /// 
    [SecurityCritical(SecurityCriticalScope.Everything)]
    public class CryptoProvider : IDisposable
    { 
        //-----------------------------------------------------
        // 
        //  Public Methods 
        //
        //----------------------------------------------------- 

        /// 
        /// This method is responsible for tearing down crypto provider that was built as a result of UseLicense.Bind call.
        ///  
        ~CryptoProvider()
        { 
            Dispose(false); 
        }
 
        /// 
        /// This method is responsible for tearing down crypto provider that was built as a result of UseLicense.Bind call.
        /// 
        public void Dispose() 
        {
            SecurityHelper.DemandRightsManagementPermission(); 
            Dispose(true); 
            GC.SuppressFinalize(this);
        } 

         /// 
        /// This function encrypts clear text content.
        /// An application is expected to create a padding scheme based on the value returned from 
        /// BlockSize property. BlockSize property should be used to determine the amount of extra
        /// padding to be added to the clear text. The length, in bytes, of the buffer holding content to 
        /// be encrypted should be a multiple of the block cipher block size. 
        /// RMS system currently uses AES block cipher. All blocks are encrypted independently, so that 2 blocks
        /// of identical clear text will produce identical results after encryption.  An application 
        /// is encouraged to either compress data prior to encryption or create some other scheme to mitigate
        /// threats potentially arising from independent block encryption.
        /// 
        public byte[] Encrypt(byte[] clearText) 
        {
            SecurityHelper.DemandRightsManagementPermission(); 
            CheckDisposed(); 

            if (clearText == null) 
            {
                throw new ArgumentNullException("clearText");
            }
 
            // validation of the proper size of the clearText is done by the unmanaged libraries
 
            if (!CanEncrypt) 
            {
                throw new RightsManagementException(RightsManagementFailureCode.EncryptionNotPermitted); 
            }

            // first get the size
            uint outputBufferSize=0; 
            byte[] outputBuffer = null;
            int hr; 
 
#if DEBUG
            hr= SafeNativeMethods.DRMEncrypt( 
                            EncryptorHandle,
                            0,
                            (uint)clearText.Length,
                            clearText, 
                            ref outputBufferSize,
                            null); 
 
            Errors.ThrowOnErrorCode(hr);
 
            // We do not expect Decryption to change the size of the buffer; otherwise it will break
            // basic assumptions behind the encrypted compound file envelope format
            Invariant.Assert(outputBufferSize == clearText.Length);
#else 
            outputBufferSize = (uint)clearText.Length;
#endif 
 
            outputBuffer = new byte[outputBufferSize];
 
            // This will decrypt content
            hr = SafeNativeMethods.DRMEncrypt(
                            EncryptorHandle,
                            0, 
                            (uint)clearText.Length,
                            clearText, 
                            ref outputBufferSize, 
                            outputBuffer);
            Errors.ThrowOnErrorCode(hr); 

            return outputBuffer;
        }
 
        /// 
        /// This function decrypts cipher text content. 
        /// The length, in bytes, of the buffer holding content to be encrypted should be a multiple of the 
        /// block cipher block size.
        ///  
        public byte[] Decrypt(byte[] cryptoText)
        {
            SecurityHelper.DemandRightsManagementPermission();
            CheckDisposed(); 

            if (cryptoText == null) 
            { 
                throw new ArgumentNullException("cryptoText");
            } 

            // validation of the proper size of the cryptoText is done by the unmanaged libraries

            if (!CanDecrypt) 
            {
                throw new RightsManagementException(RightsManagementFailureCode.RightNotGranted); 
            } 

            // first get the size 
            uint outputBufferSize=0;
            byte[] outputBuffer = null;
            int hr;
 
#if DEBUG
            hr= SafeNativeMethods.DRMDecrypt( 
                            DecryptorHandle, 
                            0,
                            (uint)cryptoText.Length, 
                            cryptoText,
                            ref outputBufferSize,
                            null);
            Errors.ThrowOnErrorCode(hr); 

            // We do not expect Decryption changing the size of the buffer; otherwise it will break 
            // basic assumptions behind the encrypted compound file envelope format 
            Invariant.Assert(outputBufferSize == cryptoText.Length);
#else 
            outputBufferSize = (uint)cryptoText.Length;
#endif

            outputBuffer = new byte[outputBufferSize]; 

            // THis will decrypt content 
            hr = SafeNativeMethods.DRMDecrypt( 
                            DecryptorHandle,
                            0, 
                            (uint)cryptoText.Length,
                            cryptoText,
                            ref outputBufferSize,
                            outputBuffer); 

            Errors.ThrowOnErrorCode(hr); 
            return outputBuffer; 
        }
 
        //------------------------------------------------------
        //
        //  Protected Methods
        // 
        //-----------------------------------------------------
 
        ///  
        /// Dispose(bool)
        ///  
        /// 
        protected virtual void Dispose(bool disposing)
        {
            // close bound license handle which is a DRMHANDLE 
            // Encryptor and Decryptor handles as well
            try 
            { 
                if (disposing)
                { 

                    if (_decryptorHandle != null && !_decryptorHandle.IsInvalid)
                        _decryptorHandle.Close();
 
                    if (_encryptorHandle != null && !_encryptorHandle.IsInvalid)
                        _encryptorHandle.Close(); 
 
                    if (_boundLicenseOwnerViewRightsHandle != null && !_boundLicenseOwnerViewRightsHandle.IsInvalid)
                        _boundLicenseOwnerViewRightsHandle.Close(); 

                    // dispose collection of the bound licenses that we have
                    if (_boundLicenseHandleList != null)
                    { 
                        foreach(SafeRightsManagementHandle boundLicenseHandle in _boundLicenseHandleList)
                        { 
                            if (boundLicenseHandle != null && !boundLicenseHandle.IsInvalid) 
                                boundLicenseHandle.Close();
                        } 
                    }
                }
            }
            finally 
            {
                _disposed = true; 
                _boundLicenseHandleList = null; 
                _boundLicenseOwnerViewRightsHandle = null;
                _decryptorHandle    = null; 
                _encryptorHandle    = null;
            }
        }
 
        //------------------------------------------------------
        // 
        //  Public Properties 
        //
        //------------------------------------------------------ 

        /// 
        /// This is bock size of the cypther that is currently in use.
        ///  
        public int BlockSize
        { 
            get 
            {
                SecurityHelper.DemandRightsManagementPermission(); 
                CheckDisposed();

                if (_blockSize ==0)
                { 
                    _blockSize = QueryBlockSize();
                } 
                return _blockSize; 
            }
        } 

        /// 
        /// This bollean indicates wheter Encrypt Decrypt calls can be made on buffers that are multiple of the BlockSize value.
        /// If the value is false Encrypt Decrypt calls must be made on buffers of the size that is exactly equal to the BlockSize. 
        /// 
        public bool CanMergeBlocks 
        { 
            get
            { 
                SecurityHelper.DemandRightsManagementPermission();
                CheckDisposed();

                // convention is to return 1 for stream ciphers 
                // Stream ciphers (although currently not used) return 1.
                // Block ciphers return size of the block that is always greater than 1. 
                // Comparing block size to 1 is a conventional way to differentiate stream and 
                // block ciphers. Block Ciphers can accept data chunks (for both encryption and decryption)
                // that fall on the block boundary and are a multiple of the block cipher block size. 
                return (BlockSize > 1);
            }
        }
 
        /// 
        /// This is a read only property. It enable client application to enumerate list of rights that were 
        /// granted to the user, and also passed all the verification checks. 
        /// 
        public ReadOnlyCollection BoundGrants 
        {
            get
            {
                SecurityHelper.DemandRightsManagementPermission(); 
                CheckDisposed();
 
                if (_boundGrantReadOnlyCollection == null) 
                {
                    // we need to enumerate all the rights and keep the ones that we can translate into enum 
                    // we ignore the rights that we can not translate for forward compatibility reasons
                    List grantList = new List(_boundRightsInfoList.Count);

                    foreach(RightNameExpirationInfoPair rightsInfo in _boundRightsInfoList) 
                    {
                        Nullable contentRight = ClientSession.GetRightFromString(rightsInfo.RightName); 
 
                        if (contentRight != null)
                        { 
                            grantList.Add(new ContentGrant(_owner, contentRight.Value, rightsInfo.ValidFrom, rightsInfo.ValidUntil));
                        }
                    }
                    _boundGrantReadOnlyCollection = new ReadOnlyCollection (grantList); 
                }
                return _boundGrantReadOnlyCollection; 
            } 
        }
 

        /// 
        /// Depending on the set of rights ggranted to the user he or she can do Encryption, Decryption or both.
        /// this property checks whether user was granted rights to encrypt, which means that he or she was granted 
        /// either an Edit or an Owner right.
        ///  
        public bool CanEncrypt 
        {
            get 
            {
                SecurityHelper.DemandRightsManagementPermission();
                CheckDisposed();
 
                return (!EncryptorHandle.IsInvalid);
            } 
        } 

        ///  
        /// Depending on the set of rights granted to the user he or she can do Encryption, Decryption or both.
        /// this property checks whether user was granted rights to decrypt. Decryption is given to a user if he or
        /// she was able to successfully bind any right (View, Edit, Print, Owner, ....)
        ///  
        public bool CanDecrypt
        { 
            get 
            {
                SecurityHelper.DemandRightsManagementPermission(); 
                CheckDisposed();

                return (!DecryptorHandle.IsInvalid);
            } 
        }
 
        //----------------------------------------------------- 
        //
        //  Internal Constructor 
        //
        //------------------------------------------------------

        ///  
        /// Constructor.
        ///  
        internal CryptoProvider(List boundLicenseHandleList, 
                                                        List rightsInfoList,
                                                        ContentUser owner) 
        {
            Invariant.Assert(boundLicenseHandleList != null);
            Invariant.Assert(boundLicenseHandleList.Count > 0);
 
            Invariant.Assert(rightsInfoList != null);
            Invariant.Assert(rightsInfoList.Count > 0); 
 
            // we expect a match between lists of the Right Information and the bound license handles
            // we will be mapping those lists based on indexes 
            Invariant.Assert(rightsInfoList.Count == boundLicenseHandleList.Count);

            Invariant.Assert(owner != null);
 
            _boundLicenseHandleList = boundLicenseHandleList;
            _boundRightsInfoList = rightsInfoList; 
 
            _owner = owner;
        } 

        //-----------------------------------------------------
        //
        //  Internal Methods 
        //
        //----------------------------------------------------- 
 
        internal UnsignedPublishLicense DecryptPublishLicense(string serializedPublishLicense)
        { 
            Invariant.Assert(serializedPublishLicense != null);

            if ((BoundLicenseOwnerViewRightsHandle == null ) || BoundLicenseOwnerViewRightsHandle.IsInvalid)
            { 
                throw new RightsManagementException(RightsManagementFailureCode.RightNotGranted);
            } 
            else 
            {
                return new UnsignedPublishLicense(BoundLicenseOwnerViewRightsHandle, serializedPublishLicense); 
            }
        }

        //----------------------------------------------------- 
        //
        //  Private Methods 
        // 
        //------------------------------------------------------
 
        /// 
        /// Call this before accepting any API call
        /// 
        private void CheckDisposed() 
        {
            if (_disposed) 
                throw new ObjectDisposedException(null, SR.Get(SRID.CryptoProviderDisposed)); 
        }
 

        private int QueryBlockSize()
        {
            uint attributeSize = 0; 
            byte[] dataBuffer = null;
 
            uint encodingType; 

            int hr = SafeNativeMethods.DRMGetInfo(DecryptorHandle, 
                                                    NativeConstants.QUERY_BLOCKSIZE,
                                                    out encodingType,
                                                    ref attributeSize,
                                                    null); 
            Errors.ThrowOnErrorCode(hr);
 
            // it must return 4 bytes for block size 
            Invariant.Assert(attributeSize == 4);
 
            dataBuffer = new byte[(int)attributeSize];  // this cast is safe based on the Invariant.Assert above.

            hr = SafeNativeMethods.DRMGetInfo(DecryptorHandle,
                                                NativeConstants.QUERY_BLOCKSIZE, 
                                                out encodingType,
                                                ref attributeSize, 
                                                dataBuffer); 
            Errors.ThrowOnErrorCode(hr);
 
            return BitConverter.ToInt32(dataBuffer,0);
        }

        //----------------------------------------------------- 
        //
        //  Private Properties 
        // 
        //------------------------------------------------------
 
        private SafeRightsManagementHandle DecryptorHandle
        {
            get
            { 
                if(!_decryptorHandleCalculated)
                { 
                    for(int i=0; i< _boundLicenseHandleList.Count; i++) 
                    {
                        SafeRightsManagementHandle decryptorHandle = null; 

                        int hr = SafeNativeMethods.DRMCreateEnablingBitsDecryptor(
                            _boundLicenseHandleList[i],
                            _boundRightsInfoList[i].RightName, 
                            0,
                            null, 
                            out decryptorHandle); 

                        if (hr == 0) 
                        {
                            Debug.Assert(decryptorHandle != null);

                            _decryptorHandle = decryptorHandle; 
                             _decryptorHandleCalculated = true;
                             return _decryptorHandle; 
                        } 
                    }
                    _decryptorHandleCalculated = true; // if we got here it means we couldn't find anything; regardless 
                                                                         // we should still mark this calculation as complete
                }
                return _decryptorHandle;
            } 
        }
 
        private SafeRightsManagementHandle EncryptorHandle 
        {
            get 
            {
                if(!_encryptorHandleCalculated)
                {
                    for(int i=0; i< _boundLicenseHandleList.Count; i++) 
                    {
                        SafeRightsManagementHandle encryptorHandle = null; 
                        int hr = SafeNativeMethods.DRMCreateEnablingBitsEncryptor( 
                            _boundLicenseHandleList[i],
                            _boundRightsInfoList[i].RightName, 
                            0,
                            null,
                            out encryptorHandle);
 
                        if (hr == 0)
                        { 
                            Debug.Assert(encryptorHandle != null); 

                            _encryptorHandle = encryptorHandle; 
                            _encryptorHandleCalculated = true;
                            return _encryptorHandle;
                        }
                    } 
                    _encryptorHandleCalculated = true; // if we got here it means we couldn't find anything; regardless
                                                                             // we should still mark this calculation as complete 
                } 
                return _encryptorHandle;
            } 
        }


        private SafeRightsManagementHandle BoundLicenseOwnerViewRightsHandle 
        {
            get 
            { 
                if(!_boundLicenseOwnerViewRightsHandleCalculated)
                { 
                    for(int i=0; i< _boundLicenseHandleList.Count; i++)
                    {
                        Nullable right =
                                        ClientSession.GetRightFromString(_boundRightsInfoList[i].RightName); 

                        if ((right != null) 
                                && 
                            ((right.Value == ContentRight.Owner) ||(right.Value== ContentRight.ViewRightsData)))
                        { 
                            _boundLicenseOwnerViewRightsHandle = _boundLicenseHandleList[i];
                            _boundLicenseOwnerViewRightsHandleCalculated = true;
                            return _boundLicenseOwnerViewRightsHandle;
                        } 
                    }
                    _boundLicenseOwnerViewRightsHandleCalculated = true; // if we got here it means we couldn't find anything; regardless 
                                                                         // we should still mark this calculation as complete 
                }
                return _boundLicenseOwnerViewRightsHandle; 
            }
        }

        //------------------------------------------------------ 
        //
        //  Private Fields 
        // 
        //-----------------------------------------------------
 
        private int _blockSize;

        private SafeRightsManagementHandle _decryptorHandle = SafeRightsManagementHandle.InvalidHandle;
        private bool _decryptorHandleCalculated; 

        private SafeRightsManagementHandle _encryptorHandle = SafeRightsManagementHandle.InvalidHandle; 
        private bool _encryptorHandleCalculated; 

        private SafeRightsManagementHandle _boundLicenseOwnerViewRightsHandle = SafeRightsManagementHandle.InvalidHandle; 
        private bool _boundLicenseOwnerViewRightsHandleCalculated;

        // if this is Invalid, we are disposed
        private List _boundLicenseHandleList; 
        private List _boundRightsInfoList;
 
        private ReadOnlyCollection _boundGrantReadOnlyCollection; 
        private ContentUser _owner;
 
        private bool _disposed;
    }
}

// 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