How do I compare byte file if exist in database using query? - c#

I want to check if file exist in database or not using asp.net. I searched about that but I didn't find comparing with byte file.
I used Visual Studio 2010, SQL Server 2008 and C# language .
So, I tried to write this code but display error:
Incorrect syntax near 'System.Byte[])'.
Also, is there anther solution about this problem ?
code
if (ext == ".doc" || ext == ".docx" || ext == ".pdf" || ext == ".txt")
{
Stream fs = FileUpload1.PostedFile.InputStream;
BinaryReader br = new BinaryReader(fs);
Byte[] bytes = br.ReadBytes((Int32)fs.Length);
//insert the file into database
strQuery = "insert into [Text File](User_id, T_Title, T_Extension, T_Data, Course_code, Course_num, T_Description, T_Keyword,Date)" +
" values (#User_id, #T_Title, #T_Extension, #T_Data, #Course_code, #Course_num, #T_Description, #T_Keyword, #Date)";
SqlCommand cmd = new SqlCommand(strQuery);
cmd.Parameters.Add("#User_id", (string)Session["ID"]);
cmd.Parameters.Add("#T_Title", SqlDbType.VarChar).Value = filename;
cmd.Parameters.Add("#T_Extension", SqlDbType.VarChar).Value = ext;
cmd.Parameters.Add("#T_Data", SqlDbType.VarBinary).Value = bytes;
strQueryCount = "select count(*) from [Text File] where T_Data.SequenceEqual ('" + bytes + ")'";
cmd.Parameters.Add("#Date", SqlDbType.DateTime).Value = DateTime.Now;
cmd.Parameters.Add("#Course_code", Course_code.SelectedItem.Text);
cmd.Parameters.Add("#Course_num", Course_num.SelectedItem.Text);
cmd.Parameters.Add("#T_Description", Description.Text);
cmd.Parameters.Add("#T_Keyword", keywords.Text);
InsertUpdateData(cmd, bytes, strQueryCount);
}
private Boolean InsertUpdateData(SqlCommand cmd, Byte[] bytes, string strQueryCount)
{
String strConnString = System.Configuration.ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
SqlConnection con = new SqlConnection(strConnString);
cmd.CommandType = CommandType.Text;
cmd.Connection = con;
try
{
con.Open();
command = new SqlCommand(strQueryCount, con);
int num = Convert.ToInt16(command.ExecuteScalar());
Label2.Text = num.ToString();
if (num == 0)
{
cmd.ExecuteNonQuery();
return true;
}
else
{
Label2.ForeColor = System.Drawing.Color.Red;
Label2.Text = "error ";
Description.Text = " ";
keywords.Text = " ";
Course_code.SelectedItem.Text = " ";
Course_num.SelectedItem.Text = " ";
return false;
}
}
catch (Exception ex)
{
Response.Write(ex.Message);
return false;
}
finally
{
con.Close();
con.Dispose();
}
}
Thanks..

You cannot compare files in byte stream as we do on other data types. You can generate some unique values for a file like hash or check-sum and store it along with byte stream in DB, which can be used to check for whether the file exists or not. Normally these mechanisms are not used for this. This only works if file contents are exactly the same. Even the slightest of variation will be failed to identify the match.
OR alternatively, you can decide to store some alternate information like we normally do. Like file name or user-based validations to check whether the file exists.
EDIT:
You can find hash like
string hash;
using(SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider())
{
hash = Convert.ToBase64String(sha1.ComputeHash(byteArray));
}
see it here

I agree, as suggested in above post, you can maintain hash to manage file comparing.
Since you asked how to compare using query, i am adding one more suggestion here.
Write a function in C# to get MD5 hash. Following is the code for function.
public static string GetMD5Hash(string input)
{
System.Security.Cryptography.MD5CryptoServiceProvider x = new System.Security.Cryptography.MD5CryptoServiceProvider();
byte[] bs = System.Text.Encoding.UTF8.GetBytes(input);
bs = x.ComputeHash(bs);
System.Text.StringBuilder s = new System.Text.StringBuilder();
foreach (byte b in bs)
{
s.Append(b.ToString("x2").ToLower());
}
return s.ToString();
}
So get MD5 hash of file, and then using HASHBYTES('MD5', VarbinaryColumn)), you can compare values . This will work,because you will have MD5 hash generated C# and used HASHBYTES in SQL server to compare.
You can also do other type hashing like SHA1 in SQL server as well as C# side.
More on hashbytes - http://codepieces.tumblr.com/post/31006268297/sql-server-hashbytes-function-and-net-hashing-md5
Again, this has same limitation, slight change in content implies mismatch between posted file and stored file in SQL .

Related

Passwords don't get stored properly in SQL Server from C# aplication

