If i stop CryptoStream Read i get Bad Data exception - c#

I'm having problem with CryptoStream Decryptor.
I'm decrypting file on another Thread.
So here is the problem:
When I let the file to decrypt to the end, everything is allright but when I stop thread, using global variable, and get out of while loop
while( !stopThread && ( nBRead = csFile.Read(readbuf, 0, 8192)) != 0)
I get Bad Data exception at thecryptostream Dispose().
What i'm doing wrong ??
Here's my code:
string ext;
//textBox1.Text = "";
OpenFileDialog ofdFile = new OpenFileDialog();
if (textMode)
ofdFile.Title = "Please select text to decrypt.";
else
ofdFile.Title = "Please select file to decrypt.";
OpenFileDialog ofdKey = new OpenFileDialog();
ofdKey.Title = "Please select KEY.";
// mora ovo ili invoke koga nema dialog :)
originalContex.Send(delegate
{
dialogRes = ofdFile.ShowDialog();
dialogResKey = ofdKey.ShowDialog();
}, null);
if ( dialogRes == DialogResult.OK && dialogResKey == DialogResult.OK )
{
FileStream fsKey = new FileStream(ofdKey.FileName, FileMode.Open);
byte[] iv = new byte[8];
byte[] key = new byte[24];
byte[] extB = new byte[20];
fsKey.Read(iv, 0, 8);
fsKey.Read(key, 0, 24);
fsKey.Read(extB, 0, 20);
fsKey.Dispose();
FileStream fsOpenedFile = new FileStream(ofdFile.FileName, FileMode.Open, FileAccess.Read);
CryptoStream csFile = new CryptoStream(fsOpenedFile, new TripleDESCryptoServiceProvider().CreateDecryptor(key, iv), CryptoStreamMode.Read);
if (textMode)
{
int readbuf;
List<byte> lb = new List<byte>();
while ((readbuf = csFile.ReadByte()) != -1)
lb.Add((byte)readbuf);
textBox1.Invoke( new MethodInvoker(() => { textBox1.Text = Encoding.UTF8.GetString(lb.ToArray()); }) );
prog.Invoke(new MethodInvoker(() => { prog.Value = 100; }));
}
else // filemode
{
byte[] readbuf = new byte[8192];
ext = Encoding.UTF8.GetString(extB).Trim('\0');
string saveDir = Path.GetDirectoryName(ofdFile.FileName) + "\\" + Path.GetFileNameWithoutExtension(ofdFile.FileName) + "_DECRYPTED";
Directory.CreateDirectory( saveDir );
Directory.SetCurrentDirectory( saveDir );
FileStream fsDecrFile = new FileStream(Path.GetFileNameWithoutExtension(ofdFile.FileName) + ext, FileMode.Create, FileAccess.Write);
FileInfo fi = new FileInfo(ofdFile.FileName);
long oneProc = fi.Length / 100;
int nBRead = 0;
long nBReadacc = 0;
while ( !stopThread && ( nBRead = csFile.Read(readbuf, 0, 8192)) != 0 )
{
nBReadacc += nBRead;
fsDecrFile.Write(readbuf, 0, nBRead);
if (nBReadacc >= oneProc)
{
nBReadacc = 0;
prog.Invoke(new MethodInvoker(() => { prog.Value +=1; }));
}
}
try
{
csFile.Dispose();
}
catch (CryptographicException e)
{
MessageBox.Show(e.Message);
}
// MessageBox.Show(nBReadacc.ToString());
fsDecrFile.Flush();
fsDecrFile.Dispose();
prog.Invoke(new MethodInvoker(() => { prog.Value = 100; }));
}
fsOpenedFile.Dispose();
// csFile.CopyTo
}
ofdFile.Dispose();
ofdKey.Dispose();
}

Related

updating XDocument with DPAPI not working?

