From 834c91d5af192f02f259e3ce8b6a163be46cc3d7 Mon Sep 17 00:00:00 2001 From: h5p9sl Date: Fri, 30 Nov 2018 04:03:21 -0700 Subject: [PATCH] Added backwards compatibility for file loading --- Crypto Notepad/AES.cs | 75 ++++++++++++++++++++++++++++++++++------- Crypto Notepad/Form1.cs | 6 ++-- 2 files changed, 65 insertions(+), 16 deletions(-) diff --git a/Crypto Notepad/AES.cs b/Crypto Notepad/AES.cs index 0e75dc2..7575a77 100644 --- a/Crypto Notepad/AES.cs +++ b/Crypto Notepad/AES.cs @@ -2,6 +2,7 @@ using System.IO; using System.Security.Cryptography; using System.Text; +using System.Windows.Forms; namespace Crypto_Notepad { @@ -52,23 +53,35 @@ public void DeleteMetadataFromBuffer(ref byte[] rawData) rawData = buffer; } - public void GetMetadata(byte[] rawData) + public bool GetMetadata(byte[] rawData) { int index = 0; + bool result = false; // Read initialVector - for (int i = 0; index < rawData.Length; index++, i++) + for (int i = 0; + index < rawData.Length; + index++, i++) { if (rawData[index] == '\0') // Null terminator { + result = true; index++; break; } - this.initialVector[i] = rawData[index]; + if (index < this.initialVector.Length) + this.initialVector[i] = rawData[index]; + else + break; } + + if (!result) return false; + // This is kind of a dirty fix, but it gets the job done // Get length of salt int length = 0; - for (int i = index; i < rawData.Length; i++) + for (int i = index; + i < rawData.Length; + i++) { if (rawData[i] == '\0') // Null terminator { @@ -82,24 +95,43 @@ public void GetMetadata(byte[] rawData) System.Buffer.BlockCopy(rawData, index - 1, this.salt, 0, length); this._offsetToData = this.salt.Length + 1 + this.initialVector.Length + 1; + + return true; } } class AES { public static string Encrypt(string plainText, string password, - string salt = "Kosher", string hashAlgorithm = "SHA1", + string salt = null, string hashAlgorithm = "SHA1", int passwordIterations = 2, int keySize = 256) { if (string.IsNullOrEmpty(plainText)) return ""; - byte[] saltValueBytes = Encoding.ASCII.GetBytes(salt); - byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText); + byte[] plainTextBytes; + byte[] saltValueBytes; + + // In case user wants a random salt or salt is null/empty for some other reason + if (string.IsNullOrEmpty(salt)) + { + saltValueBytes = new byte[64]; // Nice and long + RandomNumberGenerator rng = RandomNumberGenerator.Create(); + rng.GetNonZeroBytes(saltValueBytes); + } + else + { + saltValueBytes = Encoding.ASCII.GetBytes(salt); + } + + plainTextBytes = Encoding.UTF8.GetBytes(plainText); PasswordDeriveBytes derivedPassword = new PasswordDeriveBytes (password, saltValueBytes, hashAlgorithm, passwordIterations); + // Null password; adds *some* memory dump protection + password = null; + byte[] keyBytes = derivedPassword.GetBytes(keySize / 8); RijndaelManaged symmetricKey = new RijndaelManaged(); symmetricKey.Mode = CipherMode.CBC; @@ -134,13 +166,13 @@ public static string Encrypt(string plainText, string password, return Convert.ToBase64String(cipherTextBytes); } - public static string Decrypt(string cipherText, string password, + public static string Decrypt(string cipherText, string password, string salt = "Kosher", string hashAlgorithm = "SHA1", int passwordIterations = 2, int keySize = 256) { if (string.IsNullOrEmpty(cipherText)) - return ""; + return null; byte[] initialVectorBytes; byte[] saltValueBytes; @@ -148,10 +180,27 @@ public static string Decrypt(string cipherText, string password, // Extract metadata from file AESMetadata metadata = new AESMetadata(); - metadata.GetMetadata(cipherTextBytes); - saltValueBytes = metadata.salt; - initialVectorBytes = metadata.initialVector; - metadata.DeleteMetadataFromBuffer(ref cipherTextBytes); + if (!metadata.GetMetadata(cipherTextBytes)) + { + // Metadata parsing error + DialogResult result = MessageBox.Show("Unable to parse file metadata.\nAttempt to open anyway?\n(May result in a \'Incorrect Key\' error if the salt is wrong.)", + "Missing or Corrupted Metadata", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Asterisk); + if (result == DialogResult.Yes) + { + // Default initialization vector from builds v1.1.2 and older + const string default_IV = "16CHARSLONG12345"; + + initialVectorBytes = Encoding.ASCII.GetBytes(default_IV); + saltValueBytes = Encoding.ASCII.GetBytes(salt); + } + else { return null; } + } + else + { + saltValueBytes = metadata.salt; + initialVectorBytes = metadata.initialVector; + metadata.DeleteMetadataFromBuffer(ref cipherTextBytes); + } PasswordDeriveBytes derivedPassword = new PasswordDeriveBytes (password, saltValueBytes, hashAlgorithm, passwordIterations); diff --git a/Crypto Notepad/Form1.cs b/Crypto Notepad/Form1.cs index d6eb868..a0a363f 100644 --- a/Crypto Notepad/Form1.cs +++ b/Crypto Notepad/Form1.cs @@ -88,7 +88,7 @@ void DecryptAES() { string opnfile = File.ReadAllText(OpenFile.FileName); string NameWithotPath = Path.GetFileName(OpenFile.FileName); - string de = AES.Decrypt(opnfile, publicVar.encryptionKey, ps.HashAlgorithm, ps.PasswordIterations, ps.KeySize); + string de = AES.Decrypt(opnfile, publicVar.encryptionKey, ps.TheSalt, ps.HashAlgorithm, ps.PasswordIterations, ps.KeySize); customRTB.Text = de; this.Text = appName + NameWithotPath; @@ -165,7 +165,7 @@ private void openAsotiations() } publicVar.okPressed = false; - string de = AES.Decrypt(opnfile, publicVar.encryptionKey, ps.HashAlgorithm, ps.PasswordIterations, ps.KeySize); + string de = AES.Decrypt(opnfile, publicVar.encryptionKey, ps.TheSalt, ps.HashAlgorithm, ps.PasswordIterations, ps.KeySize); customRTB.Text = de; this.Text = appName + NameWithotPath; @@ -938,7 +938,7 @@ void AutoLock(bool minimize) OpenFile.FileName = filename; string opnfile = File.ReadAllText(OpenFile.FileName); string NameWithotPath = Path.GetFileName(OpenFile.FileName); - string de = AES.Decrypt(opnfile, publicVar.encryptionKey, ps.HashAlgorithm, ps.PasswordIterations, ps.KeySize); + string de = AES.Decrypt(opnfile, publicVar.encryptionKey, ps.TheSalt, ps.HashAlgorithm, ps.PasswordIterations, ps.KeySize); this.Text = appName + NameWithotPath; filename = OpenFile.FileName;