blah blah blah is here! blah blah » Close

up1down
link

Wrote myself a small password management utility that is supposed to support encryption of a master password file. Everything seems to work fine, and no exceptions are thrown during the entire encrypt/decrypt operation. However upon trying to parse data from the resulting decryption, a Unexpected end of file has occurred. The following elements are not closed: Account. Line 6, position 10, exception is thrown.

When looking at the decrypted XML file in web browser, it only shows the first </Account> node, all other nodes did not make it out of the decryption process. I've attached the code segment below....where did I screw the pooch?


public partial class Form1 : Form
{
public string fileName = "passfile.xml";
public DataSet ds = new DataSet("Account List");
public DataTable accounts = new DataTable("Accounts");
public Form1()
{
InitializeComponent();
accountGroupsBox.Enabled = false;
menuStrip1.Enabled = false;
button2.Enabled = false;
Types type = new Types();
this.accountGroupsBox.Items.AddRange(type.accountTypes);
accounts.Columns.AddRange(new DataColumn[] {
new DataColumn("Username"),
new DataColumn("Password"),
new DataColumn("Description")});


dataGridView1.DataSource = accounts;
dataGridView1.Columns["Username"].FillWeight = 25;
dataGridView1.Columns["Password"].FillWeight = 25;
dataGridView1.Columns["Description"].FillWeight = 50;


}

private void addNewPasswordToolStripMenuItem_Click(object sender, EventArgs e)
{
Form2 addAccount = new Form2(this);
addAccount.Show();
}

private void S_Click(object sender, EventArgs e)
{
accountGroupsBox.Enabled = true;
menuStrip1.Enabled = true;
button2.Enabled = true;
label2.Text = "Interface Unlocked";
}

private void accountGroupsBox_SelectedIndexChanged(object sender, EventArgs e)
{
accounts.Clear();
try
{
XmlDocument doc = new XmlDocument();
doc.Load(fileName);


foreach (XmlNode node in doc.GetElementsByTagName("Account"))
{
if (node["AccountType"].InnerText == accountGroupsBox.SelectedItem.ToString())
{
DataRow row = accounts.Rows.Add(
node["Username"].InnerText,
node["Password"].InnerText,
node["Description"].InnerText);
}
}

}
catch (FileLoadException ex)
{
MessageBox.Show(ex.ToString(), "Error!", MessageBoxButtons.OK);
}
}
public void Encrypt()
{
string temp = Path.GetTempFileName();
string path = System.IO.Path.GetDirectoryName(Application.ExecutablePath);
byte[] pword = Encoding.UTF8.GetBytes(textBox1.Text);
byte[] hash = SHA256.Create().ComputeHash(pword);
byte[] iv = MD5.Create().ComputeHash(pword);
byte[] key = hash;

using(FileStream fsInput = new FileStream(fileName, FileMode.Open, FileAccess.Read))
using(SymmetricAlgorithm alg = Aes.Create())
using(ICryptoTransform enc = alg.CreateEncryptor(key, iv))
using (FileStream fsOutput = new FileStream(temp, FileMode.Create, FileAccess.Write))
using (CryptoStream cs = new CryptoStream(fsOutput, enc, CryptoStreamMode.Write))
{


byte[] byteInput = new byte[fsInput.Length - 1];
fsInput.Read(byteInput, 0, byteInput.Length);
cs.Write(byteInput, 0, byteInput.Length);



}
FileInfo old = new FileInfo(fileName);
FileInfo newer = new FileInfo(temp);
old.Delete();
newer.MoveTo(Path.Combine(path, fileName));

}
public void Decrypt()
{
string temp = Path.GetTempFileName();
string path = System.IO.Path.GetDirectoryName(Application.ExecutablePath);
byte[] pword = Encoding.UTF8.GetBytes(textBox1.Text);
byte[] hash = SHA256.Create().ComputeHash(pword);
byte[] iv = MD5.Create().ComputeHash(pword);
byte[] key = hash;

using(FileStream fsInput = new FileStream(fileName, FileMode.Open, FileAccess.Read))
using(SymmetricAlgorithm alg = Aes.Create())
using(ICryptoTransform enc = alg.CreateDecryptor(key, iv))
using (CryptoStream cs = new CryptoStream(fsInput, enc, CryptoStreamMode.Read))
{
StreamWriter sw = new StreamWriter(temp);
sw.Write(new StreamReader(cs).ReadToEnd());
sw.Flush();
sw.Close();

}
FileInfo encrypted = new FileInfo(fileName);
FileInfo decrypted = new FileInfo(temp);
encrypted.Delete();
decrypted.MoveTo(Path.Combine(path, fileName));
}

last answered one year ago

1 answers

up1down
link

I'm an idiot. What I had originally posted was all wrong. It was wrong because I didn't encrypt correctly which caused all the problems. The key was to allow the CryptoStream to close (and therefore flush its buffers) before interpreting the data. I didn't and I imagine your code does the same. Try flushing your CryptoStream at the end of the block to see if that fixes it.

public void Encrypt()
{
string temp = Path.GetTempFileName();
string path = System.IO.Path.GetDirectoryName(Environment.CurrentDirectory);
byte[] pword = Encoding.UTF8.GetBytes(PASSWORD);
byte[] hash = SHA256.Create().ComputeHash(pword);
byte[] iv = MD5.Create().ComputeHash(pword);
byte[] key = hash;

using (FileStream fsInput = new FileStream(PATH, FileMode.Open, FileAccess.Read))
using (SymmetricAlgorithm alg = Aes.Create())
using (ICryptoTransform enc = alg.CreateEncryptor(key, iv))
using (FileStream fsOutput = new FileStream(temp, FileMode.Create, FileAccess.Write))
using (CryptoStream cs = new CryptoStream(fsOutput, enc, CryptoStreamMode.Write))
{
byte[] byteInput = new byte[fsInput.Length];
fsInput.Read(byteInput, 0, byteInput.Length);
cs.Write(byteInput, 0, byteInput.Length);
cs.Flush();
}
FileInfo old = new FileInfo(PATH);
FileInfo newer = new FileInfo(temp);
old.Delete();
newer.MoveTo(Path.Combine(path, PATH));
}



I'll leave a now 100% working code I had put earlier for your reference. I wrote up an Encryption class to handle the encryption and decryption of data based on a password. This program also tests it. You're free to use it if you wish.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.IO;
using System.Security.Cryptography;

namespace EncryptionTest
{
public static class Encryptor
{
private static readonly SymmetricAlgorithm _algorithm = Aes.Create();

private static void CreateKeyIV(string password, out byte[] key, out byte[] iv)
{
Rfc2898DeriveBytes db = new Rfc2898DeriveBytes(password, Encoding.Unicode.GetBytes(password));
key = db.GetBytes(_algorithm.KeySize / 8);
iv = db.GetBytes(_algorithm.BlockSize / 8);
}

public static byte[] Encrypt(string password, string plaintext)
{
byte[] key, iv;
CreateKeyIV(password, out key, out iv);
using (MemoryStream encrypted = new MemoryStream())
{
using (CryptoStream enc = new CryptoStream(encrypted, _algorithm.CreateEncryptor(key, iv), CryptoStreamMode.Write))
using (StreamWriter writer = new StreamWriter(enc))
writer.Write(plaintext);
return encrypted.ToArray();
}
}

public static string Decrypt(string password, byte[] ciphertext)
{
byte[] key, iv;
CreateKeyIV(password, out key, out iv);
using (MemoryStream encrypted = new MemoryStream(ciphertext))
using (CryptoStream dec = new CryptoStream(encrypted, _algorithm.CreateDecryptor(key, iv), CryptoStreamMode.Read))
using (StreamReader reader = new StreamReader(dec))
{
try
{
return reader.ReadToEnd();
}
catch (CryptographicException)
{
throw new CryptographicException("Invalid password.");
}
}
}

public static bool TryDecrypt(string password, byte[] ciphertext, out string decoded)
{
try
{
decoded = Decrypt(password, ciphertext);
return true;
}
catch (CryptographicException)
{
decoded = String.Empty;
return false;
}
}
}

class Program
{
const string PATH = @"..\..\Program.cs";
const string PASSWORD = "foobar";

static void Main(string[] args)
{
string plaintext = File.ReadAllText(PATH);

Console.WriteLine("Original Text:");
Console.Write(plaintext);
Console.WriteLine();

byte[] ciphertext = Encryptor.Encrypt(PASSWORD, plaintext);

// print ciphertext in 32 byte blocks
int blockSize = 32;
var q = from i in Enumerable.Range(0, (int)Math.Ceiling((double)ciphertext.Length / blockSize))
let block = ciphertext.Skip(i * blockSize).Take(blockSize)
select String.Join("", block.Select(b => b.ToString("X2")).ToArray());
Console.WriteLine("Encrypted Data:");
foreach (string line in q)
Console.WriteLine(line);
Console.WriteLine();

string decoded;
// try bad password
Console.Write("Trying To Decrypt With Bad Password: ");
if (Encryptor.TryDecrypt(PASSWORD + "x", ciphertext, out decoded))
{
Console.WriteLine("PASSED!");
Console.WriteLine("Decrypted Text:");
Console.Write(decoded);
Console.WriteLine();
}
else
{
Console.WriteLine("FAILED!");
Console.WriteLine();
}

// print decrypted data
Console.Write("Trying To Decrypt With Good Password: ");
if (Encryptor.TryDecrypt(PASSWORD, ciphertext, out decoded))
{
Console.WriteLine("PASSED!");
Console.WriteLine("Decrypted Text:");
Console.Write(decoded);
Console.WriteLine();
}
else
{
Console.WriteLine("FAILED!");
Console.WriteLine();
}

Console.Write("Decrypting With Bad Password: ");
decoded = Encryptor.Decrypt(PASSWORD + "x", ciphertext); // fail
Console.WriteLine("Decrypted Text:");
Console.Write(decoded);
Console.WriteLine();

Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
Console.WriteLine();
}
}
}


[edit]
Fixed++.

stev0
45

Wasnt sure which site to catch you on. Like I noted earlier, the flushing thing is working nicely. Based on the example you've put here, I understand what the encryption class is doing, but its not clear to me how I would modify this for what I'm trying to do. I figure the entire encryption part shouldnt be changed, I would just change the portions that output the decrypted data to the Console to instead direct the output into the Temp file and do the move/rename like I've been doing?

Feedback