Symmetric File Encryption / Decryption
Add Comment<div align="center"> <table border="0" width="70%" class="outline"> <tr> <td width="50%" class="outline"><b>Download File</b></td> <td width="50%" class="outline"><b>SDK</b></td> </tr> <tr> <td width="50%" class="outline"><a href="../../file/symencryptor.zip" class="wbox">symencryptor.zip</a> (15kb)</td> <td width="50%" class="outline">Beta1</td> </tr> </table> </div> <p> <span class=wboxheado>Introduction</span><br> Cryptography ..... Storing your files in such a way that no-one except you can view the file, does have a lot of importance today. Cryptography consists of 2 types of algorithms Asymmetric and Symmetric. <br> Asymmetric encryption is based on the concept of <i> Public and Private Key</i>. On the other hand Symmetric encryption is based on a <i> single 'Key'</i> . Hence it up to the person to first send the password to the receiver of the file so that he can decrypt it.<br> In this example we learn how to use 2 Symmetric encryption algorithms namely <i> Data Encryption Standard</i> (DES) and <i>RC2</i>. Both these are single Key based algorithms. Here we use 64 bit encryption in DES and 40 bit encryption in RC2 .<br> Also in this example you will learn how to write your own implementations of the "ICryptoStream" interface. </p> <p><span class=wboxheado>Usage</span><br> To encrypt the file the user has to select the file to encrypt and the file name to save the encrypted data in. The file gets encrypted with the password provided by the user using either of the two algorithms selected by the user.<br> Decryption checks the input file for validity and the algorithm used in encryption automatically. If the password provided for decryption is same as the one used for encryption then the file will decrypt.<br> Both binary and text files can be encrypted / decrypted .<br> <br> If you have gone through the .NET SDK (Beta 1) then you will find that I have used the Microsoft's Example on DES encryption example and built my code on it.<br> I will give you a rough idea of how the encryption takes place.<br> First the Password given by the user is Hashed by the "SHA1_CSP" class. By default the SHA1_CSP class returns a Hash of 20 bytes maximum. We are using Symmetric Algorithms which require a 'Key', the size of the Key defers based on the algorithm. In DES we use a 64 bit 'Key' while in 'RC2' we use a 40 bit key. Hence depending on the Key size we store the Hash of the password in a byte array. Also required by the encryption /decryption algorithms is a initialization 'Vector'. The size of the 'Key' and 'Vector' remain the same. So for DES, which requires a 64 bit Key, we use a 64 Bit Vector similarly for 'RC2' we use a 40 bit Vector.<br> Once the Key and Vector are generated, these are feed into a "SymmetricStreamEncryptor" class which encrypts / decrypts the bytes depending on the Algorithm , Key and Vector and writes it out to a File. </p> <p><span class=wboxheado>Requirements</span><br> .NET SDK beta1 (Note: This code might not work on the future versions of the SDK).</p> <p><span class=wboxheado>Screen Shot</span><br> <img border="0" src="../../img/symmetricenc.gif" width="400" height="400"><br> <b>Figure 1:</b> Symmetric Encryption beta1</p> <p><span class=wboxheado>Code</span><br> 1) <b>SymEncryptor.cs</b> :- The File Encryptor / Decryptor (Only relevant code)</p> <table border="0" width="100%" class="code" cellspacing="0" cellpadding="0"> <tr> <td width="100%"> <pre>namespace SaurabhCrypto { using System; using System.Drawing; using System.ComponentModel; using System.WinForms; using System.IO ; using System.Security; using System.Security.Cryptography; <span class=cmt>// Class which will Encrypt and Decrypt files</span> public class SymEncryptor : System.WinForms.Form { <span class=cmt>// Required by the Win Forms designer</span> private System.ComponentModel.Container components; private System.WinForms.SaveFileDialog saveFileDialog1; private System.WinForms.OpenFileDialog openFileDialog1; private System.WinForms.StatusBar statusBar1; private System.WinForms.Button decryptb; private System.WinForms.Button encryptb; private System.WinForms.RadioButton radioButton2; private System.WinForms.RadioButton radioButton1; private System.WinForms.Label infol; private System.WinForms.TextBox passt; private System.WinForms.Label passl; private System.WinForms.Button saveb; private System.WinForms.Button openb; private System.WinForms.TextBox savet; private System.WinForms.TextBox opent; private System.WinForms.Label savel; private System.WinForms.Label openl; <span class=cmt>//these byte arrays will contain the 'KEY' and 'Vector' used in //encryption and decryption .</span> private byte[] symKey ; private byte[] symIV ; <span class=cmt>//This is the constructor of the class. //It calls only one method 'InitlizeComponent' which draws the WinForm .</span> public SymEncryptor() { <span class=cmt> // Call the method to make the WinForm</span> InitializeComponent(); } <span class=cmt>//This method is called when the WinForm exits and it //Cleans up any resources being used</span> public override void Dispose() { base.Dispose(); components.Dispose(); } <span class=cmt>// The main entry point for the application.</span> public static void Main(string[] args) { Application.Run(new SymEncryptor()); } <span class=cmt>//Method called from the constructor //It initializes all the WinForm components</span> private void InitializeComponent() { <span class=cmt>//Here the WinForm components are placed //I have removed this code for explanation purpose //You can get the full code when you download the example</span> } <span class=cmt>//This method is called when the 'Decrypt' button is clicked by the user. //It first checks the file type and then calls the required methods to //decrypt the file .</span> protected void decryptb_click(object sender, System.EventArgs e) { <span class=cmt>//call the method 'ValidateBoxes()' which checks all the fields //of the WinForm and returns a 'true' if everything is filled //properly. If there are some errors it returns a 'false'</span> if(ValidateBoxes()) { <span class=cmt>//if all the Fields of the WinForm are valid then call the method //DecryptData(), this method takes care of all the decrypting to do</span> DecryptData(); <span class=cmt>//after decrypting set all the TextBoxes to their default values //this is not necessary but more user friendly...</span> opent.Text=""; savet.Text="" ; passt.Text="" ; radioButton1.Checked=true ; } } <span class=cmt> //This method is called when the 'Encrypt' button is pressed. //It checks the file and encrypts it according to the algorithm //specified by the user.</span> protected void encryptb_click(object sender, System.EventArgs e) { <span class=cmt>//a method 'ValidateBoxes()' is called which returns a true only if //all the fields of the WinForm are properly filled</span> if(ValidateBoxes()) { <span class=cmt>//Here we make a call the a method 'GenerateKee(bool variable)' //this method takes in a bool value and generates the Hash 'Key' //and 'Initialization Vector' which will be used in encryption /// decryption. It returns a 'true' if everything is proper //Here we Pass the 'radioButton1.Checked' as an argument since the //method generates 'key' and 'vector' depending on which algorithm to //use so if 'radioButton1.Checked=true' it means we are using the //'DES' algorithm else we are using the 'RC2' algorithm</span> if(GenerateKee(radioButton1.Checked)) {<span class=cmt> //call the method 'EncryptData()' //which will take care of all the encrypting</span> EncryptData() ; <span class=cmt>//Set the TextBoxes to their default values //this can be omitted , but its more user friendly</span> opent.Text=""; savet.Text="" ; passt.Text="" ; radioButton1.Checked=true ; } } } <span class=cmt>//This method is called when the 'Save' button is clicked // It opens a 'SaveFileDialog' and takes the file to be saved to</span> protected void saveb_click(object sender, System.EventArgs e) { <span class=cmt>//different parameters of the 'SaveFileDialog' are set here</span> saveFileDialog1.Filter="All files (*.*)|*.* | Encryptor files (*.enc)|*.enc"; saveFileDialog1.FilterIndex = 2 ; saveFileDialog1.RestoreDirectory = true ; <span class=cmt>//check if the user has already typed a file to save in the TextBox</span> if(savet.Text!="") { <span class=cmt>//if the user has typed a filename in the TextBox then assign that //to the dialogs 'FileName' property</span> saveFileDialog1.FileName=savet.Text ; } if(saveFileDialog1.ShowDialog() == DialogResult.OK) { <span class=cmt>//when the user presses 'Ok' on the 'SaveFileDialog' then set the //text of the TextBox 'savet' to the file selected</span> savet.Text = saveFileDialog1.FileName ; } } <span class=cmt>//This method is called when the 'Open' button is clicked by the user</span> protected void openb_click(object sender, System.EventArgs e) { <span class=cmt>//Set the various properties of the 'OpenFileDialog'</span> openFileDialog1.Filter="Encryptor files (*.enc)|*.enc|All files (*.*)|*.*"; openFileDialog1.FilterIndex = 2 ; openFileDialog1.RestoreDirectory = true ; <span class=cmt>//check if the user has already typed the file to open in the textbox</span> if(opent.Text!="") { <span class=cmt>//Then assign the Dialog the Filename from the TextBox</span> openFileDialog1.FileName = opent.Text ; } if(openFileDialog1.ShowDialog() == DialogResult.OK) { <span class=cmt>//if the user presses 'Ok' in the 'OpenFileDialog' then assign the //file selected to the textbox</span> opent.Text = openFileDialog1.FileName ; } } <span class=cmt>//this method checks if any of the TextBoxes are left empty by the user //and it generates the error required //it returns 'true' if all values are proper</span> private bool ValidateBoxes() { <span class=cmt>//check the 'Open' File textbox</span> if(opent.Text=="") { MessageBox.Show("Please Enter the file to Encrypt / Decrypt !") ; return false ; } <span class=cmt>//check the 'Save' file textbox</span> if(savet.Text=="") { MessageBox.Show("Please Enter the filename to save !") ; return false ; } <span class=cmt>//check the password textbox</span> if(passt.Text=="") { MessageBox.Show("Please Enter the Password Encrypt/Decrypt your file with."); return false ; } <span class=cmt>//if everything is alright return true</span> return true ; } <span class=cmt>//This Method computes the 'Key' and the 'Vector' to be used in //encrypting / decrypting. It generates the key according to the algorithm. //It returns is key generation is successful //If the algorithm to be used is 'DES' then it generates a 64bit Key and //64bit Vector from the provided 'Password' .Then this is stored in to a //'byte' array having length '8'. Since 1 byte = 8 bits , hence a byte //array having length '8' will contain a key of 8 x 8 =64 bits. //We use a 64bit key since DES supports a minimum 64 bit key //If the algorithm to be used is 'RC2' then it generates a 40bit Key //and a 40 bit Vector from the provided 'Password'. //We use a 40 bit key here since RC2 supports a minimum 40 bit key //(it does not support a 64bit key).</span> private bool GenerateKee(bool isDES) { <span class=cmt>//try-catch block</span> try { <span class=cmt>//store the password in a string </span> string pass =passt.Text ; int i ; int len ; <span class=cmt>//convert the password in to a Char array</span> char[] cp = pass.ToCharArray() ; len = cp.GetLength(0) ; <span class=cmt>//initialize a byte array </span> byte[] bt = new byte[len] ; <span class=cmt>//convert the Char array of the Password to a byte array</span> for(i=0 ; i<len ;i++) { bt[i] =(byte) cp[i]; } <span class=cmt>//if we are producing a Key-Vector for the 'DES' algorithm</span> if(isDES) { <span class=cmt>//initialize the byte arrays which will contain the 'Key' and //the 'Vector' to a length of '8' //(see above why we use a array of length '8')</span> symKey=new byte[8] ; symIV = new byte[8] ; <span class=cmt> //make a instance of the class 'SHA1_CSP()' //this class is useful in converting 'byte' into 'Hash'.</span> SHA1_CSP sha = new SHA1_CSP() ; <span class=cmt> //write the Hash of the byte array containing the password</span> sha.Write(bt) ; <span class=cmt>//close the stream</span> sha.CloseStream() ; <span class=cmt>//now Initialize the 'Key' array with the lower 64bits of the //Hash of the 'Password' provided by the user</span> for(i=0 ; i<8 ; i++) { symKey[i] = sha.Hash[i] ; } <span class=cmt>//initialize the 'Vector' array with the higher 64 bits of //Hash of the 'Password' provided by the user</span> for(i=8 ; i<16 ; i++) { symIV[i-8]= sha.Hash[i] ; } } else { <span class=cmt>//if the algorithm is 'RC2' then generate the following Key //initialize the Key and Vector arrays to a length of '5' //(see above why we use '5') </span> symKey=new byte[5] ; symIV = new byte[5] ; <span class=cmt>//make a instance of the class 'SHA1_CSP' //this class writes the hash of a given byte</span> SHA1_CSP sha = new SHA1_CSP() ; <span class=cmt>//write the Hash of the byte array containing the user password</span> sha.Write(bt) ; <span class=cmt>//close the stream</span> sha.CloseStream() ; <span class=cmt>//now Initialize the Key array to lower 40 bits of the Hash //of the 'Password'.</span> for(i=0 ; i<5 ; i++) { symKey[i] = sha.Hash[i] ; } <span class=cmt>//initilize the Vector array to 40bits of hash</span> for(i=5 ; i<10 ; i++) { symIV[i-5]= sha.Hash[i] ; } } <span class=cmt>//since every thing went properly return 'true'</span> return true ; } catch(Exception e) { MessageBox.Show("A Exception Occurred in Generating Keys :"+e.ToString()) ; <span class=cmt>//return false since there was a error</span> return false ; } } <span class=cmt>//This method encrypts the given input file in either of //the 2 algorithms 'DES' or 'RC2'. Then it writes out the encrypted file //This method first reads the input file to check to see if its already //encrypted by this same program. If its already encrypted it gives a error. //According to the algorithm specified it then encrypts the file. //Also in the first 8 bytes of the new Encrypted it writes //out "[saudes]" or "[saurc2]". This is done so the while decrypting //the program can know which algorithm was used to encrypt the file. //Also it used to check if the file has already encrypted</span> private void EncryptData() { <span class=cmt>//try-catch block</span> try { bool algo ; <span class=cmt> //a boolean variable to check which algorithm to use in encrypting</span> <span class=cmt>//open the 'FileStream' on the file to be encrypted</span> FileStream fin = new FileStream(opent.Text , FileMode.Open ,FileAccess.Read) ; <span class=cmt>//Make a file to save the encrypted data to and open a 'FileStream'</span> FileStream fout = new FileStream(savet.Text , FileMode.OpenOrCreate , FileAccess.Write); <span class=cmt>//set the position of the 'cursor' to the start of the file</span> fout.SetLength(0) ; <span class=cmt>//make a byte array of the size 64 bits //this is called the 'Buffer Size' of the algorithm //i.e. while encrypting blocks of the size 64bits are processed //at a single time later other blocks are of the same size. //we use 64bits because both 'DES' and 'RC2' both algorithms have //64 bit 'Buffer Size'</span> byte[] bin = new byte[4096] ; <span class=cmt>//set the total length of the file to me encrypted to a variable</span> long totlen = fin.Length ; long rdlen=0; int len ; <span class=cmt>//the code below is used to check if the file has already been //encrypted make a byte array of length '4'</span> byte[] tag = new byte[4]; <span class=cmt>//read the first 4 bytes from the file to be encrypted</span> fin.Read(tag,0,tag.Length); <span class=cmt>//if it contains the chars "[sau" then it has been already //encrypted by this program</span> if ((tag[0]==(byte)'[')&&(tag[1]==(byte)'S')&& (tag[2]==(byte)'a')&&(tag[3]==(byte)'u')) { <span class=cmt>//generate a error to let the user know of the error</span> MessageBox.Show("This file is already Encrypted or in Invalid format!") ; statusBar1.Text="Error - Invalid File Format !!" ; } else { <span class=cmt>//if the file if ok the proceed with encryption</span> statusBar1.Text="Encrypting..."; <span class=cmt>//set the file read cursor back to the 'Beginning' </span> fin.Seek(0, SeekOrigin.Begin); } <span class=cmt>//make a object of the class 'SymmetricAlgorithm'</span> SymmetricAlgorithm des ; if(radioButton1.Checked) { <span class=cmt>//if the algorithm to be used is 'DES' then initialize the //'SymmetricAlgorithm' to 'DES_CSP'</span> des = new DES_CSP(); <span class=cmt>//set the variable to true because we are using 'DES' algorithm.</span> algo=true ; } else { <span class=cmt>//if the algorithm to be used is 'RC2' then initialize the variable //'des' to 'RC2_CSP'</span> des=new RC2_CSP() ; <span class=cmt>//set the key size of the algorithm to 40 bits since we are //using a 40 bit key</span> des.KeySize=40 ; <span class=cmt>//uncomment the below code to find out the bits of keys supported //by RC2 algorithm</span> /*KeySizes[] ks = des.LegalKeySizes ; Console.WriteLine("Key Sizes Supported :") ; Console.WriteLine("Minimum Size:" +ks[0].MinSize) ; Console.WriteLine("Skip size of key: "+ks[0].SkipSize) ; Console.WriteLine("Maximum Size: "+ks[0].MaxSize) ; */ <span class=cmt>//set the bool variable to false since we are using the RC2 algorithm</span> algo=false ; } <span class=cmt>//Make a object of the inner class 'StoreCryptoStream' we pass the //bool variable containing the algorithm information and the FileStream</span> StoreCryptoStream scs = new StoreCryptoStream(algo,fout); <span class=cmt>//make an object of the 'SymmetricStreamEncryptor' class and pass //it the 'Key' and the 'Vector' this stream helps to encrypt data //according to the algorithm</span> SymmetricStreamEncryptor sse = des.CreateEncryptor(symKey, symIV); <span class=cmt>// a little extra feature here to show how to compose crypto // components that support ICryptoStream</span> SHA1_CSP sha = new SHA1_CSP(); <span class=cmt>// wire up the encryptor - hash - StoreCryptoStream</span> sse.SetSink(sha); sha.SetSource(sse); sha.SetSink(scs); scs.SetSource(sha); <span class=cmt> //read from the file to encrypt</span> while (rdlen < totlen) { <span class=cmt>//set the number of bytes read</span> len = fin.Read(bin,0,4096); <span class=cmt>//write the encrypted data</span> sse.Write(bin,0,len); <span class=cmt>//increase the size of bytes read</span> rdlen = rdlen + len; } <span class=cmt>//free up the resources</span> sse.CloseStream(); fin.Close(); fout.Close() ; statusBar1.Text="Encryption Complete !" ; } catch(Exception e) { MessageBox.Show("An exception occurred while encrypting :"+e.ToString()) ; statusBar1.Text="Error" ; } } <span class=cmt>//This method decrypts the given input file in either of the //2 algorithms 'DES' or 'RC2'. Then it writes out the decrypted file //This method first reads the input file to check to see if //its encrypted by which algorithm. then it automatically decrypts the file. //It reads the first 8 bytes of the encrypted file to find the custom //tag that we place while encrypting. //If it finds "[saudes]" it uses the 'DES' algorithm to decrypt //If it finds "[saurc2]" it uses the 'RC2' algorithm to decrypt</span> private void DecryptData() { <span class=cmt> //try-catch block</span> try { statusBar1.Text="Decrypting...." ; <span class=cmt>//open file streams to the input and outfiles</span> FileStream fin = new FileStream(opent.Text , FileMode.Open , FileAccess.Read) ; FileStream fout = new FileStream(savet.Text ,FileMode.OpenOrCreate ,FileAccess.Write); fout.SetLength(0) ; <span class=cmt>//a variable to check the validity of the input file</span> bool filecheck = false ; <span class=cmt>//make a byte array of the size 64 bits //this is called the 'Buffer Size' of the algorithm //i.e. while encrypting blocks of the size 64bits are processed //at a single time later other blocks are of the same size. //we use 64bits because both 'DES' and 'RC2' both algorithms //have 64 bit 'Buffer Size'</span> byte[] bin = new byte[4096] ; long totlen = fin.Length ; long rdlen=8; int len ; <span class=cmt>// declare a object of type 'SymmetricAlgorithm'</span> SymmetricAlgorithm des ; <span class=cmt>//set a temporary variable to length '8' (we use '8' since the size of //the tag put in the file is 8)</span> byte[] tag = new byte[8]; <span class=cmt>//read the first 8 bytes from the input file to check which algorithm //is used to encrypt the file</span> fin.Read(tag,0,tag.Length); if ((tag[0]==(byte)'[')&&(tag[1]==(byte)'S')&&(tag[2]==(byte)'a') &&(tag[3]==(byte)'u')&&(tag[4]==(byte)'d')&&(tag[5]==(byte)'e') &&(tag[6]==(byte)'s')&&(tag[7]==(byte)']')) { <span class=cmt>//If this is true then the 'DES' algorithm has been used to encrypt //the file so set the variable 'des' to new 'DES_CSP'</span> des = new DES_CSP() ; <span class=cmt>//set the variable to true since the file is encrypted</span> filecheck=true ; <span class=cmt>//generate the Key and Vector from the given password //we send 'true' here since the algorithm used is 'DES'</span> GenerateKee(true) ; } else if((tag[0]==(byte)'[')&&(tag[1]==(byte)'S')&&(tag[2]==(byte)'a') &&(tag[3]==(byte)'u')&&(tag[4]==(byte)'r')&&(tag[5]==(byte)'c') &&(tag[6]==(byte)'2')&&(tag[7]==(byte)']')) { <span class=cmt>//if this is true then the 'RC2' algorithm has been used to //encrypt the file so we set the variable 'des' to new 'RC2_CSP'</span> des = new RC2_CSP() ; <span class=cmt>//set the keysize of the algorithm</span> des.KeySize=40 ; <span class=cmt>//set the variable to true since it is encrypted</span> filecheck=true ; <span class=cmt>//generate the Key and Vector from the password given by the user //we pass false here since we are using 'RC2' algorithm</span> GenerateKee(false) ; } else { MessageBox.Show("File Error !! File is not encrypted by SymEncryptor !!") ; <span class=cmt>//set the des to null so no encryption occurs</span> des=null ; statusBar1.Text="Error "; } <span class=cmt>//if the file is encrypted then decrypt it</span> if(filecheck){ <span class=cmt>//create a object of the inner class 'StoreCryptoStream' //we pass it the FileStream</span> StoreCryptoStream scs = new StoreCryptoStream(fout); <span class=cmt>//make a object of this stream passing the Key and Vector //we use this stream since it helps us decrypt data from a //encrypted file</span> SymmetricStreamDecryptor ssd = des.CreateDecryptor(symKey, symIV); <span class=cmt>//set up the streams</span> ssd.SetSink(scs); scs.SetSource(ssd); <span class=cmt>//read the full encrypted file and decrypt</span> while (rdlen < totlen) { <span class=cmt>//set the length of the number of bytes read</span> len = fin.Read(bin,0,4096); <span class=cmt>//write the decrypted data </span> ssd.Write(bin,0,len); <span class=cmt>//increase the total read bytes variable</span> rdlen = rdlen + len; } <span class=cmt>//free up the resources</span> ssd.CloseStream(); } fin.Close(); fout.Close(); statusBar1.Text="Decryption Complete" ; } catch(Exception e) { MessageBox.Show("An exception occurred while decrypting :"+e.ToString()) ; statusBar1.Text="Error" ; } } <span class=cmt>//This is a inner class which Implements the 'ICryptoStream' interface //we write this class so that it will provide us with a custom stream //which will write and read the way we want it to</span> public class StoreCryptoStream : ICryptoStream { <span class=cmt>//two byte arrays containing the bytes to be written while encrypting</span> static byte[] tag1 = {(byte)'[',(byte)'S',(byte)'a',(byte)'u' ,(byte)'d' ,(byte)'e',(byte)'s' ,(byte)']'}; static byte[] tag2= {(byte)'[',(byte)'S',(byte)'a',(byte)'u' ,(byte)'r' ,(byte)'c',(byte)'2' ,(byte)']'}; FileStream fs; <span class=cmt>//This is the constructor of this class //it takes 2 parameters //1)a bool variable to indicate which algorithm has called it //if it 'true' then 'DES' has called it , if its 'false' then //'RC2' has called it. //2)the FileStream to the output file</span> public StoreCryptoStream(bool algo, FileStream fout) { fs = fout; if (algo){ <span class=cmt>//we are here since the variable 'algo' is 'true' indicating //that 'DES' algorithm is being used //hence it writes the byte array 'tag1' to the output file </span> fs.Write(tag1,0,8); } else { <span class=cmt>//we are here since the variable 'algo' is 'false' indicating that //'RC2'algorithm is being used //hence it writes the byte array 'tag2' to the output file</span> fs.Write(tag2,0,8) ; } } <span class=cmt> //This is another constructor which takes one parameter "FileStream" //It is called from the decrypting method</span> public StoreCryptoStream(FileStream fout) { fs=fout ; } <span class=cmt>//other methods which have to be implemented</span> public virtual void CloseStream() {fs.Close();} public virtual void CloseStream(Object obj) {fs.Close();} public virtual void SetSink(ICryptoStream pstm) {} public virtual void SetSource(CryptographicObject co) {} public virtual ICryptoStream GetSink () {return null;} <span class=cmt> // Write routines just copy output to the target file</span> public virtual void Write(byte[] bin) { int len = bin.GetLength(0); Write(bin, 0, len); } public virtual void Write(byte[] bin, int start, int len ) { fs.Write(bin,start,len); } }<span class=cmt>//StoreCryptoStream class</span> }<span class=cmt>//SymEncryptor class</span> }</pre> </td> </tr> </table>