@@ -1,387 +0,0 @@
 
		
	
		
			
				 using  System ;  
		
	
		
			
				 
		
	
		
			
				namespace  OtpProviderClient  
		
	
		
			
				{  
		
	
		
			
				    /// <summary> 
 
		
	
		
			
				    /// Provides Time-based One Time Passwords RFC 6238. 
 
		
	
		
			
				    /// </summary> 
 
		
	
		
			
				    public  class  Totp_Provider 
 
		
	
		
			
				    { 
 
		
	
		
			
				        /// <summary> 
 
		
	
		
			
				        /// Time reference for TOTP generation. 
 
		
	
		
			
				        /// </summary> 
 
		
	
		
			
				        private  static  readonly  DateTime  UnixEpoch  =  new  DateTime ( 1970 ,  1 ,  1 ,  0 ,  0 ,  0 ,  DateTimeKind . Utc ) ; 
 
		
	
		
			
				 
		
	
		
			
				        /// <summary> 
 
		
	
		
			
				        /// Duration of generation of each totp, in seconds. 
 
		
	
		
			
				        /// </summary> 
 
		
	
		
			
				        private  int  _Duration ; 
 
		
	
		
			
				 
		
	
		
			
				        /// <summary> 
 
		
	
		
			
				        /// Length of the generated totp. 
 
		
	
		
			
				        /// </summary> 
 
		
	
		
			
				        private  int  _Length ; 
 
		
	
		
			
				 
		
	
		
			
				        private  TimeSpan  _TimeCorrection ; 
 
		
	
		
			
				        /// <summary> 
 
		
	
		
			
				        /// Sets the time span that is used to match the server's UTC time to ensure accurate generation of Time-based One Time Passwords. 
 
		
	
		
			
				        /// </summary> 
 
		
	
		
			
				        public  TimeSpan  TimeCorrection  {  set  {  _TimeCorrection  =  value ;  }  } 
 
		
	
		
			
				 
		
	
		
			
				        /// <summary> 
 
		
	
		
			
				        /// Instanciates a new Totp_Generator. 
 
		
	
		
			
				        /// </summary> 
 
		
	
		
			
				        /// <param name="Duration">Duration of generation of each totp, in seconds.</param> 
 
		
	
		
			
				        /// <param name="Length">Length of the generated totp.</param> 
 
		
	
		
			
				        public  Totp_Provider ( int  Duration ,  int  Length ) 
 
		
	
		
			
				        { 
 
		
	
		
			
				            if  ( ! ( Duration  >  0 ) )  throw  new  Exception ( "Invalid Duration." ) ;  //Throws an exception if the duration is invalid as the class cannot work without it. 
 
		
	
		
			
				            _Duration  =  Duration ;  //Defines variable from argument. 
 
		
	
		
			
				            if  ( ! ( ( Length  >  5 )  & &  ( Length  <  9 ) ) )  throw  new  Exception ( "Invalid Length." ) ;  //Throws an exception if the length is invalid as the class cannot work without it. 
 
		
	
		
			
				            _Length  =  Length ;  //Defines variable from argument. 
 
		
	
		
			
				            _TimeCorrection  =  TimeSpan . Zero ;  //Defines variable from non-constant default value. 
 
		
	
		
			
				        } 
 
		
	
		
			
				 
		
	
		
			
				        /// <summary> 
 
		
	
		
			
				        /// Returns current time with correction int UTC format. 
 
		
	
		
			
				        /// </summary> 
 
		
	
		
			
				        public  DateTime  Now 
 
		
	
		
			
				        { 
 
		
	
		
			
				            get 
 
		
	
		
			
				            { 
 
		
	
		
			
				                return  DateTime . UtcNow  -  _TimeCorrection ;  //Computes current time minus time correction giving the corrected time. 
 
		
	
		
			
				            } 
 
		
	
		
			
				        } 
 
		
	
		
			
				 
		
	
		
			
				        /// <summary> 
 
		
	
		
			
				        /// Returns the time remaining before counter incrementation. 
 
		
	
		
			
				        /// </summary> 
 
		
	
		
			
				        public  int  Timer 
 
		
	
		
			
				        { 
 
		
	
		
			
				            get 
 
		
	
		
			
				            { 
 
		
	
		
			
				                var  n  =  ( _Duration  -  ( int ) ( ( Now  -  UnixEpoch ) . TotalSeconds  %  _Duration ) ) ;  //Computes the seconds left before counter incrementation. 
 
		
	
		
			
				                return  n  = =  0  ?  _Duration  :  n ;  //Returns timer value from 30 to 1. 
 
		
	
		
			
				            } 
 
		
	
		
			
				        } 
 
		
	
		
			
				 
		
	
		
			
				        /// <summary> 
 
		
	
		
			
				        /// Returns number of intervals that have elapsed. 
 
		
	
		
			
				        /// </summary> 
 
		
	
		
			
				        public  long  Counter 
 
		
	
		
			
				        { 
 
		
	
		
			
				            get 
 
		
	
		
			
				            { 
 
		
	
		
			
				                var  ElapsedSeconds  =  ( long ) Math . Floor ( ( Now  -  UnixEpoch ) . TotalSeconds ) ;  //Compute current counter for current time. 
 
		
	
		
			
				                return  ElapsedSeconds  /  _Duration ;  //Applies specified interval to computed counter. 
 
		
	
		
			
				            } 
 
		
	
		
			
				        } 
 
		
	
		
			
				 
		
	
		
			
				        /// <summary> 
 
		
	
		
			
				        /// Converts an unsigned integer to binary data. 
 
		
	
		
			
				        /// </summary> 
 
		
	
		
			
				        /// <param name="n">Unsigned Integer.</param> 
 
		
	
		
			
				        /// <returns>Binary data.</returns> 
 
		
	
		
			
				        private  byte [ ]  GetBytes ( ulong  n ) 
 
		
	
		
			
				        { 
 
		
	
		
			
				            byte [ ]  b  =  new  byte [ 8 ] ;  //Math. 
 
		
	
		
			
				            b [ 0 ]  =  ( byte ) ( n  > >  56 ) ;  //Math. 
 
		
	
		
			
				            b [ 1 ]  =  ( byte ) ( n  > >  48 ) ;  //Math. 
 
		
	
		
			
				            b [ 2 ]  =  ( byte ) ( n  > >  40 ) ;  //Math. 
 
		
	
		
			
				            b [ 3 ]  =  ( byte ) ( n  > >  32 ) ;  //Math. 
 
		
	
		
			
				            b [ 4 ]  =  ( byte ) ( n  > >  24 ) ;  //Math. 
 
		
	
		
			
				            b [ 5 ]  =  ( byte ) ( n  > >  16 ) ;  //Math. 
 
		
	
		
			
				            b [ 6 ]  =  ( byte ) ( n  > >  8 ) ;   //Math. 
 
		
	
		
			
				            b [ 7 ]  =  ( byte ) ( n ) ;        //Math. 
 
		
	
		
			
				            return  b ; 
 
		
	
		
			
				        } 
 
		
	
		
			
				 
		
	
		
			
				        /// <summary> 
 
		
	
		
			
				        /// Generate a Totp using provided binary data. 
 
		
	
		
			
				        /// </summary> 
 
		
	
		
			
				        /// <param name="key">Binary data.</param> 
 
		
	
		
			
				        /// <returns>Time-based One Time Password.</returns> 
 
		
	
		
			
				        public  string  Generate ( byte [ ]  key ) 
 
		
	
		
			
				        { 
 
		
	
		
			
				            System . Security . Cryptography . HMACSHA1  hmac  =  new  System . Security . Cryptography . HMACSHA1 ( key ,  true ) ;  //Instanciates a new hash provider with a key. 
 
		
	
		
			
				            byte [ ]  hash  =  hmac . ComputeHash ( GetBytes ( ( ulong ) Counter ) ) ;  //Generates hash from key using counter. 
 
		
	
		
			
				            hmac . Clear ( ) ;  //Clear hash instance securing the key. 
 
		
	
		
			
				 
		
	
		
			
				            int  offset  =  hash [ hash . Length  -  1 ]  &  0xf ;            //Math. 
 
		
	
		
			
				            int  binary  =                                         //Math. 
 
		
	
		
			
				                ( ( hash [ offset ]  &  0x7f )  < <  24 )                    //Math. 
 
		
	
		
			
				                |  ( ( hash [ offset  +  1 ]  &  0xff )  < <  16 )              //Math. 
 
		
	
		
			
				                |  ( ( hash [ offset  +  2 ]  &  0xff )  < <  8 )               //Math. 
 
		
	
		
			
				                |  ( hash [ offset  +  3 ]  &  0xff ) ;                     //Math. 
 
		
	
		
			
				 
		
	
		
			
				            int  password  =  binary  %  Convert . ToInt32 ( Math . Pow ( 10 ,  _Length ) ) ;  //Math. 
 
		
	
		
			
				            return  password . ToString ( new  string ( '0' ,  _Length ) ) ;  //Math. 
 
		
	
		
			
				        } 
 
		
	
		
			
				    } 
 
		
	
		
			
				 
		
	
		
			
				    /// <summary> 
 
		
	
		
			
				    /// Provides time correction for Time-based One Time Passwords that require accurate DateTime syncronisation with server. 
 
		
	
		
			
				    /// </summary> 
 
		
	
		
			
				    public  class  TimeCorrection_Provider 
 
		
	
		
			
				    { 
 
		
	
		
			
				        /// <summary> 
 
		
	
		
			
				        /// Timer providing the delay between each time correction check. 
 
		
	
		
			
				        /// </summary> 
 
		
	
		
			
				        private  System . Timers . Timer  _Timer ; 
 
		
	
		
			
				 
		
	
		
			
				        /// <summary> 
 
		
	
		
			
				        /// Thread which handles the time correction check. 
 
		
	
		
			
				        /// </summary> 
 
		
	
		
			
				        private  System . Threading . Thread  Task ; 
 
		
	
		
			
				 
		
	
		
			
				        private  bool  _Enable ; 
 
		
	
		
			
				        /// <summary> 
 
		
	
		
			
				        /// Defines weither or not the class will attempt to get time correction from the server. 
 
		
	
		
			
				        /// </summary> 
 
		
	
		
			
				        public  bool  Enable  {  get  {  return  _Enable ;  }  set  {  _Enable  =  value ;  _Timer . Enabled  =  value ;  }  } 
 
		
	
		
			
				 
		
	
		
			
				        private  static  int  _Interval  =  60 ; 
 
		
	
		
			
				        /// <summary> 
 
		
	
		
			
				        /// Gets or sets the interval in minutes between each online checks for time correction. 
 
		
	
		
			
				        /// </summary> 
 
		
	
		
			
				        /// <value>Time</value> 
 
		
	
		
			
				        public  static  int  Interval  {  get  {  return  _Interval ;  }  set  {  _Interval  =  value ;  }  } 
 
		
	
		
			
				        private  long  _IntervalStretcher ; 
 
		
	
		
			
				 
		
	
		
			
				        private  volatile  string  _Url ; 
 
		
	
		
			
				        /// <summary> 
 
		
	
		
			
				        /// Returns the URL this instance is using to checks for time correction. 
 
		
	
		
			
				        /// </summary> 
 
		
	
		
			
				        public  string  Url  {  get  {  return  _Url ;  }  } 
 
		
	
		
			
				 
		
	
		
			
				        private  TimeSpan  _TimeCorrection ; 
 
		
	
		
			
				        /// <summary> 
 
		
	
		
			
				        /// Returns the time span between server UTC time and this computer's UTC time of the last check for time correction. 
 
		
	
		
			
				        /// </summary> 
 
		
	
		
			
				        public  TimeSpan  TimeCorrection  {  get  {  return  _TimeCorrection ;  }  } 
 
		
	
		
			
				 
		
	
		
			
				        private  DateTime  _LastUpdateDateTime ; 
 
		
	
		
			
				        /// <summary> 
 
		
	
		
			
				        /// Returns the date and time in universal format of the last online check for time correction. 
 
		
	
		
			
				        /// </summary> 
 
		
	
		
			
				        public  DateTime  LastUpdateDateTime  {  get  {  return  _LastUpdateDateTime ;  }  } 
 
		
	
		
			
				 
		
	
		
			
				        private  bool  _LastUpdateSucceded  =  false ; 
 
		
	
		
			
				        /// <summary> 
 
		
	
		
			
				        /// Returns true if the last check for time correction was successful. 
 
		
	
		
			
				        /// </summary> 
 
		
	
		
			
				        public  bool  LastUpdateSucceded  {  get  {  return  _LastUpdateSucceded ;  }  } 
 
		
	
		
			
				        
 
		
	
		
			
				        /// <summary> 
 
		
	
		
			
				        /// Instanciates a new Totp_TimeCorrection using the specified URL to contact the server. 
 
		
	
		
			
				        /// </summary> 
 
		
	
		
			
				        /// <param name="Url">URL of the server to get check.</param> 
 
		
	
		
			
				        /// <param name="Enable">Enable or disable the time correction check.</param> 
 
		
	
		
			
				        public  TimeCorrection_Provider ( string  Url ,  bool  Enable  =  true ) 
 
		
	
		
			
				        { 
 
		
	
		
			
				            if  ( Url  = =  string . Empty )  throw  new  Exception ( "Invalid URL." ) ;  //Throws exception if the URL is invalid as the class cannot work without it. 
 
		
	
		
			
				            _Url  =  Url ;  //Defines variable from argument. 
 
		
	
		
			
				            _Enable  =  Enable ;  //Defines variable from argument. 
 
		
	
		
			
				            _LastUpdateDateTime  =  DateTime . MinValue ;  //Defines variable from non-constant default value. 
 
		
	
		
			
				            _TimeCorrection  =  TimeSpan . Zero ;  //Defines variable from non-constant default value. 
 
		
	
		
			
				            _Timer  =  new  System . Timers . Timer ( ) ;  //Instanciates timer. 
 
		
	
		
			
				            _Timer . Elapsed  + =  Timer_Elapsed ;  //Handles the timer event 
 
		
	
		
			
				            _Timer . Interval  =  1000 ;  //Defines the timer interval to 1 seconds. 
 
		
	
		
			
				            _Timer . Enabled  =  _Enable ;  //Defines the timer to run if the class is initially enabled. 
 
		
	
		
			
				            Task  =  new  System . Threading . Thread ( Task_Thread ) ;  //Instanciate a new task. 
 
		
	
		
			
				            if  ( _Enable )  Task . Start ( ) ;  //Starts the new thread if the class is initially enabled. 
 
		
	
		
			
				        } 
 
		
	
		
			
				 
		
	
		
			
				        /// <summary> 
 
		
	
		
			
				        /// Task that occurs every time the timer's interval has elapsed. 
 
		
	
		
			
				        /// </summary> 
 
		
	
		
			
				        private  void  Timer_Elapsed ( object  sender ,  EventArgs  e ) 
 
		
	
		
			
				        { 
 
		
	
		
			
				            _IntervalStretcher + + ;  //Increments timer. 
 
		
	
		
			
				            if  ( _IntervalStretcher  > =  ( 60  *  _Interval ) )  //Checks if the specified delay has been reached. 
 
		
	
		
			
				            { 
 
		
	
		
			
				                _IntervalStretcher  =  0 ;  //Resets the timer. 
 
		
	
		
			
				                Task_Do ( ) ;  //Attempts to run a new task 
 
		
	
		
			
				            } 
 
		
	
		
			
				        } 
 
		
	
		
			
				 
		
	
		
			
				        /// <summary> 
 
		
	
		
			
				        /// Instanciates a new task and starts it. 
 
		
	
		
			
				        /// </summary> 
 
		
	
		
			
				        /// <returns>Informs if reinstanciation of the task has succeeded or not. Will fail if the thread is still active from a previous time correction check.</returns> 
 
		
	
		
			
				        private  bool  Task_Do ( ) 
 
		
	
		
			
				        { 
 
		
	
		
			
				            if  ( ! Task . IsAlive )  //Checks if the task is still running. 
 
		
	
		
			
				            { 
 
		
	
		
			
				                Task  =  new  System . Threading . Thread ( Task_Thread ) ;  //Instanciate a new task. 
 
		
	
		
			
				                Task . Start ( ) ;  //Starts the new thread. 
 
		
	
		
			
				                return  true ;  //Informs if successful 
 
		
	
		
			
				            } 
 
		
	
		
			
				            return  false ;  //Informs if failed 
 
		
	
		
			
				        } 
 
		
	
		
			
				 
		
	
		
			
				        /// <summary> 
 
		
	
		
			
				        /// Event that occurs when the timer has reached the required value. Attempts to get time correction from the server. 
 
		
	
		
			
				        /// </summary> 
 
		
	
		
			
				        private  void  Task_Thread ( ) 
 
		
	
		
			
				        { 
 
		
	
		
			
				            try 
 
		
	
		
			
				            { 
 
		
	
		
			
				                var  WebClient  =  new  System . Net . WebClient ( ) ;  //WebClient to connect to server. 
 
		
	
		
			
				                WebClient . DownloadData ( _Url ) ;  //Downloads the server's page using HTTP or HTTPS. 
 
		
	
		
			
				                var  DateHeader  =  WebClient . ResponseHeaders . Get ( "Date" ) ;  //Gets the date from the HTTP header of the downloaded page. 
 
		
	
		
			
				                _TimeCorrection  =  DateTime . UtcNow  -  DateTime . Parse ( DateHeader ,  System . Globalization . CultureInfo . InvariantCulture . DateTimeFormat ) . ToUniversalTime ( ) ;  //Compares the downloaded date to the systems date giving us a timespan. 
 
		
	
		
			
				                _LastUpdateSucceded  =  true ;  //Informs that the date check has succeeded. 
 
		
	
		
			
				            } 
 
		
	
		
			
				            catch  ( Exception ) 
 
		
	
		
			
				            { 
 
		
	
		
			
				                _LastUpdateSucceded  =  false ;  //Informs that the date check has failed. 
 
		
	
		
			
				            } 
 
		
	
		
			
				            _LastUpdateDateTime  =  DateTime . Now ;  //Informs when the last update has been attempted (succeeded or not). 
 
		
	
		
			
				        } 
 
		
	
		
			
				 
		
	
		
			
				        /// <summary> 
 
		
	
		
			
				        /// Perform a time correction check, may a few seconds. 
 
		
	
		
			
				        /// </summary> 
 
		
	
		
			
				        /// <param name="ResetTimer">Resets the timer to 0. Occurs even if the attempt to attempt a new time correction fails.</param> 
 
		
	
		
			
				        /// <param name="ForceCheck">Attempts to get time correction even if disabled.</param> 
 
		
	
		
			
				        /// <returns>Informs if the time correction check was attempted or not. Will fail if the thread is still active from a previous time correction check.</returns> 
 
		
	
		
			
				        public  bool  CheckNow ( bool  ResetTimer  =  true ,  bool  ForceCheck  =  false ) 
 
		
	
		
			
				        { 
 
		
	
		
			
				            if  ( ResetTimer )  //Checks if the timer should be reset. 
 
		
	
		
			
				            { 
 
		
	
		
			
				                _IntervalStretcher  =  0 ;  //Resets the timer. 
 
		
	
		
			
				            } 
 
		
	
		
			
				            if  ( ForceCheck  | |  _Enable )  //Checks if this check is forced or if time correction is enabled. 
 
		
	
		
			
				            { 
 
		
	
		
			
				                return  Task_Do ( ) ;  //Attempts to run a new task and informs if attempt to attemp is a success of fail 
 
		
	
		
			
				            } 
 
		
	
		
			
				            return  false ;  //Informs if not attempted to attempt 
 
		
	
		
			
				        } 
 
		
	
		
			
				    } 
 
		
	
		
			
				 
		
	
		
			
				    /// <summary> 
 
		
	
		
			
				    /// Utility to deal with Base32 encoding and decoding. 
 
		
	
		
			
				    /// </summary> 
 
		
	
		
			
				    /// <remarks> 
 
		
	
		
			
				    /// http://tools.ietf.org/html/rfc4648 
 
		
	
		
			
				    /// </remarks> 
 
		
	
		
			
				    public  static  class  Base32 
 
		
	
		
			
				    { 
 
		
	
		
			
				        /// <summary> 
 
		
	
		
			
				        /// The number of bits in a base32 encoded character. 
 
		
	
		
			
				        /// </summary> 
 
		
	
		
			
				        private  const  int  encodedBitCount  =  5 ; 
 
		
	
		
			
				        /// <summary> 
 
		
	
		
			
				        /// The number of bits in a byte. 
 
		
	
		
			
				        /// </summary> 
 
		
	
		
			
				        private  const  int  byteBitCount  =  8 ; 
 
		
	
		
			
				        /// <summary> 
 
		
	
		
			
				        /// A string containing all of the base32 characters in order. 
 
		
	
		
			
				        /// This allows a simple indexof or [index] to convert between 
 
		
	
		
			
				        /// a numeric value and an encoded character and vice versa. 
 
		
	
		
			
				        /// </summary> 
 
		
	
		
			
				        private  const  string  encodingChars  =  "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567" ; 
 
		
	
		
			
				        /// <summary> 
 
		
	
		
			
				        /// Takes a block of data and converts it to a base 32 encoded string. 
 
		
	
		
			
				        /// </summary> 
 
		
	
		
			
				        /// <param name="data">Input data.</param> 
 
		
	
		
			
				        /// <returns>base 32 string.</returns> 
 
		
	
		
			
				        public  static  string  Encode ( byte [ ]  data ) 
 
		
	
		
			
				        { 
 
		
	
		
			
				            if  ( data  = =  null ) 
 
		
	
		
			
				                throw  new  ArgumentNullException ( ) ; 
 
		
	
		
			
				            if  ( data . Length  = =  0 ) 
 
		
	
		
			
				                throw  new  ArgumentNullException ( ) ; 
 
		
	
		
			
				 
		
	
		
			
				            // The output character count is calculated in 40 bit blocks.  That is because the least 
 
		
	
		
			
				            // common blocks size for both binary (8 bit) and base 32 (5 bit) is 40.  Padding must be used 
 
		
	
		
			
				            // to fill in the difference. 
 
		
	
		
			
				            int  outputCharacterCount  =  ( int ) Math . Ceiling ( data . Length  /  ( decimal ) encodedBitCount )  *  byteBitCount ; 
 
		
	
		
			
				            char [ ]  outputBuffer  =  new  char [ outputCharacterCount ] ; 
 
		
	
		
			
				 
		
	
		
			
				            byte  workingValue  =  0 ; 
 
		
	
		
			
				            short  remainingBits  =  encodedBitCount ; 
 
		
	
		
			
				            int  currentPosition  =  0 ; 
 
		
	
		
			
				 
		
	
		
			
				            foreach  ( byte  workingByte  in  data ) 
 
		
	
		
			
				            { 
 
		
	
		
			
				                workingValue  =  ( byte ) ( workingValue  |  ( workingByte  > >  ( byteBitCount  -  remainingBits ) ) ) ; 
 
		
	
		
			
				                outputBuffer [ currentPosition + + ]  =  encodingChars [ workingValue ] ; 
 
		
	
		
			
				 
		
	
		
			
				                if  ( remainingBits  < =  byteBitCount  -  encodedBitCount ) 
 
		
	
		
			
				                { 
 
		
	
		
			
				                    workingValue  =  ( byte ) ( ( workingByte  > >  ( byteBitCount  -  encodedBitCount  -  remainingBits ) )  &  31 ) ; 
 
		
	
		
			
				                    outputBuffer [ currentPosition + + ]  =  encodingChars [ workingValue ] ; 
 
		
	
		
			
				                    remainingBits  + =  encodedBitCount ; 
 
		
	
		
			
				                } 
 
		
	
		
			
				 
		
	
		
			
				                remainingBits  - =  byteBitCount  -  encodedBitCount ; 
 
		
	
		
			
				                workingValue  =  ( byte ) ( ( workingByte  < <  remainingBits )  &  31 ) ; 
 
		
	
		
			
				            } 
 
		
	
		
			
				 
		
	
		
			
				            // If we didn't finish, write the last current working char. 
 
		
	
		
			
				            if  ( currentPosition  ! =  outputCharacterCount ) 
 
		
	
		
			
				                outputBuffer [ currentPosition + + ]  =  encodingChars [ workingValue ] ; 
 
		
	
		
			
				 
		
	
		
			
				            // RFC 4648 specifies that padding up to the end of the next 40 bit block must be provided 
 
		
	
		
			
				            // Since the outputCharacterCount does account for the paddingCharacters, fill it out. 
 
		
	
		
			
				            while  ( currentPosition  <  outputCharacterCount ) 
 
		
	
		
			
				            { 
 
		
	
		
			
				                // The RFC defined paddinc char is '='. 
 
		
	
		
			
				                outputBuffer [ currentPosition + + ]  =  '=' ; 
 
		
	
		
			
				            } 
 
		
	
		
			
				 
		
	
		
			
				            return  new  string ( outputBuffer ) ; 
 
		
	
		
			
				        } 
 
		
	
		
			
				 
		
	
		
			
				        /// <summary> 
 
		
	
		
			
				        /// Takes a base 32 encoded value and converts it back to binary data. 
 
		
	
		
			
				        /// </summary> 
 
		
	
		
			
				        /// <param name="base32">Base 32 encoded string.</param> 
 
		
	
		
			
				        /// <returns>Binary data.</returns> 
 
		
	
		
			
				        public  static  byte [ ]  Decode ( string  base32 ) 
 
		
	
		
			
				        { 
 
		
	
		
			
				            if  ( string . IsNullOrEmpty ( base32 ) ) 
 
		
	
		
			
				                throw  new  ArgumentNullException ( ) ; 
 
		
	
		
			
				 
		
	
		
			
				            var  unpaddedBase32  =  base32 . ToUpperInvariant ( ) . TrimEnd ( '=' ) ; 
 
		
	
		
			
				            foreach  ( var  c  in  unpaddedBase32 ) 
 
		
	
		
			
				            { 
 
		
	
		
			
				                if  ( encodingChars . IndexOf ( c )  <  0 ) 
 
		
	
		
			
				                    throw  new  ArgumentException ( "Base32 contains illegal characters." ) ; 
 
		
	
		
			
				            } 
 
		
	
		
			
				 
		
	
		
			
				            // we have already removed the padding so this will tell us how many actual bytes there should be. 
 
		
	
		
			
				            int  outputByteCount  =  unpaddedBase32 . Length  *  encodedBitCount  /  byteBitCount ; 
 
		
	
		
			
				            byte [ ]  outputBuffer  =  new  byte [ outputByteCount ] ; 
 
		
	
		
			
				 
		
	
		
			
				            byte  workingByte  =  0 ; 
 
		
	
		
			
				            short  bitsRemaining  =  byteBitCount ; 
 
		
	
		
			
				            int  mask  =  0 ; 
 
		
	
		
			
				            int  arrayIndex  =  0 ; 
 
		
	
		
			
				 
		
	
		
			
				            foreach  ( char  workingChar  in  unpaddedBase32 ) 
 
		
	
		
			
				            { 
 
		
	
		
			
				                int  encodedCharacterNumericValue  =  encodingChars . IndexOf ( workingChar ) ; 
 
		
	
		
			
				 
		
	
		
			
				                if  ( bitsRemaining  >  encodedBitCount ) 
 
		
	
		
			
				                { 
 
		
	
		
			
				                    mask  =  encodedCharacterNumericValue  < <  ( bitsRemaining  -  encodedBitCount ) ; 
 
		
	
		
			
				                    workingByte  =  ( byte ) ( workingByte  |  mask ) ; 
 
		
	
		
			
				                    bitsRemaining  - =  encodedBitCount ; 
 
		
	
		
			
				                } 
 
		
	
		
			
				                else 
 
		
	
		
			
				                { 
 
		
	
		
			
				                    mask  =  encodedCharacterNumericValue  > >  ( encodedBitCount  -  bitsRemaining ) ; 
 
		
	
		
			
				                    workingByte  =  ( byte ) ( workingByte  |  mask ) ; 
 
		
	
		
			
				                    outputBuffer [ arrayIndex + + ]  =  workingByte ; 
 
		
	
		
			
				                    workingByte  =  ( byte ) ( encodedCharacterNumericValue  < <  ( byteBitCount  -  encodedBitCount  +  bitsRemaining ) ) ; 
 
		
	
		
			
				                    bitsRemaining  + =  byteBitCount  -  encodedBitCount ; 
 
		
	
		
			
				                } 
 
		
	
		
			
				            } 
 
		
	
		
			
				 
		
	
		
			
				            return  outputBuffer ; 
 
		
	
		
			
				        } 
 
		
	
		
			
				    } 
 
		
	
		
			
				}