Mega Code Archive

 
Categories / C# / File Stream
 

Authentication Stream

// (c) Copyright slimCODE Software Inc. - www.slimcode.com // This source is subject to the Microsoft Public License (Ms-PL). // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details. // All other rights reserved. using System; using System.Collections.Generic; using System.IO; using System.Security.Cryptography; using System.Text; namespace SlimCode.Utils {   internal class AuthenticationStream : Stream   {     public AuthenticationStream( Stream innerStream, byte[] authenticationKey, AuthenticationType authenticationType, bool writing )     {       if( innerStream == null )         throw new ArgumentNullException( "innerStream" );       if( writing && !innerStream.CanWrite )         throw new ArgumentException( "Cannot write to inner stream.", "innerStream" );       if( !writing && !innerStream.CanRead )         throw new ArgumentException( "Cannot read from inner stream.", "innerStream" );       if( authenticationKey == null )         throw new ArgumentNullException( "authenticationKey" );       if( authenticationKey.Length < 16 )         throw new ArgumentException( "The authentication key cannot be less than 16 bytes." );       switch( authenticationType )       {         case AuthenticationType.MD5:           m_hmac = new HMACMD5( authenticationKey );           break;         case AuthenticationType.SHA1:           m_hmac = new HMACSHA1( authenticationKey, true );           break;         case AuthenticationType.SHA256:           m_hmac = new HMACSHA256( authenticationKey );           break;         case AuthenticationType.SHA384:           m_hmac = new HMACSHA384( authenticationKey );           break;         case AuthenticationType.SHA512:           m_hmac = new HMACSHA512( authenticationKey );           break;         default:           throw new ArgumentException( "Unknown authentication type.", "authenticationType" );       }       m_innerStream = innerStream;       m_writing = writing;     }     public override bool CanRead     {       get { return !m_writing; }     }     public override bool CanSeek     {       get { return false; }     }     public override bool CanWrite     {       get { return m_writing; }     }     public override void Flush()     {       m_innerStream.Flush();     }     public override long Length     {       get { return m_innerStream.Length; }     }     public override long Position     {       get { return m_innerStream.Position; }       set { throw new NotSupportedException( "This stream does not support seeking." ); }     }     public override int Read( byte[] buffer, int offset, int count )     {       if( m_writing )         throw new IOException( "Cannot read from this stream. It is open for writing." );       if( buffer == null )         throw new ArgumentNullException( "buffer" );       if( ( offset < 0 ) || ( offset >= buffer.Length ) )         throw new ArgumentOutOfRangeException( "offset" );       if( count < 0 )         throw new ArgumentOutOfRangeException( "count" );       if( offset + count > buffer.Length )         throw new ArgumentOutOfRangeException( "count" );       if( count == 0 )         return 0;       int read = 0;       int hashSize = m_hmac.HashSize / 8;       if( m_bufferAvailable > hashSize )       {         read = ( count < ( m_bufferAvailable - hashSize ) ) ? ( count ) : ( m_bufferAvailable - hashSize );         Array.Copy( m_buffer, 0, buffer, offset, read );         m_hmac.TransformBlock( buffer, offset, read, buffer, offset );         offset += read;         count -= read;                  m_bufferAvailable -= read;         Array.Copy( m_buffer, read, m_buffer, 0, m_bufferAvailable );       }       if( count > 0 )       {         int innerRead = m_innerStream.Read( m_buffer, m_bufferAvailable, m_buffer.Length - m_bufferAvailable );         if( innerRead > 0 )         {           m_bufferAvailable += innerRead;           read += this.Read( buffer, offset, count );         }       }       return read;     }     public override long Seek( long offset, SeekOrigin origin )     {       throw new NotSupportedException( "This stream does not support seeking." );     }     public override void SetLength( long value )     {       throw new NotSupportedException( "This stream does not support seeking." );     }     public override void Write( byte[] buffer, int offset, int count )     {       if( !m_writing )         throw new IOException( "Cannot write to this stream. It is open for reading." );       if( buffer == null )         throw new ArgumentNullException( "buffer" );       if( ( offset < 0 ) || ( offset >= buffer.Length ) )         throw new ArgumentOutOfRangeException( "offset" );       if( count < 0 )         throw new ArgumentOutOfRangeException( "count" );       if( offset + count > buffer.Length )         throw new ArgumentOutOfRangeException( "count" );       if( count > 0 )       {         m_hmac.TransformBlock( buffer, offset, count, buffer, offset );         m_innerStream.Write( buffer, offset, count );       }     }     protected override void Dispose( bool disposing )     {       try       {         if( disposing )         {           m_hmac.TransformFinalBlock( new byte[ 0 ], 0, 0 );           byte[] hash = m_hmac.Hash;           System.Diagnostics.Trace.Assert( hash.Length == ( m_hmac.HashSize / 8 ) );           if( m_writing )           {             System.Diagnostics.Trace.Assert( hash.Length == ( m_hmac.HashSize / 8 ) );             m_innerStream.Write( hash, 0, hash.Length );           }           else           {             if( hash.Length != m_bufferAvailable )               throw new IOException( "Invalid authentication hash length." );             for( int i = 0; i < hash.Length; i++ )             {               if( hash[ i ] != m_buffer[ i ] )                 throw new IOException( "Invalid authentication hash signature." );             }           }           m_innerStream.Close();           ( ( IDisposable )m_hmac ).Dispose();         }         m_innerStream = null;         m_hmac = null;       }       finally       {         base.Dispose( disposing );       }     }     private byte[] m_buffer = new byte[ 32768 ];     private int m_bufferAvailable; // = 0     private Stream m_innerStream; // = null     private bool m_writing; // = false     private HMAC m_hmac; // = null   } }