I am new to C# and cryptography but I want to secure some data like an account with DPAPI in a C# project.
I tryed some ways to do it but the data passed is XDocument and have to stay as it.
I tryed to pass a string and modify it with no problem but when it comes to the XML Data it is broken.
I am using the sample of MS dotnet standard.
This code works (initalization of the file)
byte[] toEncrypt = null;
byte[] entropy = CreateRandomEntropy();
FileStream fStream = new FileStream("Data.dat", FileMode.OpenOrCreate);
var length = new System.IO.FileInfo("Data.dat").Length;
if (length == 0)
{
XDocument doc =
new XDocument(
new XElement("data",
new XElement("global"),
new XElement("accounts")
)
);
toEncrypt = UnicodeEncoding.ASCII.GetBytes(doc.ToString());
EncryptDataToStream(toEncrypt, entropy, DataProtectionScope.CurrentUser, fStream);
}
fStream.Close();
Then I update this previous sample with some data:
fStream = new FileStream("Data.dat", FileMode.OpenOrCreate);
byte[] decryptData = DecryptDataFromStream(entropy, DataProtectionScope.CurrentUser, fStream, 2);
string xml = UnicodeEncoding.ASCII.GetString(decryptData);
XDocument xmlData = XDocument.Parse(xml);
int maxId = 0;
if (xmlData.Descendants("account").Any())
{
maxId = xmlData.Descendants("account")
.Max(x => (int)x.Attribute("id"));
}
maxId++;
var compteElement = new XElement("account",
new XAttribute("id", maxId),
new XElement("login", "monemail#home.fr"),
new XElement("label", "compte TEST")
);
xmlData.Element("data").Element("accounts").Add(compteElement);
MemoryStream ms = new MemoryStream();
var settings = new XmlWriterSettings()
{
Indent = true
};
using (var writer = XmlWriter.Create(ms, settings))
{
xmlData.WriteTo(writer);
writer.Flush();
StreamReader sr = new StreamReader(ms);
ms.Seek(0, SeekOrigin.Begin);
String content = sr.ReadToEnd();
byte[] BytedxmlData = UnicodeEncoding.ASCII.GetBytes(content);
int bytesWritten = EncryptDataToStream(BytedxmlData, entropy, DataProtectionScope.CurrentUser, fStream);
}
fStream.Flush();
fStream.Close();
And I try to read the data:
fStream = new FileStream("Data.dat", FileMode.Open);
byte[] decryptData2 = DecryptDataFromStream(entropy, DataProtectionScope.CurrentUser, fStream, 2);
Console.WriteLine("Decrypted data: " + UnicodeEncoding.ASCII.GetString(decryptData2));
fStream.Close();
Data.dat grown each times of the byte it isi being added at each update. Some I think it is being populated correctly but when I read it, I get only the first record the initialize the file and anyupdate.
Here are the encrypt and decrypt methods:
public static int EncryptDataToStream(byte[] Buffer, byte[] Entropy, DataProtectionScope Scope, Stream S)
{
if (Buffer == null)
throw new ArgumentNullException("Buffer");
if (Buffer.Length <= 0)
throw new ArgumentException("Buffer");
if (Entropy == null)
throw new ArgumentNullException("Entropy");
if (Entropy.Length <= 0)
throw new ArgumentException("Entropy");
if (S == null)
throw new ArgumentNullException("S");
int length = 0;
byte[] encryptedData = ProtectedData.Protect(Buffer, Entropy, Scope);
if (S.CanWrite && encryptedData != null)
{
S.Write(encryptedData, 0, encryptedData.Length);
length = encryptedData.Length;
}
return length;
}
public static byte[] DecryptDataFromStream(byte[] Entropy, DataProtectionScope Scope, Stream S, int Length)
{
if (S == null)
throw new ArgumentNullException("S");
if (Length <= 0)
throw new ArgumentException("Length");
if (Entropy == null)
throw new ArgumentNullException("Entropy");
if (Entropy.Length <= 0)
throw new ArgumentException("Entropy");
byte[] inBuffer = new byte[S.Length];
byte[] outBuffer;
if (S.CanRead)
{
S.Read(inBuffer, 0, inBuffer.Length);
outBuffer = ProtectedData.Unprotect(inBuffer, Entropy, Scope);
}
else
{
throw new IOException("Could not read the stream.");
}
return outBuffer;
}
Thanks to #jdweng I was from with the encoding.
Got to change UnicodeEncoding.ASCII to Encoding.UTF-8

