22using System . Diagnostics . CodeAnalysis ;
33using System . IO ;
44using System . Security . Cryptography ;
5+ using System . Threading ;
56
67using Force . Blazer . Algorithms ;
78
89namespace Force . Blazer . Encyption
910{
10- internal class NullEncryptHelper
11+ public class NullEncryptHelper
1112 {
1213 public virtual BufferInfo Encrypt ( byte [ ] data , int offset , int length )
1314 {
@@ -21,7 +22,7 @@ public virtual byte[] AppendHeader(byte[] header)
2122 }
2223
2324 [ SuppressMessage ( "StyleCop.CSharp.MaintainabilityRules" , "SA1402:FileMayOnlyContainASingleClass" , Justification = "Reviewed. Suppression is OK here." ) ]
24- internal class EncryptHelper : NullEncryptHelper
25+ public class EncryptHelper : NullEncryptHelper
2526 {
2627 private const int PrefixSize = 8 ;
2728
@@ -33,6 +34,8 @@ internal class EncryptHelper : NullEncryptHelper
3334
3435 private readonly RandomNumberGenerator _rng ;
3536
37+ private readonly Random _random ;
38+
3639 private readonly byte [ ] _buffer ;
3740
3841 private readonly byte [ ] _randomBlock8 ;
@@ -56,6 +59,7 @@ public EncryptHelper(string password, int maxBufferSize)
5659 // this is fine for fast checking "is password correct", but does not
5760 // give full information about is it the required password
5861 _rng = RandomNumberGenerator . Create ( ) ;
62+ _random = new Random ( ) ;
5963 var salt = new byte [ 8 ] ;
6064 _rng . GetBytes ( salt ) ;
6165 var pass = new Rfc2898DeriveBytes ( password , salt , PbkIterations ) ;
@@ -64,7 +68,7 @@ public EncryptHelper(string password, int maxBufferSize)
6468 // zero. it is ok - we use data with salted random and do not need to use additional IV here
6569 _aes . IV = new byte [ 16 ] ;
6670 _aes . Mode = CipherMode . CBC ;
67- _aes . Padding = PaddingMode . Zeros ; // other padding will add additional block, we manually will add random padding
71+ _aes . Padding = PaddingMode . None ; // other padding will add additional block, we manually will add random padding
6872 _headerToWrite = new byte [ 24 ] ;
6973
7074 var random = new byte [ 8 ] ;
@@ -73,18 +77,26 @@ public EncryptHelper(string password, int maxBufferSize)
7377
7478 Buffer . BlockCopy ( random , 0 , toEncrypt , 0 , 8 ) ;
7579
76- Buffer . BlockCopy ( new [ ] { ( byte ) 'B' , ( byte ) 'l' , ( byte ) 'a' , ( byte ) 'z' , ( byte ) 'e' , ( byte ) 'r' , ( byte ) '!' , ( byte ) '! ' } , 0 , toEncrypt , 8 , 8 ) ;
80+ Buffer . BlockCopy ( new [ ] { ( byte ) 'B' , ( byte ) 'l' , ( byte ) 'a' , ( byte ) 'z' , ( byte ) 'e' , ( byte ) 'r' , ( byte ) '!' , ( byte ) '? ' } , 0 , toEncrypt , 8 , 8 ) ;
7781
7882 Buffer . BlockCopy ( salt , 0 , _headerToWrite , 0 , 8 ) ;
7983 Buffer . BlockCopy ( random , 0 , _headerToWrite , 8 , 8 ) ;
8084
85+ // currently, we use salt for password, so every encryption has own key, as result we do not need to use other values for counter
86+ // nonce is useful when password is static
87+ // _counter = ((long)salt[0] << 0) | ((long)salt[1] << 8) | ((long)salt[2] << 16) | ((long)salt[3] << 24) | ((long)salt[4] << 32) | ((long)salt[5] << 40) | ((long)salt[6] << 48) | ((long)salt[7] << 56);
88+ _counter = 0 ;
89+
8190 using ( var encryptor = _aes . CreateEncryptor ( ) )
8291 {
8392 var encoded = encryptor . TransformFinalBlock ( toEncrypt , 0 , 16 ) ;
8493 Buffer . BlockCopy ( encoded , 0 , _headerToWrite , 16 , 8 ) ;
8594 }
8695 }
8796
97+ private long _counter ;
98+
99+ [ SuppressMessage ( "StyleCop.CSharp.ReadabilityRules" , "SA1107:CodeMustNotContainMultipleStatementsOnOneLine" , Justification = "Reviewed. Suppression is OK here." ) ]
88100 public override BufferInfo Encrypt ( byte [ ] data , int offset , int length )
89101 {
90102 var count = length - offset ;
@@ -93,16 +105,21 @@ public override BufferInfo Encrypt(byte[] data, int offset, int length)
93105 // this is will elimitate CBC problem with same blocks (if data is repeatable)
94106 using ( var encryptor = _aes . CreateEncryptor ( ) )
95107 {
96- _rng . GetBytes ( _randomBlock8 ) ;
108+ // currently, we're not supporting multi-threading, so, we do not need to use Interlocked operations
109+ var c = _counter ++ ;
110+ _buffer [ 0 ] = ( byte ) ( ( c >> 00 ) & 0xff ) ; _buffer [ 1 ] = ( byte ) ( ( c >> 08 ) & 0xff ) ; _buffer [ 2 ] = ( byte ) ( ( c >> 16 ) & 0xff ) ; _buffer [ 3 ] = ( byte ) ( ( c >> 24 ) & 0xff ) ;
111+ _buffer [ 4 ] = ( byte ) ( ( c >> 32 ) & 0xff ) ; _buffer [ 5 ] = ( byte ) ( ( c >> 40 ) & 0xff ) ; _buffer [ 6 ] = ( byte ) ( ( c >> 48 ) & 0xff ) ; _buffer [ 7 ] = ( byte ) ( ( c >> 56 ) & 0xff ) ;
112+ // _rng.GetBytes(_randomBlock8);
97113 // copying prefix
98- Buffer . BlockCopy ( _randomBlock8 , 0 , _buffer , 0 , PrefixSize ) ;
114+ // Buffer.BlockCopy(_randomBlock8, 0, _buffer, 0, PrefixSize);
99115
100116 // copying real data
101117 Buffer . BlockCopy ( data , offset , _buffer , PrefixSize , count ) ;
102118
103119 var addRandomCnt = 16 - ( ( count + PrefixSize ) & 15 ) ;
104120 if ( addRandomCnt < 16 )
105121 {
122+ // here is no security required, but it faster
106123 _rng . GetBytes ( _randomBlock16 ) ;
107124 Buffer . BlockCopy ( _randomBlock16 , 0 , _buffer , PrefixSize + count , addRandomCnt ) ;
108125 }
0 commit comments