11using System ;
22using System . Globalization ;
33using Renci . SshNet . Common ;
4- using csp = System . Security . Cryptography ;
54
65namespace Renci . SshNet . Security . Cryptography . Ciphers
76{
@@ -14,20 +13,15 @@ public sealed class AesCipher : BlockCipher
1413 private const uint M2 = 0x7f7f7f7f ;
1514 private const uint M3 = 0x0000001b ;
1615
16+ private readonly AesCipherCSP _aesCSP ;
17+
1718 private int _rounds ;
1819 private uint [ ] _encryptionKey ;
1920 private uint [ ] _decryptionKey ;
20- private uint C0 , C1 , C2 , C3 ;
21-
22- #if FEATURE_AES_CSP
23- private csp . ICryptoTransform aesDecryptor ;
24- private csp . ICryptoTransform aesEncryptor ;
25- private bool useCSP ; // set to false when CSP is not available for a given mode; falls back to legacy code
26- private bool isCTRMode ;
27- private uint [ ] _ctrIV ;
28-
29- CipherPadding _padding ;
30- #endif
21+ private uint _c0 ;
22+ private uint _c1 ;
23+ private uint _c2 ;
24+ private uint _c3 ;
3125
3226 #region Static Definition Tables
3327
@@ -580,10 +574,8 @@ public AesCipher(byte[] key, CipherMode mode, CipherPadding padding)
580574 throw new ArgumentException ( string . Format ( CultureInfo . CurrentCulture , "KeySize '{0}' is not valid for this algorithm." , keySize ) ) ;
581575 }
582576
583- #if FEATURE_AES_CSP
584577 // initialize AesCryptoServiceProvider which uses AES-NI (faster, less CPU usage)
585- useCSP = initCryptoServiceProvider ( mode , padding ) ;
586- #endif
578+ _aesCSP = new AesCipherCSP ( key , 16 , mode , padding ) ;
587579 }
588580
589581 /// <summary>
@@ -678,199 +670,43 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC
678670 return BlockSize ;
679671 }
680672
681- #if FEATURE_AES_CSP
682-
683673 /// <summary>
684- /// Encrypts the specified data using AesCryptoServiceProvider
674+ /// Encrypts the specified data using CSP acceleration if enabled.
685675 /// </summary>
686- /// <param name="data">The data.</param>
687- /// <param name="offset">The zero-based offset in <paramref name="data"/> at which to begin encrypting.</param>
688- /// <param name="length">The number of bytes to encrypt from <paramref name="data"/>.</param>
689- /// <returns>Encrypted data</returns>
690- public override byte [ ] Encrypt ( byte [ ] data , int offset , int length )
676+ /// <param name="input">The data.</param>
677+ /// <param name="offset">The zero-based offset in <paramref name="input"/> at which to begin encrypting.</param>
678+ /// <param name="length">The number of bytes to encrypt from <paramref name="input"/>.</param>
679+ /// <returns>
680+ /// The encrypted data.
681+ /// </returns>
682+ public override byte [ ] Encrypt ( byte [ ] input , int offset , int length )
691683 {
692- if ( useCSP )
684+ if ( _aesCSP . IsCSPEnabled )
693685 {
694- if ( length % BlockSize > 0 )
695- {
696- if ( _padding == null )
697- {
698- throw new ArgumentException ( "data" ) ;
699- }
700- data = _padding . Pad ( BlockSize , data , offset , length ) ;
701- offset = 0 ;
702- length = data . Length ;
703- }
704-
705- if ( isCTRMode )
706- return CTREncryptDecrypt ( data , offset , length ) ;
707- else
708- {
709- byte [ ] output = new byte [ length ] ;
710- aesEncryptor . TransformBlock ( data , offset , length , output , 0 ) ;
711- return output ;
712- }
686+ return _aesCSP . Encrypt ( input , offset , length ) ;
713687 }
714- else
715- return base . Encrypt ( data , offset , length ) ;
688+
689+ return base . Encrypt ( input , offset , length ) ;
716690 }
717691
718692 /// <summary>
719- /// Decrypts the specified input using AesCryptoServiceProvider
693+ /// Encrypts the specified data using CSP acceleration if enabled.
720694 /// </summary>
721- /// <param name="data ">The input .</param>
722- /// <param name="offset">The zero-based offset in <paramref name="data "/> at which to begin decrypting .</param>
723- /// <param name="length">The number of bytes to decrypt from <paramref name="data "/>.</param>
695+ /// <param name="input ">The data .</param>
696+ /// <param name="offset">The zero-based offset in <paramref name="input "/> at which to begin encrypting .</param>
697+ /// <param name="length">The number of bytes to encrypt from <paramref name="input "/>.</param>
724698 /// <returns>
725- /// The decrypted data.
699+ /// The encrypted data.
726700 /// </returns>
727- public override byte [ ] Decrypt ( byte [ ] data , int offset , int length )
701+ public override byte [ ] Decrypt ( byte [ ] input , int offset , int length )
728702 {
729- if ( useCSP )
703+ if ( _aesCSP . IsCSPEnabled )
730704 {
731- if ( length % BlockSize > 0 )
732- {
733- if ( _padding == null )
734- {
735- throw new ArgumentException ( "data" ) ;
736- }
737- data = _padding . Pad ( BlockSize , data , offset , length ) ;
738- offset = 0 ;
739- length = data . Length ;
740- }
741-
742- if ( isCTRMode )
743- return CTREncryptDecrypt ( data , offset , length ) ;
744- else
745- {
746- byte [ ] output = new byte [ length ] ;
747- aesDecryptor . TransformBlock ( data , offset , length , output , 0 ) ;
748- return output ;
749- }
705+ return _aesCSP . Decrypt ( input , offset , length ) ;
750706 }
751- else
752- return base . Encrypt ( data , offset , length ) ;
753- }
754-
755- // initialize AesCryptoServiceProvider
756- private bool initCryptoServiceProvider ( CipherMode mode , CipherPadding padding )
757- {
758- try
759- {
760- // use the provided CipherPadding object
761- _padding = padding ;
762- csp . PaddingMode cspPadding = csp . PaddingMode . None ;
763-
764- // set the Mode
765- csp . CipherMode cspMode = 0 ;
766- isCTRMode = mode is Modes . CtrCipherMode ;
767-
768- if ( mode is Modes . CbcCipherMode )
769- cspMode = csp . CipherMode . CBC ;
770- else if ( isCTRMode )
771- cspMode = csp . CipherMode . ECB ; // CTR uses ECB
772- else
773- return false ; // OFB and CFB not supported, fallback to managed code
774-
775- // prepare IV array for CTR mode
776- if ( isCTRMode )
777- _ctrIV = GetPackedIV ( mode . IV ) ;
778-
779- // create ICryptoTransform instances
780- var aesProvider = new csp . AesCryptoServiceProvider ( )
781- {
782- BlockSize = BlockSize * 8 ,
783- KeySize = Key . Length * 8 ,
784- Mode = cspMode ,
785- Padding = cspPadding ,
786- Key = Key ,
787- IV = mode . IV ,
788- } ;
789- aesEncryptor = aesProvider . CreateEncryptor ( Key , mode . IV ) ;
790- aesDecryptor = aesProvider . CreateDecryptor ( Key , mode . IV ) ;
791- return true ;
792- }
793- catch { } // fallback for unsupported key/iv/blocksize combinations
794- return false ;
795- }
796-
797- // convert the IV into an array of uint[4]
798- private uint [ ] GetPackedIV ( byte [ ] iv )
799- {
800- uint [ ] packedIV = new uint [ 4 ] ;
801- packedIV [ 0 ] = ( uint ) ( ( iv [ 0 ] << 24 ) | ( iv [ 1 ] << 16 ) | ( iv [ 2 ] << 8 ) | ( iv [ 3 ] ) ) ;
802- packedIV [ 1 ] = ( uint ) ( ( iv [ 4 ] << 24 ) | ( iv [ 5 ] << 16 ) | ( iv [ 6 ] << 8 ) | ( iv [ 7 ] ) ) ;
803- packedIV [ 2 ] = ( uint ) ( ( iv [ 8 ] << 24 ) | ( iv [ 9 ] << 16 ) | ( iv [ 10 ] << 8 ) | ( iv [ 11 ] ) ) ;
804- packedIV [ 3 ] = ( uint ) ( ( iv [ 12 ] << 24 ) | ( iv [ 13 ] << 16 ) | ( iv [ 14 ] << 8 ) | ( iv [ 15 ] ) ) ;
805- return packedIV ;
806- }
807-
808- // Perform AES-CTR encryption/decryption
809- private byte [ ] CTREncryptDecrypt ( byte [ ] data , int offset , int length )
810- {
811- int count = length / BlockSize ;
812- if ( length % BlockSize != 0 ) count ++ ;
813-
814- byte [ ] counter = CTRCreateCounterArray ( count ) ;
815- byte [ ] aesCounter = aesEncryptor . TransformFinalBlock ( counter , 0 , counter . Length ) ;
816- byte [ ] output = CTRArrayXOR ( aesCounter , data , offset , length ) ;
817-
818- return output ;
819- }
820-
821- // creates the Counter array filled with incrementing copies of IV
822- private byte [ ] CTRCreateCounterArray ( int blocks )
823- {
824- // fill an array with IV, increment by 1 for each copy
825- uint [ ] counter = new uint [ blocks * 4 ] ;
826- for ( int i = 0 ; i < counter . Length ; i += 4 )
827- {
828- // write IV to buffer (big endian)
829- counter [ i ] = ( _ctrIV [ 0 ] << 24 ) | ( ( _ctrIV [ 0 ] << 8 ) & 0x00FF0000 ) | ( ( _ctrIV [ 0 ] >> 8 ) & 0x0000FF00 ) | ( _ctrIV [ 0 ] >> 24 ) ;
830- counter [ i + 1 ] = ( _ctrIV [ 1 ] << 24 ) | ( ( _ctrIV [ 1 ] << 8 ) & 0x00FF0000 ) | ( ( _ctrIV [ 1 ] >> 8 ) & 0x0000FF00 ) | ( _ctrIV [ 1 ] >> 24 ) ;
831- counter [ i + 2 ] = ( _ctrIV [ 2 ] << 24 ) | ( ( _ctrIV [ 2 ] << 8 ) & 0x00FF0000 ) | ( ( _ctrIV [ 2 ] >> 8 ) & 0x0000FF00 ) | ( _ctrIV [ 2 ] >> 24 ) ;
832- counter [ i + 3 ] = ( _ctrIV [ 3 ] << 24 ) | ( ( _ctrIV [ 3 ] << 8 ) & 0x00FF0000 ) | ( ( _ctrIV [ 3 ] >> 8 ) & 0x0000FF00 ) | ( _ctrIV [ 3 ] >> 24 ) ;
833-
834- // increment IV (little endian)
835- for ( int j = 3 ; j >= 0 && ++ _ctrIV [ j ] == 0 ; j -- ) ;
836- }
837-
838- // copy uint[] to byte[]
839- byte [ ] counterBytes = new byte [ blocks * 16 ] ;
840- System . Buffer . BlockCopy ( counter , 0 , counterBytes , 0 , counterBytes . Length ) ;
841- return counterBytes ;
842- }
843-
844- // XORs the input data with the encrypted Counter array to produce the final output
845- // uses uint arrays for speed
846- private byte [ ] CTRArrayXOR ( byte [ ] counter , byte [ ] data , int offset , int length )
847- {
848- int words = length / 4 ;
849- if ( length % 4 != 0 ) words ++ ;
850-
851- // convert original data to words
852- uint [ ] datawords = new uint [ words ] ;
853- System . Buffer . BlockCopy ( data , offset , datawords , 0 , length ) ;
854-
855- // convert encrypted IV counter to words
856- uint [ ] counterwords = new uint [ words ] ;
857- System . Buffer . BlockCopy ( counter , 0 , counterwords , 0 , length ) ;
858-
859- // XOR encrypted Counter with input data
860- for ( int i = 0 ; i < words ; i ++ )
861- counterwords [ i ] = counterwords [ i ] ^ datawords [ i ] ;
862-
863- // copy uint[] to byte[]
864- byte [ ] output = counter ;
865- System . Buffer . BlockCopy ( counterwords , 0 , output , 0 , length ) ;
866-
867- // adjust output for non-aligned lengths
868- if ( output . Length > length )
869- Array . Resize ( ref output , length ) ;
870707
871- return output ;
708+ return base . Encrypt ( input , offset , length ) ;
872709 }
873- #endif
874710
875711 private uint [ ] GenerateWorkingKey ( bool isEncryption , byte [ ] key )
876712 {
0 commit comments