1+ using System ;
2+ using System . Diagnostics ;
3+ using System . IO ;
4+ using System . Security . Cryptography ;
5+ using utils ;
6+ using static System . Diagnostics . Stopwatch ;
7+
8+ namespace CryptoTools
9+ {
10+ public class AesCryptoManager
11+ {
12+ /// <summary>
13+ /// Encrypts data from one file to another using AES
14+ /// </summary>
15+ /// <param name="inputFile">The file path to the unencrypted data</param>
16+ /// <param name="outputFile">The file path to output the encrypted data to</param>
17+ /// <param name="keyBytes">The bytes of the key</param>
18+ /// <returns>true if successful, else false</returns>
19+ public bool EncryptFileBytes ( string inputFile , string outputFile , byte [ ] keyBytes )
20+ {
21+
22+ var saltBytes = new byte [ ] { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 } ;
23+
24+ // Any cryptographic exception indicates the data is invalid or an incorrect password has been inputted
25+ try
26+ {
27+
28+ // Creates the instance used to encrypt. This implements IDisposable so is inside a using statement
29+ using ( var aes = new AesCryptoServiceProvider ( ) )
30+ {
31+
32+ // AESManaged properties
33+ aes . KeySize = 256 ;
34+ aes . BlockSize = 128 ;
35+ aes . Padding = PaddingMode . PKCS7 ;
36+ aes . Mode = CipherMode . CBC ;
37+
38+ #if DEBUG
39+ // Debug values
40+ if ( ! Stopwatch . IsHighResolution ) { throw new Exception ( "You don't have a high-res sysclock" ) ; }
41+ var iterations = 0L ;
42+ var fullIterationTime = 0.0D ;
43+ var watch = StartNew ( ) ;
44+ var avgIterationMilliseconds = 0D ;
45+ #endif
46+
47+ // Derives a key using PBKDF2 from the password and a salt
48+ var key = new Rfc2898DeriveBytes ( keyBytes , saltBytes , 100000 ) ;
49+
50+ // Set actual IV and key
51+ aes . Key = key . GetBytes ( aes . KeySize / 8 ) ;
52+ aes . IV = key . GetBytes ( aes . BlockSize / 8 ) ;
53+
54+ // Creates the streams necessary for reading and writing data
55+ using ( var outFileStream = File . Create ( outputFile ) )
56+ using ( var cs = new CryptoStream ( outFileStream , aes . CreateEncryptor ( ) , CryptoStreamMode . Write ) )
57+ using ( var inFile = new BinaryReader ( File . OpenRead ( inputFile ) ) ) // BinaryReader is not a stream, but it's only argument is one
58+ {
59+ // Continuously reads the stream until it hits an EndOfStream exception
60+ while ( true )
61+ {
62+ try
63+ {
64+ #if DEBUG
65+ var offset = watch . Elapsed . TotalMilliseconds ;
66+ #endif
67+ var data = inFile . ReadByte ( ) ;
68+ cs . WriteByte ( data ) ;
69+ #if DEBUG
70+ var perIterationMilliseconds = watch . Elapsed . TotalMilliseconds - offset ;
71+ avgIterationMilliseconds = ( avgIterationMilliseconds * iterations + perIterationMilliseconds ) / ( iterations + 1 ) ;
72+ fullIterationTime += perIterationMilliseconds ;
73+ iterations ++ ;
74+ #endif
75+ }
76+ catch ( EndOfStreamException )
77+ {
78+ #if DEBUG
79+ var totalMilliseconds = watch . Elapsed . TotalMilliseconds ;
80+ var totalSeconds = totalMilliseconds / 1000 ;
81+ double perIterationSeconds = avgIterationMilliseconds / 1000 ,
82+ perIterationMilliseconds = avgIterationMilliseconds ;
83+ var toWrite = new [ ] { "Time to encrypt (s):" + totalSeconds , "Time to encrypt (ms):" + totalMilliseconds ,
84+ "Average iteration length (s):" + perIterationSeconds . ToString ( "0." + new string ( '#' , 339 ) ) , "Average iteration length (ms):" + perIterationMilliseconds . ToString ( "0." + new string ( '#' , 339 ) ) ,
85+ "Time of all iterations, combined (s):" + fullIterationTime / 1000 , "Time of all iterations, combined (ms):" + fullIterationTime ,
86+ "Iterations:" + iterations } ;
87+
88+ Utils . WriteToDiagnosticsFile ( toWrite ) ;
89+ #endif
90+
91+ break ;
92+ }
93+ }
94+ }
95+ }
96+ }
97+ catch ( CryptographicException ) // If something went wrong, we get it here
98+ {
99+ return false ;
100+ }
101+
102+ return true ;
103+ }
104+
105+ /// <summary>
106+ /// Encrypts data from one file to another using AES
107+ /// </summary>
108+ /// <param name="inputFile">The file path to the unencrypted data</param>
109+ /// <param name="outputFile">The file path to output the encrypted data to</param>
110+ /// <param name="keyBytes">The bytes of the key</param>
111+ /// <returns>true if successful, else false</returns>
112+ public bool DecryptFileBytes ( string inputFile , string outputFile , byte [ ] keyBytes )
113+ {
114+
115+ var saltBytes = new byte [ ] { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 } ;
116+
117+ // Any cryptographic exception indicates the data is invalid or an incorrect password has been inputted
118+ try
119+ {
120+
121+ // Creates the instance used to decrypt. This implements IDisposable so is inside a using statement
122+ using ( var aes = new AesCryptoServiceProvider ( ) )
123+ {
124+
125+ // AESManaged properties
126+ aes . KeySize = 256 ;
127+ aes . BlockSize = 128 ;
128+ aes . Padding = PaddingMode . PKCS7 ;
129+ aes . Mode = CipherMode . CBC ;
130+
131+ #if DEBUG
132+ // Debug values
133+ if ( ! Stopwatch . IsHighResolution ) { throw new Exception ( "You don't have a high-res sysclock" ) ; }
134+ var iterations = 0L ;
135+ var fullIterationTime = 0.0D ;
136+ var watch = StartNew ( ) ;
137+ var avgIterationMilliseconds = 0D ;
138+ #endif
139+
140+ // Derives a key using PBKDF2 from the password and a salt
141+ var key = new Rfc2898DeriveBytes ( keyBytes , saltBytes , 100000 ) ;
142+
143+ // Set actual IV and key
144+ aes . Key = key . GetBytes ( aes . KeySize / 8 ) ;
145+ aes . IV = key . GetBytes ( aes . BlockSize / 8 ) ;
146+
147+ // Creates the streams necessary for reading and writing data
148+ using ( var outFileStream = File . Create ( outputFile ) )
149+ using ( var cs = new CryptoStream ( outFileStream , aes . CreateDecryptor ( ) , CryptoStreamMode . Write ) )
150+ using ( var inFile = new BinaryReader ( File . OpenRead ( inputFile ) ) ) // BinaryReader is not a stream, but it's only argument is one
151+ {
152+ // Continuously reads the stream until it hits an EndOfStream exception
153+ while ( true )
154+ {
155+ try
156+ {
157+ #if DEBUG
158+ var offset = watch . Elapsed . TotalMilliseconds ;
159+ #endif
160+ var data = inFile . ReadByte ( ) ;
161+ cs . WriteByte ( data ) ;
162+ #if DEBUG
163+ var perIterationMilliseconds = watch . Elapsed . TotalMilliseconds - offset ;
164+ avgIterationMilliseconds = ( avgIterationMilliseconds * iterations + perIterationMilliseconds ) / ( iterations + 1 ) ;
165+ fullIterationTime += perIterationMilliseconds ;
166+ iterations ++ ;
167+ #endif
168+ }
169+ catch ( EndOfStreamException )
170+ {
171+ #if DEBUG
172+ var totalMilliseconds = watch . Elapsed . TotalMilliseconds ;
173+ var totalSeconds = totalMilliseconds / 1000 ;
174+ double perIterationSeconds = avgIterationMilliseconds / 1000 ,
175+ perIterationMilliseconds = avgIterationMilliseconds ;
176+ var toWrite = new [ ] { "Time to encrypt (s):" + totalSeconds , "Time to encrypt (ms):" + totalMilliseconds ,
177+ "Average iteration length (s):" + perIterationSeconds . ToString ( "0." + new string ( '#' , 339 ) ) , "Average iteration length (ms):" + perIterationMilliseconds . ToString ( "0." + new string ( '#' , 339 ) ) ,
178+ "Time of all iterations, combined (s):" + fullIterationTime / 1000 , "Time of all iterations, combined (ms):" + fullIterationTime ,
179+ "Iterations:" + iterations } ;
180+
181+ Utils . WriteToDiagnosticsFile ( toWrite ) ;
182+ #endif
183+
184+ break ;
185+ }
186+ }
187+ }
188+ }
189+ }
190+ catch ( CryptographicException ) // If something went wrong, we get it here
191+ {
192+ return false ;
193+ }
194+
195+ return true ;
196+ }
197+ }
198+ }
0 commit comments