//********************************************************************** // // SimCrypt.NET // .NET 1.1/2.0 AES 256 bit Encryption Tool // // Copyright (C) 2006 JavaScience Consulting // //********************************************************************** // // SimCryptNet.cs // // This C# utility for .NET Framework 1.1/2.0 is a simple GUI application // to encrypt any local file using 256 bit Rijndael (AES) encryption. // Uses a new random 16 byte salt data for each invocation. // Uses 33000 iterations (~15 bits extra computational entropy) // Writes output file formatted as: // byte[] salt // byte[] IV // byte inputfilenamelength // byte[] inputfilename // byte[] encryptedinputfilecontents // All output file data encrypted except salt and IV // // Also decrypts any binary DER or b64 encoded CMS/PKCS #7 EnvelopedData file. // Raw binary output, or base64 encoded (both salt and encrypted content) //*********************************************************************** using System; using System.IO; using System.Diagnostics; using System.Net; using System.Text; using System.Windows.Forms; using System.Drawing; using System.Reflection; using System.Security.Cryptography; using System.Runtime.InteropServices; using System.ComponentModel; namespace JavaScience { public class Win32 { [DllImport("crypt32.dll", CharSet=CharSet.Auto, SetLastError=true)] public static extern IntPtr CertOpenSystemStore( IntPtr hCryptProv, string storename) ; [DllImport("crypt32.dll", SetLastError=true)] public static extern bool CertCloseStore( IntPtr hCertStore, uint dwFlags) ; [DllImport("crypt32.dll", SetLastError=true)] public static extern bool CryptDecryptMessage( ref CRYPT_DECRYPT_MESSAGE_PARA pDecryptPara, byte[] pbEncryptedBlob, int cbEncryptedBlob, [In, Out] byte[] pbDecrypted, ref int pcbDecrypted, IntPtr ppXchgCert); } [StructLayout(LayoutKind.Sequential)] public struct CRYPT_DECRYPT_MESSAGE_PARA { public int cbSize; public uint dwMsgAndCertEncodingType; public int cCertStore; public IntPtr rghCertStore; //public uint dwFlags; } //--Note: CRYPT_DECRYPT_MESSAGE_PARA.dwFlags only for XP+ OS public class SimCryptNet : Form { const String TITLE = "SymCrypt.NET"; const String INSTRUCT= "(1) Select a File or URL (2) Enter Encryption Key (3) Encrypt, Decrypt or Denvelop "; const String ABOUT = "AES 256 bit Encryption Tool: JavaScience 2006"; const String ICONIMAGE = "JavaScience.simcrypt.gif"; const int SALTBYTES = 16; const int ITERS = 33000; //roughly 15 bits const string MY = "MY"; const uint PKCS_7_ASN_ENCODING = 0x00010000; const uint X509_ASN_ENCODING = 0x00000001; static uint MY_ENCODING_TYPE = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING ; private Label about; private Label lbl; private Label instr; private TextBox pwbox; private TextBox filepath; private Button selectButton; private Button encryptButton; private Button decryptButton; private Button denvelopButton; private PictureBox imagebox; private String infile; private String DESKPATH; private Label lb64; private Label lbautostart; private CheckBox b64check; private CheckBox autostartcheck; private bool autostartenabled = false; private bool b64enabled = false; public SimCryptNet() : base() { DESKPATH = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory); InitializeComponent(); LoadImageIcon(); } private void LoadImageIcon() { Assembly oass = Assembly.GetExecutingAssembly(); try { Stream icostream = oass.GetManifestResourceStream(ICONIMAGE); imagebox.Image = (Image) new Bitmap(icostream); } catch { } } private void InitializeComponent() { int x2ndcol = 170; this.Size = new Size(510, 240); this.Text = TITLE; this.StartPosition = FormStartPosition.Manual; this.SetDesktopLocation(250,250) ; this.BackColor = Color.FromArgb(0xE0, 0xE0, 0xE0) ; imagebox = new PictureBox(); imagebox.Location = new Point(05, 10); imagebox.SizeMode = PictureBoxSizeMode.AutoSize ; about = new Label(); about.AutoSize = true; about.Text = ABOUT ; about.Location = new Point(x2ndcol, 10); selectButton = new Button(); selectButton.Text = "SelectFile"; selectButton.BackColor = Color.Yellow; selectButton.ForeColor = Color.Blue; selectButton.Location = new Point(20, 50); selectButton.Click += new EventHandler(this.select_Clicked); lbl = new Label(); lbl.Text = "Encryption Key:"; lbl.Font = new Font(lbl.Font.FontFamily, 11, lbl.Font.Style); lbl.Location = new Point(x2ndcol, 50); lbl.AutoSize = true; pwbox = new TextBox(); pwbox.Location = new Point(x2ndcol + lbl.Width+10,50); pwbox.Width = 150; pwbox.Text = ""; pwbox.PasswordChar = '*'; encryptButton = new Button(); encryptButton.Text = "Encrypt"; encryptButton.BackColor = Color.Red; encryptButton.Location = new Point(20, 90); encryptButton.Click += new EventHandler(this.encrypt_Clicked); decryptButton = new Button(); decryptButton.Text = "Decrypt"; decryptButton.BackColor = Color.LightGreen; decryptButton.Location = new Point(x2ndcol, 75); decryptButton.Click += new EventHandler(this.decrypt_Clicked); denvelopButton = new Button(); denvelopButton.Text = "Denvelop"; denvelopButton.BackColor = Color.LightGreen; denvelopButton.Location = new Point(x2ndcol, 105); denvelopButton.Click += new EventHandler(this.denvelop_Clicked); lb64 = new Label(); lb64.Text = "B64:"; lb64.TextAlign = ContentAlignment.BottomLeft; lb64.Location = new Point(pwbox.Left, 75); lb64.AutoSize = true; b64check = new CheckBox(); b64check.Location = new Point(lb64.Right + 40, 75) ; b64check.CheckedChanged += new EventHandler(this.b64Check_Clicked); lbautostart = new Label(); lbautostart.Text = "AutoStart:"; lbautostart.TextAlign = ContentAlignment.BottomLeft; lbautostart.Location = new Point(pwbox.Left, 100); lbautostart.AutoSize = true; autostartcheck = new CheckBox(); autostartcheck.Location = new Point(lb64.Right + 40, 100) ; autostartcheck.CheckedChanged += new EventHandler(this.autostartCheck_Clicked); filepath = new TextBox(); filepath.Width = this.Width - 40; filepath.Location = new Point(20, 135); instr = new Label(); instr.Text = INSTRUCT; instr.AutoSize = true; instr.Location = new Point(05, 175); this.Controls.Add(imagebox); this.Controls.Add(about); this.Controls.Add(selectButton); this.Controls.Add(lbl); this.Controls.Add(pwbox); this.Controls.Add(encryptButton); this.Controls.Add(decryptButton); this.Controls.Add(denvelopButton); this.Controls.Add(filepath); this.Controls.Add(instr) ; this.Controls.Add(lb64); this.Controls.Add(b64check) ; this.Controls.Add(lbautostart); this.Controls.Add(autostartcheck); } private void select_Clicked(object sender, EventArgs e) { String getfile = getInFileDialogName(DESKPATH); if(getfile !=null){ infile = getfile; //update instance variable filepath.Text = infile; //update display } } private void b64Check_Clicked(object sender, EventArgs e) { b64enabled = b64check.Checked ; } private void autostartCheck_Clicked(object sender, EventArgs e) { autostartenabled = autostartcheck.Checked ; } private void encrypt_Clicked(object sender, EventArgs e) { if(!File.Exists(filepath.Text)) { MessageBox.Show("File '" + filepath.Text + "' NOT FOUND ", TITLE, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } if(pwbox.Text.Equals("")) { MessageBox.Show("No Encryption Key provided ", TITLE, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } String outfile = getOutFileDialogName(DESKPATH, "_simencrypted", "Save encrypted file to ..."); if(outfile == null) { MessageBox.Show("No output file specified ", TITLE, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } if(EncryptAES(filepath.Text, outfile, pwbox.Text, b64enabled)) MessageBox.Show("Created AES encrypted file '" + outfile + "' ", TITLE, MessageBoxButtons.OK, MessageBoxIcon.Information); else MessageBox.Show("FAILED to encrypt file ", TITLE, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } private void decrypt_Clicked(object sender, EventArgs e) { String filetodecrypt = null; //for local file String dnldfile = null; //for URL bool isurl = false; if(pwbox.Text.Equals("")) { MessageBox.Show("No Encryption Key provided ", TITLE, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } if(File.Exists(filepath.Text)){ filetodecrypt = filepath.Text; } else if(GetUrlFile(filepath.Text, ref dnldfile)) { //if URL file valid and saved isurl = true; filetodecrypt = dnldfile; } else { MessageBox.Show("File '" + filepath.Text + "' FILE or URL not found ", TITLE, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } String outfile = null; if(DecryptAES(filetodecrypt, ref outfile, pwbox.Text, b64enabled)){ if(isurl) MessageBox.Show("Downloaded url and saved to file:\n" + dnldfile + "\n\n" + "Decrypted AES encrypted file to:\n" + outfile, TITLE, MessageBoxButtons.OK, MessageBoxIcon.Information); else MessageBox.Show("Decrypted AES encrypted file to:\n" + outfile, TITLE, MessageBoxButtons.OK, MessageBoxIcon.Information); if(autostartenabled) LaunchProcess(outfile); } else { if(isurl) MessageBox.Show("Downloaded url and saved to file:\n" + dnldfile + "\n\n" + "FAILED to decrypt file ", TITLE, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); else MessageBox.Show("FAILED to decrypt file ", TITLE, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } } private void denvelop_Clicked(object sender, EventArgs e) { String filetodecrypt = null; //for local file String dnldfile = null; //for URL bool isurl = false; if(File.Exists(filepath.Text)){ filetodecrypt = filepath.Text; } else if(GetUrlFile(filepath.Text, ref dnldfile)) { //if URL file valid and saved isurl = true; filetodecrypt = dnldfile; } else { MessageBox.Show("File '" + filepath.Text + "' FILE or URL not found ", TITLE, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } String outfile = null; if(DenvelopCMS(filetodecrypt, ref outfile)) { if(isurl) MessageBox.Show("Downloaded url and saved to file:\n" + dnldfile + "\n\n" + "Denveloped file to:\n" + outfile, TITLE, MessageBoxButtons.OK, MessageBoxIcon.Information); else MessageBox.Show("Denveloped file to:\n" + outfile, TITLE, MessageBoxButtons.OK, MessageBoxIcon.Information); if(autostartenabled) LaunchProcess(outfile); } else { if(isurl) MessageBox.Show("Downloaded url and saved to file:\n" + dnldfile + "\n\n" + "FAILED to denvelop file ", TITLE, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); else MessageBox.Show("FAILED to denvelop file ", TITLE, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } } private bool GetUrlFile(String url, ref String savefile) { const int bufferLen = 1000; String DESKPATH = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory); try { Uri myUri =new Uri(url); String localpath = myUri.LocalPath; String filename = Path.GetFileName(localpath); if( filename == String.Empty) savefile = DESKPATH + "\\_simcrypturl"; else savefile = DESKPATH + "\\" + filename; WebRequest myRequest= WebRequest.Create(myUri); myRequest.Timeout=7000; //7 second timeout HttpWebResponse myResponse = (HttpWebResponse) myRequest.GetResponse(); long contentsize = myResponse.ContentLength; //Console.WriteLine("ContentLength: {0}", myResponse.ContentLength) ; FileStream fOut = new FileStream(savefile, FileMode.Create, FileAccess.Write); Stream instr = myResponse.GetResponseStream(); byte[] buff = new byte[bufferLen]; int bytesread = 0; while((bytesread = instr.Read(buff, 0, bufferLen))>0) fOut.Write(buff, 0, bytesread); fOut.Flush(); fOut.Close(); instr.Close(); myResponse.Close(); return true; } catch(Exception) { return false ; } } /* EncryptAES() Write encrypted output file formatted as: byte[] salt byte[] IV byte inputfilenamelength byte[] inputfilename byte[] encryptedinputfilecontents All output encrypted except salt and IV */ private bool EncryptAES(String fileIn, String fileOut, String pswd, bool b64enabled) { String fileInName = null; if(!File.Exists(fileIn)) return false; try{ fileInName = Path.GetFileName(fileIn);} //ensure valid filename characters catch { return false; } byte[] finname = Encoding.ASCII.GetBytes(fileInName); int fnamelen = finname.Length ; if(fnamelen >255) //filename must be <256 characters long (length encoded into 1 byte) return false; try{ CryptoStream cstream = null; CryptoStream b64str = null; FileStream fSIn = new FileStream(fileIn, FileMode.Open, FileAccess.Read); FileStream fSOut = new FileStream(fileOut, FileMode.Create, FileAccess.Write); byte[] ransalt = new byte[SALTBYTES]; //salt can be any size RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); rng.GetBytes(ransalt) ; PasswordDeriveBytes pdb = new PasswordDeriveBytes(pswd, ransalt, "SHA1", ITERS); Rijndael algor = Rijndael.Create(); //instantiages with random key and IV algor.Key = pdb.GetBytes(32); //32 byte (256 bit) key is derived from password if(b64enabled) //if b64 requested, wrap output stream with B64 encoder stream { b64str = new CryptoStream(fSOut, new ToBase64Transform(), CryptoStreamMode.Write); b64str.Write(ransalt, 0, ransalt.Length); //write out the random salt to file as b64 b64str.Write(algor.IV, 0, algor.IV.Length); //write out the random IV to file as b64 cstream = new CryptoStream(b64str, algor.CreateEncryptor(), CryptoStreamMode.Write); } else { fSOut.Write(ransalt, 0, ransalt.Length); //write out the random salt to file as binary fSOut.Write(algor.IV, 0,algor.IV.Length); //write out the random IV to file as binary cstream = new CryptoStream(fSOut, algor.CreateEncryptor(), CryptoStreamMode.Write); } int bufferLen = 1024; byte[] buff = new byte[bufferLen]; int bytesread = 0; //----- Encrypt the original filename information ------------ cstream.WriteByte((byte)fnamelen); //write encrypted byte with original filename length cstream.Write(finname, 0, fnamelen); //write encrypted ASCII encoded original filename while((bytesread = fSIn.Read(buff, 0, bufferLen))>0) //write encrypted file contents cstream.Write(buff, 0, bytesread); cstream.FlushFinalBlock(); fSIn.Close(); fSOut.Close(); cstream.Close(); cstream.Clear(); if(b64str !=null) b64str.Clear(); Array.Clear(buff, 0, buff.Length) ; return true; } catch(Exception exc) { MessageBox.Show("Problem encrypting file\n" + exc.Message, TITLE, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return false; } } private bool DecryptAES(String fileIn, ref String fileOut, String pswd, bool b64enabled) { if(!File.Exists(fileIn) || (new FileInfo(fileIn)).Length0) fSOut.Write(buff, 0, bytesread); fSOut.Close(); fSIn.Close(); cstream.Close(); cstream.Clear(); if(b64str !=null) b64str.Clear(); Array.Clear(buff, 0, buff.Length) ; return true; } catch(Exception exc) { MessageBox.Show("Problem decrypting file\n" + exc.Message, TITLE, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return false; } finally { try { if(fSIn !=null) fSIn.Close(); if(fSOut !=null) fSOut.Close(); } catch(Exception) {;} } } //------ Denvelop CMS/PKCS #7 file using Pinvoke; does NOT use streaming ----- private bool DenvelopCMS(String fileIn, ref String fileOut) { String sysstore = MY; IntPtr hSysStore = IntPtr.Zero; IntPtr hCertCntxt = IntPtr.Zero; IntPtr pProvInfo = IntPtr.Zero; IntPtr pexcKey = IntPtr.Zero; const long MAXFILESIZE = 10000000; //max size 10 Mb //------ Validate input ---------- if(!File.Exists(fileIn)) return false; if( (new FileInfo(fileIn)).Length > MAXFILESIZE) return false; //------- Get encoded enveloped data from file ----- byte[] envdata = GetFileBytes(fileIn); byte[] denvbytes; bool retstatus = false; int decbytes = 0; hSysStore = Win32.CertOpenSystemStore(IntPtr.Zero, sysstore) ; if(hSysStore == IntPtr.Zero) { return false; } CRYPT_DECRYPT_MESSAGE_PARA messpara = new CRYPT_DECRYPT_MESSAGE_PARA(); messpara.cbSize = Marshal.SizeOf(messpara); messpara.dwMsgAndCertEncodingType = MY_ENCODING_TYPE; messpara.cCertStore = 1; messpara.rghCertStore = Marshal.AllocHGlobal(IntPtr.Size); //one cert store pointer Marshal.WriteIntPtr(messpara.rghCertStore, hSysStore); try { //---- if fails, then might be b64 encoded file; try b64 decoding ----- if(!Win32.CryptDecryptMessage(ref messpara, envdata, envdata.Length, null, ref decbytes, IntPtr.Zero)) { ASCIIEncoding ascii = new ASCIIEncoding(); String datastr = ascii.GetString(envdata); envdata = Convert.FromBase64String(datastr); //try to b64 decode; throws NumberFormatException } if(Win32.CryptDecryptMessage(ref messpara, envdata, envdata.Length, null, ref decbytes, IntPtr.Zero)) { denvbytes = new byte[decbytes]; if(Win32.CryptDecryptMessage(ref messpara, envdata, envdata.Length, denvbytes, ref decbytes, IntPtr.Zero)) { fileOut = getOutFileDialogName(DESKPATH, "_simdenveloped", "Save denveloped file to ..."); if(fileOut != null) //if filedialog not cancelled { FileStream fSOut = new FileStream(fileOut, FileMode.Create, FileAccess.Write); fSOut.Write(denvbytes, 0, decbytes); fSOut.Close(); retstatus = true; } } } return retstatus; } //end try catch(Exception exc) { MessageBox.Show("Problem denveloping file\n" + exc.Message, TITLE, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return retstatus; } finally { Marshal.FreeHGlobal(messpara.rghCertStore); if(hSysStore != IntPtr.Zero) Win32.CertCloseStore(hSysStore, 0) ; } } private static String getInFileDialogName(String mydir) { OpenFileDialog openFileDialog1 = new OpenFileDialog(); openFileDialog1.Title = "Open File to Encrypt/Decrypt .." ; openFileDialog1.InitialDirectory = mydir ; openFileDialog1.RestoreDirectory = true ; if(openFileDialog1.ShowDialog() == DialogResult.OK) return openFileDialog1.FileName ; else return null; } private static String getOutFileDialogName(String mydir, String fname, String title) { SaveFileDialog saveFileDialog1 = new SaveFileDialog(); saveFileDialog1.Title = title ; saveFileDialog1.InitialDirectory = mydir ; saveFileDialog1.RestoreDirectory = true ; saveFileDialog1.FileName = fname ; if(saveFileDialog1.ShowDialog() == DialogResult.OK) return saveFileDialog1.FileName ; else return null; } private static byte[] GetFileBytes(String filename){ if(!File.Exists(filename)) return null; Stream stream=new FileStream(filename,FileMode.Open); int datalen = (int)stream.Length; byte[] filebytes =new byte[datalen]; stream.Seek(0,SeekOrigin.Begin); stream.Read(filebytes,0,datalen); stream.Close(); return filebytes; } private void LaunchProcess(String applic) { if(!File.Exists(applic)) return; Process p = new Process(); p.StartInfo.FileName = applic; //allow file-extension mapping p.StartInfo.UseShellExecute = true; try{ p.Start(); } catch {;} } [STAThread] public static void Main() { SimCryptNet app = new SimCryptNet(); Application.Run(app); } } }