0

I'm creating a feature for an app to store a file on a webserver while maintaining data about the file on SQL Server. I generate a SHA256 hash and store it as BINARY(32) and then upload the file to a WebDav server using HTTPClient. Later when I want to view the file in the app, I do a GET request, download the file, and check the SHA256 hash with the stored hash. It doesn't match :( Why?

I've tried checking the hash on the server and the local machine and it doesn't match either. I've done a ton of research and made sure I wasn't hashing the filename (you can see the code below).

public static byte[] GetSHA256(string path) {
    using (var stream = File.OpenRead(path)) {
        using (var sha256 = SHA256.Create()) {
            return sha256.ComputeHash(stream);
        }
   }
}

To Upload a file:

public async Task<bool> Upload(string path, string name) {
    var storedHash = GetSHA256(path/name);
    //Store this hash in a database, omitted for brevity
    using (var file = File.OpenRead(path)) {
        var content = new MultipartFormDataContent();
        content.Headers.ContentType.Media = "multipart/form-data";
        content.Add(new StreamContent(file));
        var result = await HttpClient.PutAsync(uri, content);
  }
}

To download:

var result = await HttpClient.GetAsync(uri);
using (var stream = await result.Content.ReadAsStreamAsync()) {
    var fileInfo = new FileInfo("TestFile");
    using(var fileStream = fileInfo.Open(FileMode.CreateNew, FileAccess.ReadWrite, FileShare.Delete)) {
        await stream.CopyToAsync(fileStream);
    }
}
var downloadedFileHash = GetSHA256("TestFile");

//check if downloadedFileHash matches the storedHash by comparing byte[] length and content with for loop.

I expect that the hash would match. I know I'm missing a few using statements and other code but I omitted a bunch for brevity.

EDIT: The hashes for the downloaded files stay the same so the problem isn't downloading but uploading. I uploaded the same files multiple times but get back different hashes for each one. But the different hashes stay constant.

redcabbage
  • 31
  • 1
  • 4
  • 1
    What if you check basic stuff like byte size? e.g. uploaded/downloaded? it may mean your WebDAV server manipulates the file somehow. – zaitsman Oct 30 '19 at 23:54
  • 2
    It is *very unlikely* that problem has anything to do with SHA256. Could you please clarify if you claim that identical files/byte arrays produce different SHA256 hashes on different machines OR code corrupts file while upload/download? – Alexei Levenkov Oct 30 '19 at 23:56
  • 1
    First try without the upload/download just to see if it matches. Are you getting any exceptions. If the hash isn't valid you should be getting an exception. So my guess is you are generating a new hash instead of using old hash. A bad hash would give an exception. – jdweng Oct 30 '19 at 23:58

1 Answers1

1

Sorry y'all, you can delete this question because I found the problem/answer but am still confused why this is occurring.

Turns out webdav was adding extra headers to my file for some reason, see: Header info being written into file when PUT-ing to a Webdav server

Strangest thing. So I encountered this post. https://blogs.msdn.microsoft.com/robert_mcmurray/2011/10/18/sending-webdav-requests-in-net-revisited/

Rewrote my code to be

public static async Task<HttpResponseMessage> Upload(string path, string name, FileStream file) {
    var method = new HttpMethod(@"PUT");
    var message = new HttpRequestMessage(method, path/name) {
        Content = new StreamContent(file)
    };

    return await HttpClient.SendAsync(message);
}

And it works... But I'm wonder how the two methods of uploading differ.

redcabbage
  • 31
  • 1
  • 4
  • 2
    Nice to hear that you found the answer yourself. Stack Overflow won't punish you for that, so you should consider editing your answer so it can help others who eventually run into the same problem. – Eric Wu Oct 31 '19 at 17:25