I'm having an issue where my hashed passwords are not getting properly stored in SQL Server. The fields for password and salt (saved in base64) are nvarchar(128) and I'm using this function to encode the string (credits to user blowdart for it):
private static byte[] GenerateSaltedHash(byte[] plainText, byte[] salt) {
HashAlgorithm algorithm = new SHA256Managed();
byte[] plainTextWithSaltBytes =
new byte[plainText.Length + salt.Length];
for (int i = 0; i < plainText.Length; i++) {
plainTextWithSaltBytes[i] = plainText[i];
}
for (int i = 0; i < salt.Length; i++) {
plainTextWithSaltBytes[plainText.Length + i] = salt[i];
}
return algorithm.ComputeHash(plainTextWithSaltBytes);
}
I'm creating the byte array using the following method:
Encoding.UTF8.GetBytes(string)
And I'm saving it to the database with this method:
public Boolean CredentialNew(AuthBE authBE) {
con.ConnectionString = conection.GetCon();
cmd.Connection = con;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "PERSONA.CredentialNew";
string HashedPasswordString = Encoding.UTF8.GetString(authBE.HashedPassword);
try {
cmd.Parameters.AddWithValue("#password", HashedPasswordString);
cmd.Parameters.AddWithValue("#salt", authBE.Salt);
con.Open();
cmd.ExecuteNonQuery();
} catch (SqlException x) {
throw new Exception(x.Message);
} finally {
con.Close();
}
return success;
}
After that, this is what appears in my database. The characters appear with squares and often times many?
The problem is authBE.HashedPassword looks like raw byte code, not encoded string. So you should use something else than Encoding.UTF8.GetString(authBE.HashedPassword), f. ex. Convert.ToBase64String(authBE.HashedPassword).

Why I am having connection Issues with some kind of passwords in C# using MD5 hash?

