DeobfuscatingStream.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / MS / Internal / IO / Packaging / DeobfuscatingStream.cs / 1305600 / DeobfuscatingStream.cs

                            //------------------------------------------------------------------------------ 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: 
//  This class provides stream implementation that de-obfuscates the bytes that are obfuscated in accordance 
//      with the section under Embbedded Font Obfuscation in the XPS spec.
// 
//  Recap of font obfuscation:
//      1. Generate a 128-bit GUID (a 128-bit random number may be use instead)
//      2. Generate a part name using the GUID
//      3. XOR the first 32 bytes of the binary data of the font with the binary representation of the GUID 
//      4. in the step #3, start with the LSB of the binary GUID
// 
// Notes: 
//  The stream is read only
// 
// History:
//  05/23/05: [....]: Initial implementation.
//-----------------------------------------------------------------------------
 
using System;
using System.IO; 
using System.IO.Packaging; 

using MS.Internal.PresentationCore;     // for ExceptionStringTable 

namespace MS.Internal.IO.Packaging
{
    //----------------------------------------------------- 
    //
    //  Internal Members 
    // 
    //-----------------------------------------------------
    ///  
    /// Wrapper stream that returns de-obfuscated bytes from obfuscated stream
    /// 
    internal class DeobfuscatingStream : Stream
    { 
        //------------------------------------------------------
        // 
        //  Public Methods 
        //
        //----------------------------------------------------- 
        #region Stream Methods
        /// 
        /// Read bytes from the stream
        ///  
        /// destination buffer
        /// offset to read into that buffer 
        /// how many bytes requested 
        /// how many bytes were wread .
        public override int Read(byte[] buffer, int offset, int count) 
        {
            CheckDisposed();

            long readPosition = _obfuscatedStream.Position; 

            // Read in the raw data from the underlying stream 
            int bytesRead = _obfuscatedStream.Read(buffer, offset, count); 

            // Apply de-obfuscatation as necessary 
            Deobfuscate(buffer, offset, bytesRead, readPosition);

            return bytesRead;
        } 

        ///  
        /// Write 
        /// 
        /// This is a read-only stream; throw now supported exception 
        public override void Write(byte[] buffer, int offset, int count)
        {
            CheckDisposed();
 
            throw new NotSupportedException(SR.Get(SRID.WriteNotSupported));
        } 
 
        /// 
        /// Seek 
        /// 
        /// offset
        /// origin
        public override long Seek(long offset, SeekOrigin origin) 
        {
            CheckDisposed(); 
 
            return _obfuscatedStream.Seek(offset, origin);
        } 

        /// 
        /// SetLength
        ///  
        /// This is a read-only stream; throw now supported exception
        public override void SetLength(long newLength) 
        { 
            CheckDisposed();
 
            throw new NotSupportedException(SR.Get(SRID.SetLengthNotSupported));
       }

        ///  
        /// Flush
        ///  
        public override void Flush() 
        {
            CheckDisposed(); 

            _obfuscatedStream.Flush();
        }
        #endregion Stream Methods 

        #region Stream Properties 
        ///  
        /// Current position of the stream
        ///  
        public override long Position
        {
            get
            { 
                CheckDisposed();
 
                return _obfuscatedStream.Position; 
            }
            set 
            {
                CheckDisposed();

                _obfuscatedStream.Position = value; 
            }
        } 
 
        /// 
        /// Length 
        /// 
        public override long Length
        {
            get 
            {
                return _obfuscatedStream.Length; 
            } 
        }
 
        /// 
        /// Is stream readable?
        /// 
        /// returns false when called on disposed stream 
        public override bool CanRead
        { 
            get 
            {
                // cannot read from a close stream, but don't throw if asked 
                return (_obfuscatedStream != null) && _obfuscatedStream.CanRead;
            }
        }
 
        /// 
        /// Is stream seekable 
        ///  
        /// returns false when called on disposed stream
        public override bool CanSeek 
        {
            get
            {
                // cannot seek on a close stream, but don't throw if asked 
                return (_obfuscatedStream != null) && _obfuscatedStream.CanSeek;
            } 
        } 

        ///  
        /// Is stream writeable?
        /// 
        /// returns false always since it is a read-only stream
        public override bool CanWrite 
        {
            get 
            { 
                return false;
            } 
        }
        #endregion

