A program in C# which copy a file or whole folders to another folder is made and in that application checksum SHA-512 has been used to verify that input and output of the copy process is/are identical, the program works fine but I need to test the whole program and especially test or verify the checksum. how can I, give the program an input e.g. a file and in the process modify the file somehow in order to see that checksum detect that error? thanks for your suggestions
Here's a simple example of testing the SHA512 hash. Here we have two tests, TestSHA512Modify and TestSHA512Append. One modifies bytes within the file, open appends bytes to the file. Both are useful tests of the Hash.
static void TestSHA512Modify()
{
var testFile = Path.GetTempFileName();
CreateRandomFile(testFile, 1024);
var sha12 = GetFileSHA512(testFile);
Console.WriteLine("TestSHA12Modify: Original file SHA512: " + ToHexString(sha12));
// Modify file bytes. Here we set byte offset [100] [101] [102]
WriteBytes(testFile, 100, new byte[] { 1, 2, 3 });
var modifiedSha12 = GetFileSHA512(testFile);
Console.WriteLine("TestSHA12Modify: Updated file SHA512: " + ToHexString(modifiedSha12));
Console.WriteLine("TestSHA12Modify: SHA12 Hashes are: " + (sha12.SequenceEqual(modifiedSha12) ? "EQUAL" : "NOT EQUAL"));
}
static void TestSHA512Append()
{
var testFile = Path.GetTempFileName();
CreateRandomFile(testFile, 1024);
var sha12 = GetFileSHA512(testFile);
Console.WriteLine("TestSHA12Append: Original file SHA512: " + ToHexString(sha12));
// Append bytes to the end of a file
AppendBytes(testFile, new byte[] { 1 });
var modifiedSha12 = GetFileSHA512(testFile);
Console.WriteLine("TestSHA12Append: Updated file SHA512: " + ToHexString(modifiedSha12));
Console.WriteLine("TestSHA12Append: SHA12 Hashes are: " + (sha12.SequenceEqual(modifiedSha12) ? "EQUAL" : "NOT EQUAL"));
}
static void CreateRandomFile(string path, int length)
{
// Make some random bytes.
var randomData = new byte[1024];
RNGCryptoServiceProvider p = new RNGCryptoServiceProvider();
p.GetBytes(randomData);
File.WriteAllBytes(path, randomData);
}
static void WriteBytes(string path, int fileOffset, byte[] data)
{
using (var fileStream = new FileStream(path, FileMode.Open))
{
fileStream.Seek(fileOffset, SeekOrigin.Begin);
fileStream.Write(data, 0, data.Length);
}
}
static void AppendBytes(string path, byte[] data)
{
using (var fileStream = new FileStream(path, FileMode.Append))
{
fileStream.Write(data, 0, data.Length);
}
}
static byte[] GetFileSHA512(string path)
{
using (SHA512 sha = new SHA512Managed())
{
return sha.ComputeHash(File.ReadAllBytes(path));
}
}
static string ToHexString(byte[] data)
{
return string.Join("", data.Select(b => b.ToString("X2")));
}
Related
I am using .NET 6 , Visual Studio 2022 Preview on Windows 11 pro x64.
using System;
using System.IO;
using System.Security.Cryptography;
public class HMACSHA512example
{
public static void Main(string[] Fileargs)
{
string dataFile;
string signedFile;
//If no file names are specified, create them.
if (Fileargs.Length < 2)
{
dataFile = #"text.txt";
signedFile = "signedFile.enc";
if (!File.Exists(dataFile))
{
// Create a file to write to.
using (StreamWriter sw = File.CreateText(dataFile))
{
sw.WriteLine("Here is a message to sign");
}
}
}
else
{
dataFile = Fileargs[0];
signedFile = Fileargs[1];
}
try
{
// Create a random key using a random number generator. This would be the
// secret key shared by sender and receiver.
byte[] secretkey = new Byte[64];
//RNGCryptoServiceProvider is an implementation of a random number generator.
using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
{
// The array is now filled with cryptographically strong random bytes.
rng.GetBytes(secretkey);
// Use the secret key to sign the message file.
SignFile(secretkey, dataFile, signedFile);
// Verify the signed file
VerifyFile(secretkey, signedFile);
}
}
catch (IOException e)
{
Console.WriteLine("Error: File not found", e);
}
} //end main
// Computes a keyed hash for a source file and creates a target file with the keyed hash
// prepended to the contents of the source file.
public static void SignFile(byte[] key, String sourceFile, String destFile)
{
// Initialize the keyed hash object.
using (HMACSHA512 hmac = new HMACSHA512(key))
{
using (FileStream inStream = new FileStream(sourceFile, FileMode.Open))
{
using (FileStream outStream = new FileStream(destFile, FileMode.Create))
{
// Compute the hash of the input file.
byte[] hashValue = hmac.ComputeHash(inStream);
// Reset inStream to the beginning of the file.
inStream.Position = 0;
// Write the computed hash value to the output file.
outStream.Write(hashValue, 0, hashValue.Length);
// Copy the contents of the sourceFile to the destFile.
int bytesRead;
// read 1K at a time
byte[] buffer = new byte[1024];
do
{
// Read from the wrapping CryptoStream.
bytesRead = inStream.Read(buffer, 0, 1024);
outStream.Write(buffer, 0, bytesRead);
} while (bytesRead > 0);
}
}
}
return;
} // end SignFile
// Compares the key in the source file with a new key created for the data portion of the file. If the keys
// compare the data has not been tampered with.
public static bool VerifyFile(byte[] key, String sourceFile)
{
bool err = false;
// Initialize the keyed hash object.
using (HMACSHA512 hmac = new HMACSHA512(key))
{
// Create an array to hold the keyed hash value read from the file.
byte[] storedHash = new byte[hmac.HashSize / 8];
// Create a FileStream for the source file.
using (FileStream inStream = new FileStream(sourceFile, FileMode.Open))
{
// Read in the storedHash.
inStream.Read(storedHash, 0, storedHash.Length);
// Compute the hash of the remaining contents of the file.
// The stream is properly positioned at the beginning of the content,
// immediately after the stored hash value.
byte[] computedHash = hmac.ComputeHash(inStream);
// compare the computed hash with the stored value
for (int i = 0; i < storedHash.Length; i++)
{
if (computedHash[i] != storedHash[i])
{
err = true;
}
}
}
}
if (err)
{
Console.WriteLine("Hash values differ! Signed file has been tampered with!");
return false;
}
else
{
Console.WriteLine("Hash values agree -- no tampering occurred.");
return true;
}
} //end VerifyFile
} //end class
Source: https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.hmacsha512?view=net-6.0
How to convert this file to top-level statement?
You just have to move your main to the top level, and keep the methods.
using System.Security.Cryptography;
string dataFile;
string signedFile;
//If no file names are specified, create them.
if (args.Length < 2)
{
dataFile = #"text.txt";
signedFile = "signedFile.enc";
if (!File.Exists(dataFile))
{
// Create a file to write to.
using (StreamWriter sw = File.CreateText(dataFile))
{
sw.WriteLine("Here is a message to sign");
}
}
}
else
{
dataFile = args[0];
signedFile = args[1];
}
try
{
// Create a random key using a random number generator. This would be the
// secret key shared by sender and receiver.
byte[] secretkey = new Byte[64];
//RNGCryptoServiceProvider is an implementation of a random number generator.
using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
{
// The array is now filled with cryptographically strong random bytes.
rng.GetBytes(secretkey);
// Use the secret key to sign the message file.
SignFile(secretkey, dataFile, signedFile);
// Verify the signed file
VerifyFile(secretkey, signedFile);
}
}
catch (IOException e)
{
Console.WriteLine("Error: File not found", e);
}
// Computes a keyed hash for a source file and creates a target file with the keyed hash
// prepended to the contents of the source file.
static void SignFile(byte[] key, String sourceFile, String destFile)
{
// Initialize the keyed hash object.
using (HMACSHA512 hmac = new HMACSHA512(key))
{
using (FileStream inStream = new FileStream(sourceFile, FileMode.Open))
{
using (FileStream outStream = new FileStream(destFile, FileMode.Create))
{
// Compute the hash of the input file.
byte[] hashValue = hmac.ComputeHash(inStream);
// Reset inStream to the beginning of the file.
inStream.Position = 0;
// Write the computed hash value to the output file.
outStream.Write(hashValue, 0, hashValue.Length);
// Copy the contents of the sourceFile to the destFile.
int bytesRead;
// read 1K at a time
byte[] buffer = new byte[1024];
do
{
// Read from the wrapping CryptoStream.
bytesRead = inStream.Read(buffer, 0, 1024);
outStream.Write(buffer, 0, bytesRead);
} while (bytesRead > 0);
}
}
}
return;
} // end SignFile
// Compares the key in the source file with a new key created for the data portion of the file. If the keys
// compare the data has not been tampered with.
static bool VerifyFile(byte[] key, String sourceFile)
{
bool err = false;
// Initialize the keyed hash object.
using (HMACSHA512 hmac = new HMACSHA512(key))
{
// Create an array to hold the keyed hash value read from the file.
byte[] storedHash = new byte[hmac.HashSize / 8];
// Create a FileStream for the source file.
using (FileStream inStream = new FileStream(sourceFile, FileMode.Open))
{
// Read in the storedHash.
inStream.Read(storedHash, 0, storedHash.Length);
// Compute the hash of the remaining contents of the file.
// The stream is properly positioned at the beginning of the content,
// immediately after the stored hash value.
byte[] computedHash = hmac.ComputeHash(inStream);
// compare the computed hash with the stored value
for (int i = 0; i < storedHash.Length; i++)
{
if (computedHash[i] != storedHash[i])
{
err = true;
}
}
}
}
if (err)
{
Console.WriteLine("Hash values differ! Signed file has been tampered with!");
return false;
}
else
{
Console.WriteLine("Hash values agree -- no tampering occurred.");
return true;
}
} //end VerifyFile
I have a large file (Source file (assuming 10GB)), that I need to read it by chunks, compress and hash it.
(Finally, we have two outputs: the hash of the file in string format (md5HashHex) and the compressed file in byte format (destData).)
Also before compression, I need to add a header to the destination (destData) and hash it. After that, need to open the source file and read it chunk by chunk, compress and hash each chunk. I found out that my hashing would be different when I read the file chunk by chunk comparing to do the hash in one go. Here is my code, I appreciate if you can help me with that. Also I would like to know if I am doing the compression correctly. Thank you.
public static void CompresingHashing(string inputFile)
{
MD5 md5 = MD5.Create();
int byteCount = 0;
var length = 8192;
var chunk = new byte[length];
byte[] destData;
byte[] compressedData;
byte[] header;
header = Encoding.ASCII.GetBytes("HEADER");
md5.TransformBlock(header, 0, header.Length, null, 0);
destData = AppendingArrays(destData, header); //destination
using (FileStream sourceFile = File.OpenRead(inputFile))
{
while ((byteCount = sourceFile.Read(chunk, 0, length)) > 0)
{
using (var ms = new MemoryStream())
{
using (ZlibStream result = new ZlibStream(ms, CompressionMode.Compress, CompressionLevel.Default)
result.Write(chunk, 0, chunk.Length);
}
compressedData = ms.ToArray();
md5.TransformBlock(compressedData, 0, compressedData.Length, null, 0);
destData = AppendingArrays(destData, compressedData);
}
md5.TransformFinalBlock(chunk, 0, 0);
byte[] md5Hash = md5.Hash;
string md5HashHex = string.Join(string.Empty, md5Hash.Select(b => b.ToString("x2")));
}
Console.WriteLine("Hash : " + hash);
}
public static byte[] AppendingArrays(byte[] existingArray, byte[] ArrayToAdd)
{
byte[] newArray = new byte[existingArray.Length + ArrayToAdd.Length];
existingArray.CopyTo(newArray, 0);
ArrayToAdd.CopyTo(newArray, existingArray.Length);
return newArray;
}
But If I hash destData (which is the source file + the header) I got the different result: (for the sake of space I didn't repeat the code )
.
.
.
destData = AppendingArrays(destData, compressedData);
byte[] md5Hash = md5.ComputeHash(data);
.
.
.
Looks like you are processing the last chunk twice on the md5. Simply call TransformFinalBlock with a byte[0] and length and offset of 0.
I am writing an API that allows users to upload files (image, video, etc). I use a SHA-1 hash to make sure the same file isn't uploaded multiple times. Previously we only allowed smaller files so I was reading them into a byte array and hashing that but now we allow larger files so I am using a file stream. The problem is the SHA-1 algorithm returns a different hash. I need to figure out how to get the same hash regardless of the method, even if I have to turn the byte array into a file stream or something. However, I've tried writing the byte array to a temp file and reading it in and it returns the same hash as the byte array. Here is an example console app that shows what I am doing:
static void Main(string[] args)
{
string file = "C:\\CUWCDFileStorage\\temp\\test.png";
var bytes = File.ReadAllBytes(file);
using (var stream = File.Open(file, FileMode.Open))
{
Console.WriteLine(Sha1HashFile(bytes)); // Returns B7F6D90C30233F91FCEFE05FB49679F8B26C9D80
Console.WriteLine(Sha1HashFile(stream)); // Returns DA39A3EE5E6B4B0D3255BFEF95601890AFD80709
Console.WriteLine(Sha1HashFile2(bytes)); // Returns B7F6D90C30233F91FCEFE05FB49679F8B26C9D80
}
Console.Read();
}
public static string Sha1HashFile(byte[] file)
{
using (SHA1Managed sha1 = new SHA1Managed())
{
return BitConverter.ToString(sha1.ComputeHash(file)).Replace("-", "");
}
}
public static string Sha1HashFile(Stream stream)
{
using (SHA1Managed sha1 = new SHA1Managed())
{
return BitConverter.ToString(sha1.ComputeHash(stream)).Replace("-", "");
}
}
public static string Sha1HashFile2(byte[] bytes)
{
string file = "C:\\CUWCDFileStorage\\temp\\test2.png";
File.WriteAllBytes(file, bytes);
return Sha1HashFile(File.OpenRead(file));
}
I've even tried to just put the byte array into a MemoryStream with new MemoryStream(bytes) but that didn't work either. It seems like once I have the file in a byte array it can't be put back.
EDIT:
I removed some code from my example because I thought MD5 was working. Here is the original code I was using to test:
static void Main(string[] args)
{
string file = "C:\\CUWCDFileStorage\\temp\\test.png";
var bytes = File.ReadAllBytes(file);
using (var stream = File.Open(file, FileMode.Open))
{
Console.WriteLine(Md5HashFile(bytes));
Console.WriteLine(Md5HashFile(stream));
Console.WriteLine(Sha1HashFile(bytes));
Console.WriteLine(Sha1HashFile(stream));
Console.WriteLine(Sha1HashFile2(bytes));
}
Console.Read();
}
public static string Md5HashFile(byte[] file)
{
using (MD5 md5 = MD5.Create())
{
return BitConverter.ToString(md5.ComputeHash(file)).Replace("-", "");
}
}
public static string Sha1HashFile(byte[] file)
{
using (SHA1Managed sha1 = new SHA1Managed())
{
return BitConverter.ToString(sha1.ComputeHash(file)).Replace("-", "");
}
}
public static string Md5HashFile(Stream stream)
{
using (MD5 md5 = MD5.Create())
{
return BitConverter.ToString(md5.ComputeHash(stream)).Replace("-", "");
}
}
public static string Sha1HashFile(Stream stream)
{
using (SHA1Managed sha1 = new SHA1Managed())
{
return BitConverter.ToString(sha1.ComputeHash(stream)).Replace("-", "");
}
}
public static string Sha1HashFile2(byte[] bytes)
{
string file = "C:\\CUWCDFileStorage\\temp\\test2.png";
File.WriteAllBytes(file, bytes);
return Sha1HashFile(File.OpenRead(file));
}
See answer below for explanation of the problem.
The problem is that the stream is being read to the end when hashing the first way. That is causing the second hash to be wrong. Because of that, I need to either reopen a stream for the second hash or rewind the stream to the beginning before hashing the second way. Here is the solution:
static void Main(string[] args)
{
string file = "C:\\CUWCDFileStorage\\temp\\test.png";
var bytes = File.ReadAllBytes(file);
using (var stream = File.Open(file, FileMode.Open))
{
Console.WriteLine(Md5HashFile(bytes));
Console.WriteLine(Md5HashFile(stream));
}
using (var stream = File.Open(file, FileMode.Open))
{
Console.WriteLine(Sha1HashFile(bytes));
Console.WriteLine(Sha1HashFile(stream));
Console.WriteLine(Sha1HashFile2(bytes));
}
Console.Read();
}
public static string Md5HashFile(byte[] file)
{
using (MD5 md5 = MD5.Create())
{
return BitConverter.ToString(md5.ComputeHash(file)).Replace("-", "");
}
}
public static string Sha1HashFile(byte[] file)
{
using (SHA1Managed sha1 = new SHA1Managed())
{
return BitConverter.ToString(sha1.ComputeHash(file)).Replace("-", "");
}
}
public static string Md5HashFile(Stream stream)
{
using (MD5 md5 = MD5.Create())
{
return BitConverter.ToString(md5.ComputeHash(stream)).Replace("-", "");
}
}
public static string Sha1HashFile(Stream stream)
{
using (SHA1Managed sha1 = new SHA1Managed())
{
return BitConverter.ToString(sha1.ComputeHash(stream)).Replace("-", "");
}
}
public static string Sha1HashFile2(byte[] bytes)
{
string file = "C:\\CUWCDFileStorage\\temp\\test2.png";
File.WriteAllBytes(file, bytes);
return Sha1HashFile(File.OpenRead(file));
}
In my project i added a .txt file. I need to get the content inside of it, line after line, and slip the lines. I alreaddy have code to slipt the lines and overall handle the content of the .txt file like i want to, ill i need is to acess the content of the added file.
The code i have to handle the text form a txt file in the computer:
public static string[] loc_file = File.ReadAllLines(AppDomain.CurrentDomain.BaseDirectory + "\\loc.txt", Encoding.UTF8);
public static string loc_up = string.Join("|", loc_file);
public static string[] loc_p = loc_up.Split('|');
public static string[] loc = loc_p.Where((c, i) => i % 2 == 0).ToArray<string>();
public static string[] loc_txt = loc_p.Where((c, i) => i % 2 != 0).ToArray<string>();
now, how i think the code for what i need will be:
public string exePath = Application.StartupPath.ToString() + "\\loc.txt";
Stream stream = GetType().Assembly.GetManifestResourceStream(namexe);
string[] a = GetType().Assembly.GetManifestResourceNames();
byte[] bytes = new byte[(int)stream.Length];
stream.Read(bytes, 0, bytes.Length);
File.WriteAllBytes(exePath, bytes);
and then just read the text from the file.
thanks!
EDIT 1:
im making this code on my own, not sure if it will work but ill post annyways, if it ends out working i might be helping someone:
public bool get_file(string file)
{
string filePath = Application.StartupPath.ToString() + file;
if (File.Exists(filePath))
{
try
{
Stream stream = GetType().Assembly.GetManifestResourceStream(file);
string[] a = GetType().Assembly.GetManifestResourceNames();
byte[] bytes = new byte[(int)stream.Length];
stream.Read(bytes, 0, bytes.Length);
File.WriteAllBytes(filePath, bytes);
return true;
}
catch { return false; }
}
else { return false; }
}
EDIT 2:
I just realized that string filePath = Application.StartupPath.ToString() + file;
if (File.Exists(filePath))
will give me error because there is no file at the strat of the , lets call it cycle. So ill remove the part to see if file exists cause it makes no sence, leaving the code to be:
public bool get_file(string file)
{
string filePath = Application.StartupPath.ToString() + file;
try
{
Stream stream = GetType().Assembly.GetManifestResourceStream(file);
string[] a = GetType().Assembly.GetManifestResourceNames();
byte[] bytes = new byte[(int)stream.Length];
stream.Read(bytes, 0, bytes.Length);
File.WriteAllBytes(filePath, bytes);
return true;
}
catch { return false; }
}
I have a requirement where I need to decrypt large files in memory because these files contain sensitive data (SSNs, DOBs, etc). In other words the decrypted data cannot be at rest (on disk). I was able to use the BouncyCastle API for C# and managed to make it to work for files up to 780 MB. Basically here's the code that works:
string PRIVATE_KEY_FILE_PATH = #"c:\pgp\privatekey.gpg";
string PASSPHRASE = "apassphrase";
string pgpData;
string[] pgpLines;
string pgpFilePath = #"C:\test\test.gpg";
Stream inputStream = File.Open(pgpFilePath, FileMode.Open);
Stream privateKeyStream = File.Open(PRIVATE_KEY_FILE_PATH, FileMode.Open);
string pgpData = CryptoHelper.DecryptPgpData(inputStream, privateKeyStream, PASSPHRASE);
string[] pgpLines = pgpData.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None);
Console.WriteLine(pgpLines.Length);
Console.ReadLine();
foreach (var x in pgpLines)
{
Console.WriteLine(x);
Console.ReadLine();
}
In the above code the entire decrypted data is stored in the pgpData string and that's fine for files up to 780MB as stated previously.
However, I will be getting much larger files and my solution above does not work as I get OutOfMemoryExeception exception.
I've been trying the code below, and I keep getting errors when the DecryptPgpData method below is invoked. When using 512 as the chunksize I get a "Premature end of stream in PartialInputStream" exception. When using 1024 as the chunksize I get a "Exception starting decryption" exception. My question is, is this the correct way to decerypt chunks of data using BouncyCastle? The pgp file I'm trying to decrypt was encrypted using the gpg.exe utility. Any help is much appreciated.....It's been almost two days that I've been trying to make this to work with no success.
string PRIVATE_KEY_FILE_PATH = #"c:\pgp\privatekey.gpg";
string PASSPHRASE = "apassphrase";
string pgpData;
string[] pgpLines;
string pgpFilePath = #"C:\test\test.gpg";
string decryptedData = string.Empty;
FileInfo inFile = new FileInfo(pgpFilePath);
FileStream fs = null;
fs = inFile.OpenRead();
int chunkSize = 1024;
byte[] buffer = new byte[chunkSize];
int totalRead = 0;
while (totalRead < fs.Length)
{
int readBytes = fs.Read(buffer, 0, chunkSize);
totalRead += readBytes;
Stream stream = new MemoryStream(buffer);
decryptedData = CryptoHelper.DecryptPgpData(stream, privateKeyStream, PASSPHRASE);
Console.WriteLine(decryptedData);
}
fs.Close();
Console.WriteLine(totalRead);
Console.ReadLine();