Depending in what kind of password I use to store in the database my program crashes on "Consulta" method when its trying to do Reader.close() inside the first "if".
For example if I set as password "1234" I have no problems, with "prueba" instead the crash happens and it doesnt even go to "catch".
This is the method to save a new user, which is in a button event.
private void bbtnGuardar_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
DB con = new DB(path);
MD5 md5 = MD5.Create();
byte[] hash = md5.ComputeHash(Encoding.Default.GetBytes(tbPassword.Text));
String encryptedPassword = Encoding.Default.GetString(hash);
string query = "INSERT INTO IEM182_LOGIN (USUARIO, PASSWORD) VALUES " +
"('" + tbUsuario.Text + "', '" + encryptedPassword + "');";
try
{
con.Consulta(query);
MessageBox.Show("Nuevo usuario dado de alta correctamente");
limpiar_usuario();
}
catch
{
try
{
con.Cerrar();
query = "SELECT * FROM IEM182_LOGIN WHERE USUARIO = '" + tbUsuario.Text + "'";
con.Consulta(query);
if (con.Reader.Read())
{
MessageBox.Show("El nombre de usuario ya existe");
}
}
catch
{
MessageBox.Show("El usuario contiene caracteres no validos");
}
con.Cerrar();
}
This is the database class with some methods.
class DB
{
private SqlDataReader rdr;
private string path;
private SqlConnection con;
private SqlCommand cmd;
public DB(string cadenaConexion)
{
path = cadenaConexion;
con = new SqlConnection(path);
}
public void Consulta(string query)
{
if (Conexion.State == System.Data.ConnectionState.Open)
{
cmd = new SqlCommand(query, con);
Reader.Close();
Reader = cmd.ExecuteReader();
}
else
{
con.Open();
cmd = new SqlCommand(query, con);
Reader = cmd.ExecuteReader();
}
}
public SqlDataReader Reader
{
get { return rdr; }
set { rdr = value; }
}
public void Cerrar()
{
con.Close();
}
public SqlConnection Conexion
{
get { return con; }
set { con = value; }
}
This is your problem:
byte[] hash = md5.ComputeHash(Encoding.Default.GetBytes(tbPassword.Text));
String encryptedPassword = Encoding.Default.GetString(hash);
There is absolutely no guarantee that the bytes you get back from a hash algorithm forms a legal unicode string, in fact I would say that it is a very slim chance that this will produce usable strings at all. Seems you have found a few odd cases that do. This is just by chance.
You should not pipe those bytes through Encoding.Default.GetString, instead you should use something like Base 64 encoding:
String encryptedPassword = Convert.ToBase64String(bytes);
This will produce a string that doesn't have oddball characters that won't survive a roundtrip through the database.
To get the hash bytes back you decode using the same class:
byte[] hash = Convert.FromBase64String(encryptedPassword);
Now, is this the only problem with your code?
No, it isn't.
The second problem, that coupled with the above one, will throw a spanner into your SQL execution is this:
string query = "INSERT INTO IEM182_LOGIN (USUARIO, PASSWORD) VALUES " +
"('" + tbUsuario.Text + "', '" + encryptedPassword + "');";
You should never form a SQL through string concatenation, you should instead use parameters.
Since you've made a method, Consulta that does this querying, actually modifying your code to use parameters is quite a bit of changes but to execute the above SQL, with parameters, you would do something like this:
string query = "INSERT INTO IEM182_LOGIN (USUARIO, PASSWORD) VALUES " +
"(#username, #password);";
var cmd = new SqlCommand();
cmd.CommandText = query;
cmd.Parameters.AddWithValue("#username", tbUsuario.Text);
cmd.Parameters.AddWithValue("#password", encryptedPassword);
cmd.ExecuteNonQuery();
Exactly how you go about changing your Consultas method to handle this is up to you, but this is the way you must do it!
So to fix the problem I was having I used another encrypting method
// byte array representation of that string
byte[] encodedPassword = new UTF8Encoding().GetBytes(password);
// need MD5 to calculate the hash
byte[] hash = ((HashAlgorithm)CryptoConfig.CreateFromName("MD5")).ComputeHash(encodedPassword);
// string representation (similar to UNIX format)
string encoded = BitConverter.ToString(hash)
// without dashes
.Replace("-", string.Empty)
// make lowercase
.ToLower();
And fixed the first "try/catch" adding another try/catch to call the con.Consulta() method and to catch the invalid characters.
Thanks you very much https://stackoverflow.com/users/267/lasse-v-karlsen

Why Sql Server Image In Binary Causes Issue in string Query but works in Parameterized Query

I am saving Image in a table in VarBinary and its working.but the problem is if i save image using string query when i retrieve it it says parameter not valid although Image binary is save in database and i can see it. but if i use parametrized query and retrieve image it is displayed correctly:
Here is my parametrized query code:
try
{
byte[] byteImg = ImageToByteArray(pictureBox1.Image);
connection = con.getConnection();
if (connection != null)
{
query = #"INSERT INTO [tblImages]
([Image])
VALUES
(#image)";
connection.Open();
cmd = new SqlCommand(query, connection);
cmd.Parameters.AddWithValue("#image", byteImg);
cmd.ExecuteNonQuery();
MessageBox.Show("Saved");
connection.Close();
pictureBox1.Image = null;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
Database Row View Using Parameterized:
Here is my string query code:
try
{
byte[] byteImg = ImageToByteArray(pictureBox1.Image);
connection = con.getConnection();
if (connection != null)
{
query = #"INSERT INTO [tblImages]
([Image])
VALUES
(Convert(varbinary(MAX),'" + byteImg + "'))";
connection.Open();
cmd = new SqlCommand(query, connection);
cmd.ExecuteNonQuery();
MessageBox.Show("Saved");
connection.Close();
pictureBox1.Image = null;
}
}
catch
{
}
Byte Conversion Method:
public byte[] ImageToByteArray(Image img)
{
System.IO.MemoryStream ms = new System.IO.MemoryStream();
img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
return ms.ToArray();
}
Database Row View:
Why is this happening why using Parametrized query binary is different in row and using string query it different, its very weird.
Any help will be appreciated.
You can actually just do:
INSERT INTO [tblImages] ([Image])
VALUES 0x5379......
To build the binary string use code like this (buffer is your byte array)
_sbScript.Append("0x");
for (int i = 0; i < buffer.Length; i++)
{
_sbScript.Append(buffer[i].ToString("X2",System.Globalization.CultureInfo.InvariantCulture));
}
In the hex in the second data snapshot (0x53797374...) all the bytes spell out the type name ("System.Byte[]" maybe? I stopped translating...).
0x53 - 'S'
0x79 - 'y'
0x73 - 's'
0x74 - 't'
0x65 - 'e'
0x6D - 'm'
When you build the string using CONVERT(VARBINARY(MAX), '" + array + "')" the arrays ToString method is being called, which is not well defined on System.Array and returns the name of the type. Then your Sql looks like INSERT INTO ... (CONVERT(VARBINARY(MAX), 'System.Byte[]') and that will be inserted into the database in error.
Choosing the parameterized option would definately be the safer way to go (with respect to both Security, and potential bugs), but if you want to execute it as a SQL string, you will want to build a string of the actual bytes, as demonstrated in ErikEJ's answer.
You have a different INSERT statement in the string query code.
The parametrized query code is:
query = #"INSERT INTO [tblImages]
([Image])
VALUES (#image)";
Whilst the string query code is:
query = #"INSERT INTO [tblImages]
([Image])
VALUES (Convert(varbinary(MAX),'" + byteImg + "'))";
Removing the CONVERT should woudl make the two statements insert in the same way.

Saving and retrving image from mysql

In C#, I am trying to save and load an image. I am saving it into a mysql database (type longblob) and trying to load it back into an picture box. The problem i keep getting is the error "Parameter is not valid", see code below
ConnectionClass Sqlconnection = new ConnectionClass();
Sqlconnection.ConnectionOpen();
OdbcCommand cmd = new OdbcCommand("Insert into pictest(pic) values('"+ Encoding.Unicode.GetBytes(richTextBox1.Rtf) + "')", Sqlconnection.connection);
int num = cmd.ExecuteNonQuery();
MessageBox.Show(num + " Rows inserted ");
Sqlconnection.ConnectionClose();
OdbcDataReader rd = null;
try
{
Sqlconnection.ConnectionOpen();
string query = "select * from pictest where id = 1";
cmd = new OdbcCommand(query, Sqlconnection.connection);
rd = cmd.ExecuteReader();
if (rd.Read())
{
byte[] bytes = (byte[])rd[1];
ImageConverter converter = new ImageConverter();
pictureBox1.Image = Image.FromStream(new MemoryStream(bytes)); <--Parameter is not valid
pictureBox1.Refresh();
pictureBox1.Image = Encoding.Unicode.GetString(bytes);
}
Sqlconnection.ConnectionClose();
rd.Close();
}
catch (Exception asd)
{
MessageBox.Show("Problem " + asd.Message);
Sqlconnection.ConnectionClose();
if (rd != null)
{
rd.Close();
}
}
what exact is the problem? Is the image not saving correctly? it should be as it is saving to a longblob. The record for the image says System.Byte[]
you should be able to inspect (via the debugger) the values inside OdbcDataReader before trying to cast the first field to byte[]. Take a look at what type is actually stored in the OdbcDataReader
Using SELECT * is problematic performance wise. It also leaves your rd[1] up for interpretation. If the order of columns ever changes, your code could break. Use rd["your_column_name"] to access the values. As of right now I can't tell if index 1 is correct due to the SELECT * and non-named indexing into the Items array.
First of all why you need to store image in MySql?
Why not in physical drive? If its not a crucial data go for saving it in physical drive.
However, here is code to retrieve:
public byte [] getImage(int imageNumber)
{
string strSql = "SELECT * FROM File";
DataSet ds = new DataSet("Image");
OdbcDataAdapter tempAP = new OdbcDataAdapter(strSql,this._objConn);
OdbcCommandBuilder objCommand = new OdbcCommandBuilder(tempAP);
tempAP.Fill(ds,"Table");
try
{
this._objConn.Open();
byte [] buffer = (byte [])ds.Tables["Table"].Rows[imageNumber]["Data"];
return buffer;
}
catch{this._objConn.Close();return null;}
finally{this._objConn.Close();}
}
Courtesy:
http://www.codeproject.com/Articles/6750/Storing-Images-in-MySQL-using-ASP-NET
For physical drive
http://www.codeproject.com/Articles/2113/C-Photo-Album-Viewer

string to byte array transformation c#

I asked too many questions today but I have one more question. I'm trying to save an image into my database. I couldn't solve something. When I try to add image, it says paramater string can not be transleted into BYTE[]. Actually I'm giving bytes[] as paramater value.I tried to solve, but I couldn't find any answer maybe you can help me. Here is my code:
Stream fs = FileUpload1.PostedFile.InputStream;
BinaryReader br = new BinaryReader(fs);
Byte[] bytes = br.ReadBytes((Int32)fs.Length);
//insert the file into database
string strQuery = "INSERT INTO Books(Book_Name, Author_Name, Image,In_Lib) VALUES (#BN, #AN, #IM,#LIB)";
SqlCommand cmd = new SqlCommand(strQuery);
string val1 = "" + TextBox1.Text;
string val2 = "" + TextBox2.Text;
cmd.Parameters.Add("#BN", SqlDbType.VarChar).Value = val1;
cmd.Parameters.Add("#AN", SqlDbType.VarChar).Value= val2;
cmd.Parameters.Add("#IM", SqlDbType.Binary).Value = bytes;
cmd.Parameters.Add("#LIB", SqlDbType.Binary).Value = "NO";
InsertUpdateData(cmd);
lblMessage.ForeColor = System.Drawing.Color.Green;
lblMessage.Text = "File Uploaded Successfully";
This line is invalid:
cmd.Parameters.Add("#LIB", SqlDbType.Binary).Value = "NO";
Based on your SQL, it looks like you intended to use a varchar there.
You have passed the string "NO" as a value of the Binary parameter #LIB:
cmd.Parameters.Add("#LIB", SqlDbType.Binary).Value = "NO";
I guess that is your problem.

Categories

Resources