        #region Internal 
        //------------------------------------------------------
        // 
        //  Internal Constructors 
        //
        //------------------------------------------------------ 
        /// 
        /// Constructor
        /// 
        /// stream that holds obfuscated resource 
        /// the original Uri which is used to obtain obfuscatedStream; it holds
        ///                         the GUID information which is used to obfuscate the resources 
        /// if it is false, obfuscatedStream will be also disposed when 
        ///                         DeobfuscatingStream is disposed
        /// streamUri has to be a pack Uri 
        internal DeobfuscatingStream(Stream obfuscatedStream, Uri streamUri, bool leaveOpen)
        {
            if (obfuscatedStream == null)
            { 
                throw new ArgumentNullException("obfuscatedStream");
            } 
 
            // Make sure streamUri is in the correct form; getting partUri from it will do all necessary checks for error
            //    conditions; We also have to make sure that it has a part name 
            Uri partUri = PackUriHelper.GetPartUri(streamUri);
            if (partUri == null)
            {
                throw new InvalidOperationException(SR.Get(SRID.InvalidPartName)); 
            }
 
            // Normally we should use PackUriHelper.GetStringForPartUri to get the string representation of part Uri 
            //    however, since we already made sure that streamUris is in the correct form (such as to check if it is an absolute Uri
            //    and there is a correct authority (package)), it doesn't have to be fully validated again. 
            // Get the escaped string for the part name as part names should have only ascii characters
            String guid = Path.GetFileNameWithoutExtension(
                                    streamUri.GetComponents(UriComponents.Path | UriComponents.KeepDelimiter, UriFormat.UriEscaped));
 
            _guid = GetGuidByteArray(guid);
            _obfuscatedStream = obfuscatedStream; 
            _ownObfuscatedStream = !leaveOpen; 
        }
 
        #endregion

        //-----------------------------------------------------
        // 
        //  Protected Methods
        // 
        //------------------------------------------------------ 
        /// 
        /// Dispose(bool) 
        /// 
        /// 
        /// We implement this because we want a consistent experience (essentially Flush our data) if the user chooses to
        /// call Dispose() instead of Close(). 
        protected override void Dispose(bool disposing)
        { 
            try 
            {
                if (disposing) 
                {
                    // If this class owns the underlying steam, close it
                    if (_obfuscatedStream != null && _ownObfuscatedStream)
                    { 
                        _obfuscatedStream.Close();
                    } 
                    _obfuscatedStream = null; 
                }
            } 
            finally
            {
                base.Dispose(disposing);
            } 
        }
 
        #region Private 
        //-----------------------------------------------------
        // 
        //  Private Properties
        //
        //-----------------------------------------------------
        //----------------------------------------------------- 
        //
        //  Private Methods 
        // 
        //------------------------------------------------------
        ///  
        /// Call this before accepting any public API call (except some Stream calls that
        /// are allowed to respond even when Closed
        /// 
        private void CheckDisposed() 
        {
            if (_obfuscatedStream == null) 
                throw new ObjectDisposedException(null, SR.Get(SRID.Media_StreamClosed)); 
        }
 
        /// 
        /// Apply de-obfuscation as necessary (the first 32 bytes of the underlying stream are obfuscated
        /// 
        private void Deobfuscate(byte[] buffer, int offset, int count, long readPosition) 
        {
            // only the first 32 bytes of the underlying stream are obfuscated 
            //   if the read position is beyond offset 32, there is no need to do de-obfuscation 
            if (readPosition >= ObfuscatedLength || count <= 0)
                return; 

            // Find out how many bytes in the buffer are needed to be XORed
            // Note on casting:
            //      count can be safely cast to long since it is int 
            //      We don't need to check for overflow of (readPosition + (long) count) since count is int and readPosition is less than
            //          ObfuscatedLength 
            //      The result of (Math.Min(ObfuscatedLength, readPosition + (long) count) - readPosition) can be safely cast to int 
            //          since it cannot be bigger than ObfuscatedLength which is 32
            int bytesToXor = (int) (Math.Min(ObfuscatedLength, unchecked (readPosition + (long) count)) - readPosition); 

            int guidBytePosition = _guid.Length - ((int) readPosition % _guid.Length) - 1;

            for (int i = offset; bytesToXor > 0; --bytesToXor, ++i, --guidBytePosition) 
            {
                // If we exhausted the Guid bytes, go back to the least significant byte 
                if (guidBytePosition < 0) 
                    guidBytePosition = _guid.Length - 1;
 
                // XOR the obfuscated byte with the appropriate byte from the Guid byte array
                buffer[i] ^= _guid[guidBytePosition];
            }
        } 

