1
1
using System ;
2
2
using System . Globalization ;
3
3
using Renci . SshNet . Common ;
4
- using csp = System . Security . Cryptography ;
5
4
6
5
namespace Renci . SshNet . Security . Cryptography . Ciphers
7
6
{
@@ -14,20 +13,15 @@ public sealed class AesCipher : BlockCipher
14
13
private const uint M2 = 0x7f7f7f7f ;
15
14
private const uint M3 = 0x0000001b ;
16
15
16
+ private readonly AesCipherCSP _aesCSP ;
17
+
17
18
private int _rounds ;
18
19
private uint [ ] _encryptionKey ;
19
20
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 ;
31
25
32
26
#region Static Definition Tables
33
27
@@ -580,10 +574,8 @@ public AesCipher(byte[] key, CipherMode mode, CipherPadding padding)
580
574
throw new ArgumentException ( string . Format ( CultureInfo . CurrentCulture , "KeySize '{0}' is not valid for this algorithm." , keySize ) ) ;
581
575
}
582
576
583
- #if FEATURE_AES_CSP
584
577
// 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 ) ;
587
579
}
588
580
589
581
/// <summary>
@@ -678,199 +670,43 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC
678
670
return BlockSize ;
679
671
}
680
672
681
- #if FEATURE_AES_CSP
682
-
683
673
/// <summary>
684
- /// Encrypts the specified data using AesCryptoServiceProvider
674
+ /// Encrypts the specified data using CSP acceleration if enabled.
685
675
/// </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 )
691
683
{
692
- if ( useCSP )
684
+ if ( _aesCSP . IsCSPEnabled )
693
685
{
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 ) ;
713
687
}
714
- else
715
- return base . Encrypt ( data , offset , length ) ;
688
+
689
+ return base . Encrypt ( input , offset , length ) ;
716
690
}
717
691
718
692
/// <summary>
719
- /// Decrypts the specified input using AesCryptoServiceProvider
693
+ /// Encrypts the specified data using CSP acceleration if enabled.
720
694
/// </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>
724
698
/// <returns>
725
- /// The decrypted data.
699
+ /// The encrypted data.
726
700
/// </returns>
727
- public override byte [ ] Decrypt ( byte [ ] data , int offset , int length )
701
+ public override byte [ ] Decrypt ( byte [ ] input , int offset , int length )
728
702
{
729
- if ( useCSP )
703
+ if ( _aesCSP . IsCSPEnabled )
730
704
{
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 ) ;
750
706
}
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 ) ;
870
707
871
- return output ;
708
+ return base . Encrypt ( input , offset , length ) ;
872
709
}
873
- #endif
874
710
875
711
private uint [ ] GenerateWorkingKey ( bool isEncryption , byte [ ] key )
876
712
{
0 commit comments