How can i add a progress bar on a cryptostream write operation in c#

I have been working on a program to encrypt and decrypt a file as part of a project. The program is working fine on its own but when I try to add a progress bar to it to show the progress of the encryption/decryption process things go wrong. The progress bar proceeds pretty good upto around 85-90% and then it throws an error that the value has exceeded the maximum limit. Also the bar proceeds too slow, it takes around 15-20 seconds to reach the error situation even when I am encrypting a 16KB file, which takes almost no time when done without any progress bar. I have tried using a backgroundworker to implement the progressbar. Can anyone can tell me how I can get the progressbar to work on my program?
Here is my code for the encryption process:
public void EncryptFile()
{
try
{
OpenFileDialog od = new OpenFileDialog();
od.Title = "Select File To Encrypt";
od.Filter = "All files (*.*)|*.*";
string ifile = "";
if (od.ShowDialog() == DialogResult.OK)
{
ifile = od.InitialDirectory + od.FileName;
}
else
{
MessageBox.Show("No file selected!!");
goto b;
}
if (Path.GetExtension(ifile) == ".arv")
{
MessageBox.Show("Error!!File already Encrypted.");
return;
}
string ofile = ifile + ".arv";
a: string password = Prompt.ShowDialog();
if (password == "")
{
MessageBox.Show("Password Field cannot be blank!!");
goto a;
}
else if (password == null)
{
goto b;
}
int ph = password.GetHashCode();
byte[] ia = BitConverter.GetBytes(ph);
if (BitConverter.IsLittleEndian)
Array.Reverse(ia);
byte[] phb = ia;
UnicodeEncoding UE = new UnicodeEncoding();
byte[] salt = new byte[] { 10, 20, 30, 40, 50, 60, 70, 80 };
Rfc2898DeriveBytes k = new Rfc2898DeriveBytes(password, salt);
string cryptFile = ofile;
FileStream fsCrypt = new FileStream(cryptFile, FileMode.Create);
AesManaged AMCrypto = new AesManaged();
AMCrypto.Key = k.GetBytes(32);
AMCrypto.IV = k.GetBytes(16);
CryptoStream cs = new CryptoStream(fsCrypt, AMCrypto.CreateEncryptor(), CryptoStreamMode.Write);
cs.Write(phb, 0, 4);
FileStream fsIn = new FileStream(ifile, FileMode.Open);
int data;
while ((data = fsIn.ReadByte()) != -1)
cs.WriteByte((byte)data);
fsIn.Close();
cs.Close();
fsCrypt.Close();
File.Delete(ifile);
MessageBox.Show("File Encrypted!!");
b: ;
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
The Prompt is a separate class that I created to generate a dynamic form that asks the user to enter his password. It looks pretty much like any password prompt with two fields to enter and verify the password and a show password checkbox. The ifile is the input file while ofile is the output file.
Update: Here is the code that I tried with backgroundworker. The progress bar seems to work now but the encryption speed is reduced considerably and also the encryption process completes before the progress bar is filled,i.e., the "encryption complete" message shows up before the progress bar has filled. Also when I try to do the same thing for decryption i get an exception saying that the cryptostream does not support seeking. Any ideas?
public Form1()
{
InitializeComponent();
Shown += new EventHandler(Form1_Shown);
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
}
void Form1_Shown(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
try
{
string ifile = #"F:\abc.mp4";
int i = 0;
if (Path.GetExtension(ifile) == ".arv")
{
MessageBox.Show("Error!!File already Encrypted.");
return;
}
string ofile = ifile + ".arv";
a: string password = Prompt.ShowDialog();
if (password == "")
{
MessageBox.Show("Password Field cannot be blank!!");
goto a;
}
else if (password == null)
{
goto b;
}
int ph = password.GetHashCode();
byte[] ia = BitConverter.GetBytes(ph);
if (BitConverter.IsLittleEndian)
Array.Reverse(ia);
byte[] phb = ia;
UnicodeEncoding UE = new UnicodeEncoding();
byte[] salt = new byte[] { 10, 20, 30, 40, 50, 60, 70, 80 };
Rfc2898DeriveBytes k = new Rfc2898DeriveBytes(password, salt);
string cryptFile = ofile;
FileStream fsCrypt = new FileStream(cryptFile, FileMode.Create);
AesManaged AMCrypto = new AesManaged();
AMCrypto.Key = k.GetBytes(32);
AMCrypto.IV = k.GetBytes(16);
CryptoStream cs = new CryptoStream(fsCrypt, AMCrypto.CreateEncryptor(), CryptoStreamMode.Write);
cs.Write(phb, 0, 4);
FileStream fsIn = new FileStream(ifile, FileMode.Open);
int data;
double counter = 1;
while ((data = fsIn.ReadByte()) != -1)
{
cs.WriteByte((byte)data);
backgroundWorker1.ReportProgress((int)((counter / fsIn.Length) * 100));
counter++;
}
fsIn.Close();
cs.Close();
fsCrypt.Close();
File.Delete(ifile);
MessageBox.Show("File Encrypted!!");
b: ;
}
catch (Exception f)
{
MessageBox.Show(f.ToString());
}
Using a BackgroundWorker:
int data;
double counter = 1;
while ((data = fsIn.ReadByte()) != -1)
{
cs.WriteByte((byte)data);
worker.ReportProgress((int)((counter / fs.Length) * 100));
counter++;
}
If you are unsure on how to use a BackgroundWorker:
C# Progress bar - can't wrap my head around it

Error while accessing file C#

I get the Error (IOException) that I don't know where is the error. Here he code:
The constructor:
private const int MAX = 200;
private String path = "\\Registros\\reg";
private FileStream fs;
private BinaryWriter bw = null;
private BinaryReader br = null;
private int N;
private long pos;
public Manejo_Ficheros(String filepath){
this.path = filepath;
if(!File.Exists(path+".dat")){
fs = new FileStream(path + ".dat", FileMode.Create);
this.N = 0;
bw = new BinaryWriter(fs);
fs.Seek(0,SeekOrigin.Begin);
bw.Write(N);
}else{
fs = new FileStream(path + ".dat", FileMode.Open);
br = new BinaryReader(fs);
fs.Seek(0,SeekOrigin.Begin);
this.N = br.ReadInt32();
}
}
Here the Writting:
public void escribirRegistro(Persona p)
{
pos = 4 + this.N * MAX;
int i = (int)pos;
bw = new BinaryWriter(fs);
bw.Seek(i, SeekOrigin.Begin);
bw.Write(p.ID);
bw.Write(p.nombre);
bw.Write(p.apellidos);
bw.Write(p.Num);
bw.Write(p.Nced);
bw.Write(p.pais);
bw.Write(p.observaciones);
bw.Write(p.Anac);
bw.Write(p.tPer);
this.N += 1;
fs.Seek(0, SeekOrigin.Begin);
bw.Write(N);
bw.Close();
fs.Close();
}
As you can see, I am using a flush. It will receive a "Persona" object type and then Writting to a File.
The writting is working fine. But when I want to use the reading method see:
public Persona[] leerTodos()
{
Persona[] p = new Persona[this.N];
br = new BinaryReader(fs);
for (int i = 0; i < p.Length; i++)
{
pos = 4+i*MAX;
br.BaseStream.Seek(pos, SeekOrigin.Begin);
Persona p1 = new Persona();
p1.ID = br.ReadInt32();
p1.nombre = br.ReadString();
p1.apellidos = br.ReadString();
p1.Num = br.ReadString();
p1.Nced = br.ReadString();
p1.pais = br.ReadString();
p1.observaciones = br.ReadString();
p1.Anac = br.ReadInt32();
p1.tPer = br.ReadString();
p[i] = p1;
}
return p;
}
The application breaks in this line fs = new FileStream(path + ".dat", FileMode.Open); The process cannot access the file 'C:\Users\Allan\Desktop\data.dat' because it is being used by another process.
Thing that Writting it does not happen. I dont know what is going wrong.
Try doing this in your code
public Manejo_Ficheros(String filepath){
this.path = filepath;
if(!File.Exists(path+".dat")){
using (fs = new FileStream(path + ".dat", FileMode.Create));
{
this.N = 0;
bw = new BinaryWriter(fs);
fs.Seek(0,SeekOrigin.Begin);
bw.Write(N);
}
}else{
using (fs = new FileStream(path + ".dat", FileMode.Open))
{
br = new BinaryReader(fs);
fs.Seek(0,SeekOrigin.Begin);
this.N = br.ReadInt32();
}
}

Reading Data from Network Stream in TCP Listener

I'm having a network stream which is having filename and filedata in it. I'm sending files in some chunks and each chunk carries the filename for easy identification. Can you please help me in reading the network stream properly and writing all of the data to the file stream.
I seem to miss few bytes when i write the data from network stream.
Say for example filename length will be in oth index and filename will start from 4th index.
Client:
int NoOfPackets = Convert.ToInt32
(Math.Ceiling((Convert.ToDouble(Fs.Length))/ Convert.ToDouble(BufferSize)));
int TotalLength = (NoOfPackets *4+fileNameByte.Length) +(int)Fs.Length, CurrentPacketLength, counter = 0;
netstream1 = client.GetStream();
for (int i = 0; i < NoOfPackets+1 ; i++)
{
if (TotalLength > BufferSize)
{
CurrentPacketLength = BufferSize;
TotalLength = TotalLength - CurrentPacketLength;
}
else
CurrentPacketLength = TotalLength;
SendingBuffer = new byte[CurrentPacketLength];
fileNameLength.CopyTo(SendingBuffer, 0);
fileNameByte.CopyTo(SendingBuffer, 4);
Fs.Read(SendingBuffer, 4 + fileNameByte.Length, CurrentPacketLength - (4 + fileNameByte.Length));
netstream1.Write(SendingBuffer, 0, SendingBuffer.Length);
netstream1.Flush();
}
Listener Code:
client = Listener.AcceptTcpClient();
client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
//client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, true);
client.Client.LingerState = new LingerOption(true, 300);
client.Client.SendTimeout = 300000;
client.Client.ReceiveTimeout = 300000;
client.NoDelay = true;
NetworkStream netstream = client.GetStream();
MemoryStream ms = new MemoryStream();
bool first = true;
string fullPath = "";
byte[] RecData = new byte[512000];
while ((RecBytes = netstream.Read
(RecData, 0, RecData.Length)) > 0)
{
int fileNameLen = RecData[0];
if (fileNameLen > 0 && first)
{
string name1 = "", name2 = "";
first = false;
name1 = Encoding.UTF8.GetString(RecData, 4, fileNameLen);
name2 = name1;
string folderName = "";
if (name2.Contains("\\"))
{
folderName = name2.Substring(0, name2.LastIndexOf("\\"));
if (!Directory.Exists("D:\\123\\" + folderName))
Directory.CreateDirectory("D:\\123\\" + folderName);
}
if (folderName != "")
fullPath = "D:\\123\\" + folderName + "\\" + name2.Substring(name2.LastIndexOf("\\") + 1);
else
fullPath = "D:\\123\\" + name2.Substring(name2.LastIndexOf("\\") + 1);
}
if (!File.Exists(fullPath))
{
//file = new FileStream(fullPath, FileMode.OpenOrCreate, FileAccess.Write);
while (true)
{
try
{
using (FileStream file = new FileStream(fullPath, FileMode.OpenOrCreate, FileAccess.Write))
{
if (RecBytes - (4 + fileNameLen) > 0)
file.Write(RecData, 4 + fileNameLen, RecBytes - (4 + fileNameLen));
break;
}
}
catch (IOException)
{
Thread.Sleep(20);
}
}
//using (file = File.Create(fullPath))
//{
// file.Write(data, 4 + fileNameLen, (int)data.Length - (4 + fileNameLen));
//}
}
else
{
while (true)
{
try
{
using (FileStream file = new FileStream(fullPath, FileMode.Append, FileAccess.Write))
{
if (RecBytes - (4 + fileNameLen) > 0)
file.Write(RecData, 4 + fileNameLen, RecBytes - (4 + fileNameLen));
break;
}
}
catch (IOException)
{
Thread.Sleep(20);
}
}
}
}
ms.Close();
netstream.Close();
client.Close();
even though you are as vague as anyone can be, still I would suggest that you create a structure so that serialization and de-serialization of data could be done in a known format!! and data loss could be avoided!!
Again if your approach is known it would be great help in answering your question.

Sockets in Visual C#. Need Help!

I'm from the Urkraine, and have bad english, but anyway not sure if there is an answer on my question.
I took example from [here][1] but i have exception that GZip magical number is not valid, why ?
public long WriteUrl()
{
long num1 = 0;
bool saveItAtCache = false;
bool existsAtCache = false;
byte[] cachedFile = null;
string ext = Path.GetExtension(_url).ToLower();
if (!_url.Contains(".php") && ".gif.jpg.swf.js.css.png.html".IndexOf(ext) != -1 && ext != "")
{
saveItAtCache = true;
cachedFile = cache.GetFile(_url);
existsAtCache = (cachedFile != null);
}
if (existsAtCache)
{
writeSuccess(cachedFile.Length, null);
socket.Send(cachedFile);
}
string host = new Uri(_url).Host;
IPHostEntry ipAddress = Dns.GetHostEntry(host);
IPEndPoint ip = new IPEndPoint(ipAddress.AddressList[0], 80);
using (Socket s = new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp))
{
s.Connect(ip);
using (NetworkStream n = new NetworkStream(s))
{
if (HttpRequestType == "GET")
{
SendRequest(n, new[] { socketQuery});
}
Dictionary<string, string> headers = new Dictionary<string, string>();
while (true)
{
string line = ReadLine(n);
if (line.Length == 0)
{
break;
}
int index = line.IndexOf(':');
if (!headers.ContainsKey(line.Substring(0, index)))
{
headers.Add(line.Substring(0, index), line.Substring(index + 2));
}
}
string contentEncoding;
if (headers.TryGetValue("Content-Encoding", out contentEncoding))
{
Stream responseStream = n;
if (contentEncoding.Equals("gzip"))
{
responseStream = new GZipStream(responseStream, CompressionMode.Decompress, true);
}
else if (contentEncoding.Equals("deflate"))
{
responseStream = new DeflateStream(responseStream, CompressionMode.Decompress);
}
var memStream = new MemoryStream();
var respBuffer = new byte[4096];
try
{
int bytesRead = responseStream.Read(respBuffer, 0, respBuffer.Length);
//int bytesRead = responseStream.Read(respBuffer, 0, respBuffer.Length);
while (bytesRead > 0)
{
memStream.Write(respBuffer, 0, bytesRead);
bytesRead = responseStream.Read(respBuffer, 0, respBuffer.Length);
}
}
finally
{
responseStream.Close();
}
string str = encoding.GetString(memStream.ToArray());
ManageCookies(headers["Set-Cookie"], _headers["Host"]);
cachedFile = encoding.GetBytes(str);
if (saveItAtCache)
{
cache.Store(_url, cachedFile);
}
writeSuccess(cachedFile.Length, headers["Set-Cookie"]);
socket.Send(cachedFile);
num1 = str.Length;
}
else
{
while (true)
{
string line = ReadLine(n);
if (line == null)
{
break;
}
num1 = line.Length;
}
}
}
}
return num1;
}
In these lines
string str = encoding.GetString(memStream.ToArray());
ManageCookies(headers["Set-Cookie"], _headers["Host"]);
cachedFile = encoding.GetBytes(str);
You're converting the byte array to a string and then back to a byte array. Since the original data is a gzip or jpg or whatever and not really a string, this conversion is probably screwing it up. I don't see you using str at all, so just take it out (use cachedFile.Length when you need the length instead of str.Length).

Categories