        ///  
        /// Returns the byte representation of guidString 
        /// 
        ///  
        /// We cannot use Guid.GetByteArray directly due to little or big endian issues
        /// Guid is defined as below:
        /// typedef struct _GUID
        /// { 
        ///     DWORD Data1;
        ///     WORD Data2; 
        ///     WORD Data3; 
        ///     BYTE Data4[8];
        ///  } GUID; 
        /// So, Guid.GetByteArray returns a byte array where the first 8 bytes are ordered according to a specific endian format
        /// 
        private static byte[] GetGuidByteArray(string guidString)
        { 
            // Make sure we have at least on '-' since Guid constructor will take both dash'ed and non-dash'ed format of GUID string
            //  while XPS spec requires dash'ed format of GUID 
            if (guidString.IndexOf('-') == -1) 
            {
                throw new ArgumentException(SR.Get(SRID.InvalidPartName)); 
            }

            // Use Guid constructor to do error checking in parsing
            Guid guid = new Guid(guidString); 

            // Convert the GUID into string in 32 digits format (xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) 
            string wellFormedGuidString = guid.ToString("N"); 

            // Now it is safe to do parsing of the well-formed GUID string 
            byte[] guidBytes = new byte[16];

            // We don't need to check the length of wellFormedGuidString since it is guaranteed to be 32
            for (int i = 0; i < guidBytes.Length; i++) 
            {
                guidBytes[i] = Convert.ToByte(wellFormedGuidString.Substring(i * 2, 2), 16); 
            } 

            return guidBytes; 
        }

        //-----------------------------------------------------
        // 
        //  Private Variables
        // 
        //------------------------------------------------------ 

        private Stream  _obfuscatedStream;        // stream we ultimately decompress from and to in the container 
        private byte[] _guid;
        private bool _ownObfuscatedStream;      // Does this class own the underlying stream?
                                                                    //  if it does, it should dispose the underlying stream when this class is disposed
        private const long ObfuscatedLength = 32; 
        #endregion
    } 
} 

// 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 provides stream implementation that de-obfuscates the bytes that are obfuscated in accordance 
//      with the section under Embbedded Font Obfuscation in the XPS spec.
// 
//  Recap of font obfuscation:
//      1. Generate a 128-bit GUID (a 128-bit random number may be use instead)
//      2. Generate a part name using the GUID
//      3. XOR the first 32 bytes of the binary data of the font with the binary representation of the GUID 
//      4. in the step #3, start with the LSB of the binary GUID
// 
// Notes: 
//  The stream is read only
// 
// History:
//  05/23/05: [....]: Initial implementation.
//-----------------------------------------------------------------------------
 
using System;
using System.IO; 
using System.IO.Packaging; 

using MS.Internal.PresentationCore;     // for ExceptionStringTable 

namespace MS.Internal.IO.Packaging
{
    //----------------------------------------------------- 
    //
    //  Internal Members 
    // 
    //-----------------------------------------------------
    ///  
    /// Wrapper stream that returns de-obfuscated bytes from obfuscated stream
    /// 
    internal class DeobfuscatingStream : Stream
    { 
        //------------------------------------------------------
        // 
        //  Public Methods 
        //
        //----------------------------------------------------- 
        #region Stream Methods
        /// 
        /// Read bytes from the stream
        ///  
        /// destination buffer
        /// offset to read into that buffer 
        /// how many bytes requested 
        /// how many bytes were wread .
        public override int Read(byte[] buffer, int offset, int count) 
        {
            CheckDisposed();

            long readPosition = _obfuscatedStream.Position; 

            // Read in the raw data from the underlying stream 
            int bytesRead = _obfuscatedStream.Read(buffer, offset, count); 

            // Apply de-obfuscatation as necessary 
            Deobfuscate(buffer, offset, bytesRead, readPosition);

            return bytesRead;
        } 

        ///  
        /// Write 
        /// 
        /// This is a read-only stream; throw now supported exception 
        public override void Write(byte[] buffer, int offset, int count)
        {
            CheckDisposed();
 
            throw new NotSupportedException(SR.Get(SRID.WriteNotSupported));
        } 
 
