Exemple #1
0
        /// <summary>
        /// Chunks and saves data to blobstore.
        /// Operates on stream input, so Filestreams can be used and
        /// entire files need not be loaded into memory.
        /// If an error occurs (typically when reading from a stream
        /// representing a file), it is thrown to the caller.
        /// </summary>
        /// <param name="inputstream"></param>
        /// <param name="type"></param>
        /// <param name="filehash"></param>
        /// <param name="hashblobqueue"></param>
        public static void SplitData(Stream inputstream, byte[] filehash, BlockingCollection <HashBlobPair> hashblobqueue)
        {
            // https://rsync.samba.org/tech_report/node3.html
            List <byte> newblob = new();

            byte[] alphachksum    = new byte[2];
            byte[] betachksum     = new byte[2];
            SHA1   sha1filehasher = HashTools.GetSHA1Hasher();
            SHA1   sha1blobhasher = HashTools.GetSHA1Hasher();;

            if (inputstream.Length != 0)
            {
                int    readsize       = 8_388_608;
                int    rollwindowsize = 32;
                byte[] readin;
                byte[] shifted = new byte[2];
                for (int i = 0; i < inputstream.Length; i += readsize) // read the file in larger chunks for efficiency
                {
                    if (i + readsize <= inputstream.Length)            // readsize or more bytes left to read
                    {
                        readin = new byte[readsize];
                        inputstream.Read(readin, 0, readsize);
                    }
                    else // < readsize bytes left to read
                    {
                        readin = new byte[inputstream.Length % readsize];
                        inputstream.Read(readin, 0, (int)(inputstream.Length % readsize));
                    }
                    for (int j = 0; j < readin.Length; j++) // Byte by byte
                    {
                        newblob.Add(readin[j]);
                        HashTools.ByteSum(alphachksum, newblob[^ 1]);
Exemple #2
0
 /// <summary>
 /// Loads the data from a blob, no special handling of multiblob references etc.
 /// </summary>
 /// <param name="blocation"></param>
 /// <param name="hash">Null for no verification</param>
 /// <returns></returns>
 private byte[] LoadBlob(BlobLocation blocation, byte[] hash, int retries = 0)
 {
     byte[] data     = Dependencies.LoadBlob(blocation.EncryptedHash);
     byte[] datahash = HashTools.GetSHA1Hasher().ComputeHash(data);
     if (datahash.SequenceEqual(hash))
     {
         return(data);
     }
     else if (retries > 0)
     {
         return(LoadBlob(blocation, hash, retries - 1));
     }
     // NOTE: This hash check sometimes fails and throws the error, Issue #17
     throw new Exception("Blob data did not match hash.");
 }
Exemple #3
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="file"></param>
        /// <param name="hash"></param>
        /// <param name="data"></param>
        /// <returns>fileId</returns>
        private async Task <(byte[] encryptedHash, string fileId)> StoreFileAsync(string file, byte[] hash, byte[] data, bool preventEncryption = false)
        {
            async Task <GetUploadUrlResponse> GetUploadUrl(int attempts = 0)
            {
                if (AuthResp == null)
                {
                    AuthResp = await AuthorizeAccount();
                }
                Delay();
                try
                {
                    var urlresp = await AuthResp.apiUrl
                                  .AppendPathSegment("/b2api/v1/b2_get_upload_url")
                                  .WithHeaders(new { Authorization = AuthResp.authorizationToken })
                                  .PostJsonAsync(new { bucketId = BucketId })
                                  .ReceiveJson <GetUploadUrlResponse>().ConfigureAwait(false);

                    SuccessfulTransmission();
                    return(urlresp);
                }
                catch (FlurlHttpException ex)
                {
                    if (ex.Call.HttpStatus != null && ex.Call.HttpStatus == System.Net.HttpStatusCode.Unauthorized)
                    {
                        AuthResp = null;
                    }
                    else
                    {
                        // Other classes of errors may be congestion related so we increase the delay
                        FailedTransmission();
                    }
                    if (attempts < Retries)
                    {
                        return(await GetUploadUrl(attempts + 1).ConfigureAwait(false));
                    }
                    throw;
                }
            }

            var hashFileId = await UploadData();

            async Task <(byte[] encryptedHash, string fileId)> UploadData(int attempts = 0)
            {
                if (UploadUrlResp == null)
                {
                    UploadUrlResp = await GetUploadUrl();
                }
                Delay();
                try
                {
                    if (Encryptor != null && !preventEncryption)
                    {
                        data = Encryptor.EncryptBytes(data);
                        hash = HashTools.GetSHA1Hasher().ComputeHash(data);
                    }

                    var filecontent = new ByteArrayContent(data);
                    filecontent.Headers.Add("Content-Type", "application/octet-stream");
                    var uploadresp = await UploadUrlResp.uploadUrl
                                     .WithHeaders(new
                    {
                        Authorization     = UploadUrlResp.authorizationToken,
                        X_Bz_File_Name    = file,
                        Content_Length    = data.Length,
                        X_Bz_Content_Sha1 = HashTools.ByteArrayToHexViaLookup32(hash)
                    })
                                     .PostAsync(filecontent)
                                     .ReceiveJson <UploadResponse>().ConfigureAwait(false);

                    SuccessfulTransmission();
                    return(hash, uploadresp.fileId);
                }
                catch (FlurlHttpException ex)
                {
                    if (ex.Call.HttpStatus != null && ex.Call.HttpStatus == System.Net.HttpStatusCode.Unauthorized)
                    {
                        UploadUrlResp = null;
                    }
                    else
                    {
                        // Other classes of errors may be congestion related so we increase the delay
                        FailedTransmission();
                    }

                    if (attempts < Retries)
                    {
                        return(await UploadData(attempts + 1).ConfigureAwait(false));
                    }
                    throw;
                }
            }

            return(hashFileId);
        }
Exemple #4
0
 private Task StoreFileAsync(string file, byte[] data, bool preventEncryption = false) => StoreFileAsync(file, HashTools.GetSHA1Hasher().ComputeHash(data), data, preventEncryption);
Exemple #5
0
        /// <summary>
        /// Chunks and saves data to blobstore.
        /// Operates on stream input, so Filestreams can be used and
        /// entire files need not be loaded into memory.
        /// If an error occurs (typically when reading from a stream
        /// representing a file), it is thrown to the caller.
        /// </summary>
        /// <param name="inputstream"></param>
        /// <param name="type"></param>
        /// <param name="filehash"></param>
        /// <param name="hashblobqueue"></param>
        public static void SplitData(Stream inputstream, byte[] filehash, BlockingCollection <HashBlobPair> hashblobqueue)
        {
            // https://rsync.samba.org/tech_report/node3.html
            List <byte> newblob = new List <byte>();

            byte[] alphachksum    = new byte[2];
            byte[] betachksum     = new byte[2];
            SHA1   sha1filehasher = HashTools.GetSHA1Hasher();
            SHA1   sha1blobhasher = HashTools.GetSHA1Hasher();;

            if (inputstream.Length != 0)
            {
                int    readsize       = 8_388_608;
                int    rollwindowsize = 32;
                byte[] readin;
                byte[] shifted = new byte[2];
                for (int i = 0; i < inputstream.Length; i += readsize) // read the file in larger chunks for efficiency
                {
                    if (i + readsize <= inputstream.Length)            // readsize or more bytes left to read
                    {
                        readin = new byte[readsize];
                        inputstream.Read(readin, 0, readsize);
                    }
                    else // < readsize bytes left to read
                    {
                        readin = new byte[inputstream.Length % readsize];
                        inputstream.Read(readin, 0, (int)(inputstream.Length % readsize));
                    }
                    for (int j = 0; j < readin.Length; j++) // Byte by byte
                    {
                        newblob.Add(readin[j]);
                        HashTools.ByteSum(alphachksum, newblob[newblob.Count - 1]);
                        if (newblob.Count > rollwindowsize)
                        {
                            HashTools.ByteDifference(alphachksum, newblob[newblob.Count - rollwindowsize - 1]);
                            shifted[0] = (byte)((newblob[newblob.Count - 1] << 5) & 0xFF); // rollwindowsize = 32 = 2^5 => 5
                            shifted[1] = (byte)((newblob[newblob.Count - 1] >> 3) & 0xFF); // 8-5 = 3
                            HashTools.BytesDifference(betachksum, shifted);
                        }
                        HashTools.BytesSum(betachksum, alphachksum);

                        if (alphachksum[0] == 0xFF && betachksum[0] == 0xFF && betachksum[1] < 0x02) // (256*256*128)^-1 => expected value (/2) = ~4MB
                        {
                            byte[] blob = newblob.ToArray();
                            if (i + readsize >= inputstream.Length && j + 1 >= readin.Length) // Need to use TransformFinalBlock if at end of input
                            {
                                sha1filehasher.TransformFinalBlock(blob, 0, blob.Length);
                            }
                            else
                            {
                                sha1filehasher.TransformBlock(blob, 0, blob.Length, blob, 0);
                            }
                            hashblobqueue.Add(new HashBlobPair(sha1blobhasher.ComputeHash(blob), blob));
                            newblob = new List <byte>();
                            Array.Clear(alphachksum, 0, 2);
                            Array.Clear(betachksum, 0, 2);
                        }
                    }
                }
                if (newblob.Count != 0) // Create blob from remaining bytes
                {
                    byte[] blob = newblob.ToArray();
                    sha1filehasher.TransformFinalBlock(blob, 0, blob.Length);
                    hashblobqueue.Add(new HashBlobPair(sha1blobhasher.ComputeHash(blob), blob));
                }
            }
            else
            {
                byte[] blob = new byte[0];
                sha1filehasher.TransformFinalBlock(blob, 0, blob.Length);
                hashblobqueue.Add(new HashBlobPair(sha1blobhasher.ComputeHash(blob), blob));
            }
            Array.Copy(sha1filehasher.Hash, filehash, sha1filehasher.Hash.Length);
            hashblobqueue.CompleteAdding();
        }