Пример #1
0
        public int StoreSnapshot(
            IReadOnlyCollection <Blob> blobs,
            Fuzzy scanFuzzy,
            DateTime creationTimeUtc,
            Func <string, Stream> openRead)
        {
            var newSnapshot = new Snapshot(
                _currentSnapshotId == null
                    ? 0
                    : _currentSnapshotId.Value + 1,
                creationTimeUtc,
                WriteBlobs(blobs, scanFuzzy, openRead));

            using var memoryStream = new MemoryStream(
                      DataConvert.ObjectToBytes(newSnapshot));

            var newSnapshotReference = new SnapshotReference(
                _salt,
                _iterations,
                WriteContent(AesGcmCrypto.GenerateNonce(), memoryStream));

            _intRepository.StoreValue(
                newSnapshot.SnapshotId,
                DataConvert.ObjectToBytes(newSnapshotReference));

            _currentSnapshotId = newSnapshot.SnapshotId;

            _probe.StoredSnapshot(newSnapshot.SnapshotId);

            return(newSnapshot.SnapshotId);
        }
Пример #2
0
        public void RetrieveContent(
            IEnumerable <Uri> contentUris,
            Stream outputStream)
        {
            contentUris.EnsureNotNull(nameof(contentUris));
            outputStream.EnsureNotNull(nameof(outputStream));

            foreach (var contentUri in contentUris)
            {
                try
                {
                    var decrypted = AesGcmCrypto.Decrypt(
                        _uriRepository.RetrieveValue(contentUri),
                        _key.Value);

                    outputStream.Write(decrypted);
                }
                catch (CryptographicException e)
                {
                    throw new ChunkyardException(
                              $"Could not decrypt content: {contentUri}",
                              e);
                }
            }
        }
Пример #3
0
        public SnapshotStore(
            IRepository <Uri> uriRepository,
            IRepository <int> intRepository,
            FastCdc fastCdc,
            string hashAlgorithmName,
            IPrompt prompt,
            IProbe probe,
            int parallelizeChunkThreshold)
        {
            _uriRepository             = uriRepository;
            _intRepository             = intRepository;
            _fastCdc                   = fastCdc;
            _hashAlgorithmName         = hashAlgorithmName;
            _probe                     = probe;
            _parallelizeChunkThreshold = parallelizeChunkThreshold;

            if (parallelizeChunkThreshold <= 0)
            {
                throw new ArgumentException(
                          "Value must be larger than zero",
                          nameof(parallelizeChunkThreshold));
            }

            _currentSnapshotId = FetchCurrentSnapshotId();

            if (_currentSnapshotId == null)
            {
                _salt       = AesGcmCrypto.GenerateSalt();
                _iterations = AesGcmCrypto.Iterations;
            }
            else
            {
                var snapshotReference = GetSnapshotReference(
                    _currentSnapshotId.Value);

                _salt       = snapshotReference.Salt;
                _iterations = snapshotReference.Iterations;
            }

            _key = new Lazy <byte[]>(() =>
            {
                var password = _currentSnapshotId == null
                    ? prompt.NewPassword()
                    : prompt.ExistingPassword();

                return(AesGcmCrypto.PasswordToKey(password, _salt, _iterations));
            });
        }
Пример #4
0
        public static void Encrypt_And_Decrypt_Return_Input()
        {
            var expectedText = "Hello!";
            var key          = AesGcmCrypto.PasswordToKey(
                "secret",
                AesGcmCrypto.GenerateSalt(),
                AesGcmCrypto.Iterations);

            var cipherText = AesGcmCrypto.Encrypt(
                AesGcmCrypto.GenerateNonce(),
                Encoding.UTF8.GetBytes(expectedText),
                key);

            var actualText = Encoding.UTF8.GetString(
                AesGcmCrypto.Decrypt(cipherText, key));

            Assert.Equal(expectedText, actualText);
        }
Пример #5
0
        private BlobReference[] WriteBlobs(
            IReadOnlyCollection <Blob> blobs,
            Fuzzy scanFuzzy,
            Func <string, Stream> openRead)
        {
            var currentBlobReferences = _currentSnapshotId == null
                ? new Dictionary <string, BlobReference>()
                : GetSnapshot(_currentSnapshotId.Value).BlobReferences
                                        .ToDictionary(br => br.Name, br => br);

            return(blobs
                   .AsParallel()
                   .Select(blob =>
            {
                currentBlobReferences.TryGetValue(
                    blob.Name,
                    out var current);

                if (!scanFuzzy.IsMatch(blob.Name) &&
                    current != null &&
                    current.ToBlob().Equals(blob))
                {
                    return current;
                }

                // Known blobs should be encrypted using the same nonce
                var nonce = current?.Nonce
                            ?? AesGcmCrypto.GenerateNonce();

                using var stream = openRead(blob.Name);

                var blobReference = new BlobReference(
                    blob.Name,
                    blob.LastWriteTimeUtc,
                    nonce,
                    WriteContent(nonce, stream));

                _probe.StoredBlob(blobReference);

                return blobReference;
            })
                   .OrderBy(blobReference => blobReference.Name)
                   .ToArray());
        }
Пример #6
0
        private IReadOnlyCollection <Uri> WriteContent(
            byte[] nonce,
            Stream stream)
        {
            Uri WriteChunk(byte[] chunk)
            {
                var encryptedData = AesGcmCrypto.Encrypt(
                    nonce,
                    chunk,
                    _key.Value);

                var contentUri = Id.ComputeContentUri(
                    _hashAlgorithmName,
                    encryptedData);

                _uriRepository.StoreValue(contentUri, encryptedData);

                return(contentUri);
            }

            var expectedChunks = stream.Length / _fastCdc.AvgSize;

            if (expectedChunks < _parallelizeChunkThreshold)
            {
                return(_fastCdc.SplitIntoChunks(stream)
                       .Select(WriteChunk)
                       .ToArray());
            }
            else
            {
                return(_fastCdc.SplitIntoChunks(stream)
                       .AsParallel()
                       .AsOrdered()
                       .Select(WriteChunk)
                       .ToArray());
            }
        }