        /// 
        /// Seek 
        /// 
        /// offset
        /// origin
        public override long Seek(long offset, SeekOrigin origin) 
        {
            CheckDisposed(); 
 
            return _obfuscatedStream.Seek(offset, origin);
        } 

        /// 
        /// SetLength
        ///  
        /// This is a read-only stream; throw now supported exception
        public override void SetLength(long newLength) 
        { 
            CheckDisposed();
 
            throw new NotSupportedException(SR.Get(SRID.SetLengthNotSupported));
       }

        ///  
        /// Flush
        ///  
        public override void Flush() 
        {
            CheckDisposed(); 

            _obfuscatedStream.Flush();
        }
        #endregion Stream Methods 

        #region Stream Properties 
        ///  
        /// Current position of the stream
        ///  
        public override long Position
        {
            get
            { 
                CheckDisposed();
 
                return _obfuscatedStream.Position; 
            }
            set 
            {
                CheckDisposed();

                _obfuscatedStream.Position = value; 
            }
        } 
 
        /// 
        /// Length 
        /// 
        public override long Length
        {
            get 
            {
                return _obfuscatedStream.Length; 
            } 
        }
 
        /// 
        /// Is stream readable?
        /// 
        /// returns false when called on disposed stream 
        public override bool CanRead
        { 
            get 
            {
                // cannot read from a close stream, but don't throw if asked 
                return (_obfuscatedStream != null) && _obfuscatedStream.CanRead;
            }
        }
 
        /// 
        /// Is stream seekable 
        ///  
        /// returns false when called on disposed stream
        public override bool CanSeek 
        {
            get
            {
                // cannot seek on a close stream, but don't throw if asked 
                return (_obfuscatedStream != null) && _obfuscatedStream.CanSeek;
            } 
        } 

        ///  
        /// Is stream writeable?
        /// 
        /// returns false always since it is a read-only stream
        public override bool CanWrite 
        {
            get 
            { 
                return false;
            } 
        }
        #endregion

        #region Internal 
        //------------------------------------------------------
        // 
        //  Internal Constructors 
        //
        //------------------------------------------------------ 
        /// 
        /// Constructor
        /// 
        /// stream that holds obfuscated resource 
        /// the original Uri which is used to obtain obfuscatedStream; it holds
        ///                         the GUID information which is used to obfuscate the resources 
        /// if it is false, obfuscatedStream will be also disposed when 
        ///                         DeobfuscatingStream is disposed
        /// streamUri has to be a pack Uri 
        internal DeobfuscatingStream(Stream obfuscatedStream, Uri streamUri, bool leaveOpen)
        {
            if (obfuscatedStream == null)
            { 
                throw new ArgumentNullException("obfuscatedStream");
            } 
 
            // Make sure streamUri is in the correct form; getting partUri from it will do all necessary checks for error
            //    conditions; We also have to make sure that it has a part name 
            Uri partUri = PackUriHelper.GetPartUri(streamUri);
            if (partUri == null)
            {
                throw new InvalidOperationException(SR.Get(SRID.InvalidPartName)); 
            }
 
            // Normally we should use PackUriHelper.GetStringForPartUri to get the string representation of part Uri 
            //    however, since we already made sure that streamUris is in the correct form (such as to check if it is an absolute Uri
            //    and there is a correct authority (package)), it doesn't have to be fully validated again. 
            // Get the escaped string for the part name as part names should have only ascii characters
            String guid = Path.GetFileNameWithoutExtension(
                                    streamUri.GetComponents(UriComponents.Path | UriComponents.KeepDelimiter, UriFormat.UriEscaped));
 
            _guid = GetGuidByteArray(guid);
            _obfuscatedStream = obfuscatedStream; 
            _ownObfuscatedStream = !leaveOpen; 
        }
 
        #endregion

        //-----------------------------------------------------
        // 
        //  Protected Methods
        // 
        //------------------------------------------------------ 
        /// 
        /// Dispose(bool) 
        /// 
        /// 
        /// We implement this because we want a consistent experience (essentially Flush our data) if the user chooses to
        /// call Dispose() instead of Close(). 
        protected override void Dispose(bool disposing)
        { 
            try 
            {
                if (disposing) 
                {
                    // If this class owns the underlying steam, close it
                    if (_obfuscatedStream != null && _ownObfuscatedStream)
                    { 
                        _obfuscatedStream.Close();
                    } 
                    _obfuscatedStream = null; 
                }
            } 
            finally
            {
                base.Dispose(disposing);
            } 
        }
 
        #region Private 
        //-----------------------------------------------------
        // 
        //  Private Properties
        //
        //-----------------------------------------------------
        //----------------------------------------------------- 
        //
        //  Private Methods 
        // 
        //------------------------------------------------------
        ///  
        /// Call this before accepting any public API call (except some Stream calls that
        /// are allowed to respond even when Closed
        /// 
        private void CheckDisposed() 
        {
            if (_obfuscatedStream == null) 
                throw new ObjectDisposedException(null, SR.Get(SRID.Media_StreamClosed)); 
        }
 
        /// 
        /// Apply de-obfuscation as necessary (the first 32 bytes of the underlying stream are obfuscated
        /// 
        private void Deobfuscate(byte[] buffer, int offset, int count, long readPosition) 
        {
            // only the first 32 bytes of the underlying stream are obfuscated 
            //   if the read position is beyond offset 32, there is no need to do de-obfuscation 
            if (readPosition >= ObfuscatedLength || count <= 0)
                return; 

            // Find out how many bytes in the buffer are needed to be XORed
            // Note on casting:
            //      count can be safely cast to long since it is int 
            //      We don't need to check for overflow of (readPosition + (long) count) since count is int and readPosition is less than
            //          ObfuscatedLength 
            //      The result of (Math.Min(ObfuscatedLength, readPosition + (long) count) - readPosition) can be safely cast to int 
            //          since it cannot be bigger than ObfuscatedLength which is 32
            int bytesToXor = (int) (Math.Min(ObfuscatedLength, unchecked (readPosition + (long) count)) - readPosition); 

            int guidBytePosition = _guid.Length - ((int) readPosition % _guid.Length) - 1;

            for (int i = offset; bytesToXor > 0; --bytesToXor, ++i, --guidBytePosition) 
            {
                // If we exhausted the Guid bytes, go back to the least significant byte 
                if (guidBytePosition < 0) 
                    guidBytePosition = _guid.Length - 1;
 
                // XOR the obfuscated byte with the appropriate byte from the Guid byte array
                buffer[i] ^= _guid[guidBytePosition];
            }
        } 

        ///  
        /// Returns the byte representation of guidString 
        /// 
        ///  
        /// We cannot use Guid.GetByteArray directly due to little or big endian issues
        /// Guid is defined as below:
        /// typedef struct _GUID
        /// { 
        ///     DWORD Data1;
        ///     WORD Data2; 
        ///     WORD Data3; 
        ///     BYTE Data4[8];
        ///  } GUID; 
        /// So, Guid.GetByteArray returns a byte array where the first 8 bytes are ordered according to a specific endian format
        /// 
        private static byte[] GetGuidByteArray(string guidString)
        { 
            // Make sure we have at least on '-' since Guid constructor will take both dash'ed and non-dash'ed format of GUID string
            //  while XPS spec requires dash'ed format of GUID 
            if (guidString.IndexOf('-') == -1) 
            {
                throw new ArgumentException(SR.Get(SRID.InvalidPartName)); 
            }

            // Use Guid constructor to do error checking in parsing
            Guid guid = new Guid(guidString); 

            // Convert the GUID into string in 32 digits format (xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) 
            string wellFormedGuidString = guid.ToString("N"); 

            // Now it is safe to do parsing of the well-formed GUID string 
            byte[] guidBytes = new byte[16];

            // We don't need to check the length of wellFormedGuidString since it is guaranteed to be 32
            for (int i = 0; i < guidBytes.Length; i++) 
            {
                guidBytes[i] = Convert.ToByte(wellFormedGuidString.Substring(i * 2, 2), 16); 
            } 

            return guidBytes; 
        }

        //-----------------------------------------------------
        // 
        //  Private Variables
        // 
        //------------------------------------------------------ 

        private Stream  _obfuscatedStream;        // stream we ultimately decompress from and to in the container 
        private byte[] _guid;
        private bool _ownObfuscatedStream;      // Does this class own the underlying stream?
                                                                    //  if it does, it should dispose the underlying stream when this class is disposed
        private const long ObfuscatedLength = 32; 
        #endregion
    } 
} 

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