Repository: kopia/kopia
Pull request #978 (2021-04-13 02:18:10)

build(deps): bump @fortawesome/free-regular-svg-icons in /htmlui
Bumps [@fortawesome/free-regular-svg-icons](https://github.com/FortAwesome/Font-Awesome) from 5.15.2 to 5.15.3.
- [Release notes](https://github.com/FortAwesome/Font-Awesome/releases)
- [Changelog](https://github.com/FortAwesome/Font-Awesome/blob/master/CHANGELOG.md)
- [Commits](https://github.com/FortAwesome/Font-Awesome/compare/5.15.2...5.15.3)

Signed-off-by: dependabot[bot] <support@github.com>

codecov[bot]: # [Codecov](https://codecov.io/gh/kopia/kopia/pull/978?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kopia) Report
> Merging [#978](https://codecov.io/gh/kopia/kopia/pull/978?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kopia) (957f86b) into [master](https://codecov.io/gh/kopia/kopia/commit/667d171714af1686a2600e4041a011dbddf4d15c?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kopia) (667d171) will **decrease** coverage by `0.02%`.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/kopia/kopia/pull/978/graphs/tree.svg?width=650&height=150&src=pr&token=CRK4RMRFSH&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kopia)](https://codecov.io/gh/kopia/kopia/pull/978?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kopia)

```diff
@@            Coverage Diff             @@
##           master     #978      +/-   ##
==========================================
- Coverage   62.30%   62.28%   -0.03%     
==========================================
  Files         136      136              
  Lines        7519     7519              
==========================================
- Hits         4685     4683       -2     
- Misses       2186     2187       +1     
- Partials      648      649       +1     
```


| [Impacted Files](https://codecov.io/gh/kopia/kopia/pull/978?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kopia) | Coverage Δ | |
|---|---|---|
| [repo/blob/storage.go](https://codecov.io/gh/kopia/kopia/pull/978/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kopia#diff-cmVwby9ibG9iL3N0b3JhZ2UuZ28=) | `60.52% <0.00%> (-5.27%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/kopia/kopia/pull/978?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kopia).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kopia)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/kopia/kopia/pull/978?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kopia). Last update [667d171...957f86b](https://codecov.io/gh/kopia/kopia/pull/978?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kopia). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kopia).


Patch:
diff --git a/.goreleaser.yml b/.goreleaser.yml
index fb042d87..9669bfa9 100644
--- a/.goreleaser.yml
+++ b/.goreleaser.yml
@@ -8,6 +8,7 @@ builds:
   - CGO_ENABLED=0
   goos:
   - linux
+  - freebsd
   goarch:
     - amd64
     - arm
@@ -24,6 +25,7 @@ archives:
       darwin: macOS
       linux: linux
       windows: windows
+      freebsd: freebsd-experimental
       amd64: x64
     name_template: "{{ .ProjectName }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}"
     wrap_in_directory: true
diff --git a/app/package-lock.json b/app/package-lock.json
index 6f036e7d..016a1b00 100644
--- a/app/package-lock.json
+++ b/app/package-lock.json
@@ -17987,9 +17987,9 @@
       "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
     },
     "uuid": {
-      "version": "7.0.3",
-      "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz",
-      "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg=="
+      "version": "8.3.2",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+      "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
     },
     "v8-compile-cache": {
       "version": "2.3.0",
diff --git a/app/package.json b/app/package.json
index 893b14bf..903ad0eb 100644
--- a/app/package.json
+++ b/app/package.json
@@ -15,7 +15,7 @@
     "react-dom": "^17.0.2",
     "react-router-dom": "^5.2.0",
     "react-scripts": "^4.0.3",
-    "uuid": "^7.0.3"
+    "uuid": "^8.3.2"
   },
   "author": {
     "email": "kopia-pmc@googlegroups.com",
diff --git a/cli/app.go b/cli/app.go
index 0e8eedab..6077486e 100644
--- a/cli/app.go
+++ b/cli/app.go
@@ -190,7 +190,7 @@ func maybeRepositoryAction(act func(ctx context.Context, rep repo.Repository) er
 				go http.ListenAndServe(*metricsListenAddr, mux) // nolint:errcheck
 			}
 
-			rep, err := openRepository(ctx, nil, mode.mustBeConnected)
+			rep, err := openRepository(ctx, mode.mustBeConnected)
 			if err != nil && mode.mustBeConnected {
 				return errors.Wrap(err, "open repository")
 			}
diff --git a/cli/command_maintenance_info.go b/cli/command_maintenance_info.go
index 4d8f858f..0c95d699 100644
--- a/cli/command_maintenance_info.go
+++ b/cli/command_maintenance_info.go
@@ -42,7 +42,7 @@ func runMaintenanceInfoCommand(ctx context.Context, rep repo.DirectRepository) e
 		printStdout("  %v:\n", run)
 
 		for _, t := range timings {
-			errInfo := ""
+			var errInfo string
 			if t.Success {
 				errInfo = "SUCCESS"
 			} else {
diff --git a/cli/command_repository_create.go b/cli/command_repository_create.go
index b1aee3a9..1b78d0c6 100644
--- a/cli/command_repository_create.go
+++ b/cli/command_repository_create.go
@@ -91,7 +91,7 @@ func runCreateCommandWithStorage(ctx context.Context, st blob.Storage) error {
 }
 
 func populateRepository(ctx context.Context, password string) error {
-	rep, err := repo.Open(ctx, repositoryConfigFileName(), password, applyOptionsFromFlags(ctx, nil))
+	rep, err := repo.Open(ctx, repositoryConfigFileName(), password, optionsFromFlags(ctx))
 	if err != nil {
 		return errors.Wrap(err, "unable to open repository")
 	}
diff --git a/cli/command_snapshot_migrate.go b/cli/command_snapshot_migrate.go
index 5ae224b2..7fa69b88 100644
--- a/cli/command_snapshot_migrate.go
+++ b/cli/command_snapshot_migrate.go
@@ -122,7 +122,7 @@ func openSourceRepo(ctx context.Context) (repo.Repository, error) {
 		}
 	}
 
-	sourceRepo, err := repo.Open(ctx, *migrateSourceConfig, pass, applyOptionsFromFlags(ctx, nil))
+	sourceRepo, err := repo.Open(ctx, *migrateSourceConfig, pass, optionsFromFlags(ctx))
 	if err != nil {
 		return nil, errors.Wrap(err, "can't open source repository")
 	}
diff --git a/cli/config.go b/cli/config.go
index d0976408..b6b9388f 100644
--- a/cli/config.go
+++ b/cli/config.go
@@ -59,7 +59,7 @@ func onCtrlC(f func()) {
 	}()
 }
 
-func openRepository(ctx context.Context, opts *repo.Options, required bool) (repo.Repository, error) {
+func openRepository(ctx context.Context, required bool) (repo.Repository, error) {
 	if _, err := os.Stat(repositoryConfigFileName()); os.IsNotExist(err) {
 		if !required {
 			return nil, nil
@@ -75,7 +75,7 @@ func openRepository(ctx context.Context, opts *repo.Options, required bool) (rep
 		return nil, errors.Wrap(err, "get password")
 	}
 
-	r, err := repo.Open(ctx, repositoryConfigFileName(), pass, applyOptionsFromFlags(ctx, opts))
+	r, err := repo.Open(ctx, repositoryConfigFileName(), pass, optionsFromFlags(ctx))
 	if os.IsNotExist(err) {
 		return nil, errors.New("not connected to a repository, use 'kopia connect'")
 	}
@@ -83,16 +83,14 @@ func openRepository(ctx context.Context, opts *repo.Options, required bool) (rep
 	return r, errors.Wrap(err, "unable to open repository")
 }
 
-func applyOptionsFromFlags(ctx context.Context, opts *repo.Options) *repo.Options {
-	if opts == nil {
-		opts = &repo.Options{}
-	}
+func optionsFromFlags(ctx context.Context) *repo.Options {
+	var opts repo.Options
 
 	if *traceStorage {
 		opts.TraceStorage = log(ctx).Debugf
 	}
 
-	return opts
+	return &opts
 }
 
 func repositoryConfigFileName() string {
diff --git a/cli/storage_providers.go b/cli/storage_providers.go
index 0919c8cf..524582da 100644
--- a/cli/storage_providers.go
+++ b/cli/storage_providers.go
@@ -68,7 +68,7 @@ func RegisterStorageConnectFlags(
 			return errors.Wrap(err, "can't connect to storage")
 		}
 
-		rep, err := openRepository(ctx, nil, true)
+		rep, err := openRepository(ctx, true)
 		if err != nil {
 			return errors.Wrap(err, "open repository")
 		}
diff --git a/go.mod b/go.mod
index 65eaef9c..decd1889 100644
--- a/go.mod
+++ b/go.mod
@@ -63,7 +63,7 @@ require (
 	golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57
 	golang.org/x/term v0.0.0-20210317153231-de623e64d2a6
 	google.golang.org/api v0.44.0
-	google.golang.org/grpc v1.36.1
+	google.golang.org/grpc v1.37.0
 	google.golang.org/protobuf v1.26.0
 	gopkg.in/ini.v1 v1.62.0 // indirect
 	gopkg.in/kothar/go-backblaze.v0 v0.0.0-20210124194846-35409b867216
diff --git a/go.sum b/go.sum
index bf3272a6..e3da4c5e 100644
--- a/go.sum
+++ b/go.sum
@@ -223,6 +223,7 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
 github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
 github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
 github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
@@ -1225,8 +1226,9 @@ google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv
 google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
 google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
 google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.36.1 h1:cmUfbeGKnz9+2DD/UYsMQXeqbHZqZDs4eQwW0sFOpBY=
 google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.37.0 h1:uSZWeQJX5j11bIQ4AJoj+McDBo29cY1MCoC1wO3ts+c=
+google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
 google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
diff --git a/internal/cache/storage_protection.go b/internal/cache/storage_protection.go
index caf589df..bd6fd32b 100644
--- a/internal/cache/storage_protection.go
+++ b/internal/cache/storage_protection.go
@@ -102,9 +102,5 @@ func AuthenticatedEncryptionProtection(key []byte) (StorageProtection, error) {
 		return nil, errors.Wrap(err, "unable to create encryptor")
 	}
 
-	if !e.IsAuthenticated() {
-		return nil, errors.Wrap(err, "encryption is not authenticated!")
-	}
-
 	return authenticatedEncryptionProtection{e}, nil
 }
diff --git a/internal/mount/mount_fuse.go b/internal/mount/mount_fuse.go
index a69e7eb0..839c5438 100644
--- a/internal/mount/mount_fuse.go
+++ b/internal/mount/mount_fuse.go
@@ -1,4 +1,4 @@
-// +build !windows
+// +build !windows,!freebsd
 
 package mount
 
diff --git a/internal/mount/mount_posix_webdav_helper.go b/internal/mount/mount_posix_webdav_helper.go
index 9af9c05d..9d4ac777 100644
--- a/internal/mount/mount_posix_webdav_helper.go
+++ b/internal/mount/mount_posix_webdav_helper.go
@@ -1,4 +1,4 @@
-// +build !windows
+// +build !windows,!freebsd
 
 package mount
 
diff --git a/internal/mount/mount_unsupported.go b/internal/mount/mount_unsupported.go
new file mode 100644
index 00000000..6374e5d9
--- /dev/null
+++ b/internal/mount/mount_unsupported.go
@@ -0,0 +1,16 @@
+// +build freebsd
+
+package mount
+
+import (
+	"context"
+
+	"github.com/pkg/errors"
+
+	"github.com/kopia/kopia/fs"
+)
+
+// Directory returns an error due to mounting being unsupported on current operating system.
+func Directory(ctx context.Context, entry fs.Directory, mountPoint string, mountOptions Options) (Controller, error) {
+	return nil, errors.Errorf("mounting is not supported")
+}
diff --git a/repo/blob/providers/providers.go b/repo/blob/providers/providers.go
deleted file mode 100644
index f83710c8..00000000
--- a/repo/blob/providers/providers.go
+++ /dev/null
@@ -1,9 +0,0 @@
-// Package providers registers all storage providers that are included as part of Kopia.
-package providers
-
-import (
-
-	// Register well-known blob storage providers.
-	_ "github.com/kopia/kopia/repo/blob/filesystem"
-	_ "github.com/kopia/kopia/repo/blob/gcs"
-)
diff --git a/repo/blob/s3/s3_storage.go b/repo/blob/s3/s3_storage.go
index c74da82a..71f69b3e 100644
--- a/repo/blob/s3/s3_storage.go
+++ b/repo/blob/s3/s3_storage.go
@@ -150,7 +150,7 @@ func (s *s3Storage) DeleteBlob(ctx context.Context, b blob.ID) error {
 		return nil
 	}
 
-	return translateError(err)
+	return err
 }
 
 func (s *s3Storage) getObjectNameString(b blob.ID) string {
diff --git a/repo/content/committed_read_manager.go b/repo/content/committed_read_manager.go
index 0f3cf4ca..36252e3c 100644
--- a/repo/content/committed_read_manager.go
+++ b/repo/content/committed_read_manager.go
@@ -1,9 +1,7 @@
 package content
 
 import (
-	"bytes"
 	"context"
-	"crypto/aes"
 	"os"
 	"sync"
 	"sync/atomic"
@@ -230,19 +228,15 @@ func (sm *SharedManager) decryptContentAndVerify(payload []byte, bi *Info) ([]by
 func (sm *SharedManager) decryptAndVerify(encrypted, iv []byte) ([]byte, error) {
 	decrypted, err := sm.encryptor.Decrypt(nil, encrypted, iv)
 	if err != nil {
+		sm.Stats.foundInvalidContent()
 		return nil, errors.Wrap(err, "decrypt")
 	}
 
+	sm.Stats.foundValidContent()
 	sm.Stats.decrypted(len(decrypted))
 
-	if sm.encryptor.IsAuthenticated() {
-		// already verified
-		return decrypted, nil
-	}
-
-	// Since the encryption key is a function of data, we must be able to generate exactly the same key
-	// after decrypting the content. This serves as a checksum.
-	return decrypted, sm.verifyChecksum(decrypted, iv)
+	// already verified
+	return decrypted, nil
 }
 
 // IndexBlobs returns the list of active index blobs.
@@ -250,22 +244,6 @@ func (sm *SharedManager) IndexBlobs(ctx context.Context, includeInactive bool) (
 	return sm.indexBlobManager.listIndexBlobs(ctx, includeInactive)
 }
 
-func (sm *SharedManager) verifyChecksum(data, contentID []byte) error {
-	var hashOutput [maxHashSize]byte
-
-	expected := sm.hasher(hashOutput[:0], data)
-	expected = expected[len(expected)-aes.BlockSize:]
-
-	if !bytes.HasSuffix(contentID, expected) {
-		sm.Stats.foundInvalidContent()
-		return errors.Errorf("invalid checksum for blob %x, expected %x", contentID, expected)
-	}
-
-	sm.Stats.foundValidContent()
-
-	return nil
-}
-
 func (sm *SharedManager) setupReadManagerCaches(ctx context.Context, caching *CachingOptions) error {
 	dataCacheStorage, err := cache.NewStorageOrNil(ctx, caching.CacheDirectory, caching.MaxCacheSizeBytes, "contents")
 	if err != nil {
@@ -389,7 +367,7 @@ func NewSharedManager(ctx context.Context, st blob.Storage, f *FormattingOptions
 		repositoryFormatBytes:   opts.RepositoryFormatBytes,
 		checkInvariantsOnUnlock: os.Getenv("KOPIA_VERIFY_INVARIANTS") != "",
 		writeFormatVersion:      int32(f.Version),
-		encryptionBufferPool:    buf.NewPool(ctx, defaultEncryptionBufferPoolSegmentSize+encryptor.MaxOverhead(), "content-manager-encryption"),
+		encryptionBufferPool:    buf.NewPool(ctx, defaultEncryptionBufferPoolSegmentSize+encryptor.Overhead(), "content-manager-encryption"),
 	}
 
 	caching = caching.CloneOrDefault()
diff --git a/repo/content/content_manager_lock_free.go b/repo/content/content_manager_lock_free.go
index ac4f7f27..a7d8580c 100644
--- a/repo/content/content_manager_lock_free.go
+++ b/repo/content/content_manager_lock_free.go
@@ -25,7 +25,7 @@ func (sm *SharedManager) maybeEncryptContentDataForPacking(output *gather.WriteB
 		return errors.Wrapf(err, "unable to get packed content IV for %q", contentID)
 	}
 
-	b := sm.encryptionBufferPool.Allocate(len(data) + sm.encryptor.MaxOverhead())
+	b := sm.encryptionBufferPool.Allocate(len(data) + sm.encryptor.Overhead())
 	defer b.Release()
 
 	cipherText, err := sm.encryptor.Encrypt(b.Data[:0], data, iv)
diff --git a/repo/encryption/aes256_gcm_hmac_sha256_encryptor.go b/repo/encryption/aes256_gcm_hmac_sha256_encryptor.go
index 55644fea..f41a9113 100644
--- a/repo/encryption/aes256_gcm_hmac_sha256_encryptor.go
+++ b/repo/encryption/aes256_gcm_hmac_sha256_encryptor.go
@@ -56,15 +56,7 @@ func (e aes256GCMHmacSha256) Encrypt(output, input, contentID []byte) ([]byte, e
 	return aeadSealWithRandomNonce(output, a, input, contentID)
 }
 
-func (e aes256GCMHmacSha256) IsAuthenticated() bool {
-	return true
-}
-
-func (e aes256GCMHmacSha256) IsDeprecated() bool {
-	return false
-}
-
-func (e aes256GCMHmacSha256) MaxOverhead() int {
+func (e aes256GCMHmacSha256) Overhead() int {
 	return aes256GCMHmacSha256Overhead
 }
 
diff --git a/repo/encryption/chacha20_poly1305_hmac_sha256_encryptor.go b/repo/encryption/chacha20_poly1305_hmac_sha256_encryptor.go
index a590ddcd..8e228aeb 100644
--- a/repo/encryption/chacha20_poly1305_hmac_sha256_encryptor.go
+++ b/repo/encryption/chacha20_poly1305_hmac_sha256_encryptor.go
@@ -52,15 +52,7 @@ func (e chacha20poly1305hmacSha256Encryptor) Encrypt(output, input, contentID []
 	return aeadSealWithRandomNonce(output, a, input, contentID)
 }
 
-func (e chacha20poly1305hmacSha256Encryptor) IsAuthenticated() bool {
-	return true
-}
-
-func (e chacha20poly1305hmacSha256Encryptor) IsDeprecated() bool {
-	return false
-}
-
-func (e chacha20poly1305hmacSha256Encryptor) MaxOverhead() int {
+func (e chacha20poly1305hmacSha256Encryptor) Overhead() int {
 	return chacha20poly1305hmacSha256EncryptorOverhead
 }
 
diff --git a/repo/encryption/deprecated_ctr_encryptor.go b/repo/encryption/deprecated_ctr_encryptor.go
deleted file mode 100644
index a2afef26..00000000
--- a/repo/encryption/deprecated_ctr_encryptor.go
+++ /dev/null
@@ -1,91 +0,0 @@
-package encryption
-
-import (
-	"crypto/aes"
-	"crypto/cipher"
-
-	"github.com/pkg/errors"
-)
-
-const (
-	aes128KeyLength = 16
-	aes192KeyLength = 24
-	aes256KeyLength = 32
-)
-
-// ctrEncryptor implements encrypted format which uses CTR mode of a content cipher with nonce==IV.
-type ctrEncryptor struct {
-	createCipher func() (cipher.Block, error)
-}
-
-func (fi ctrEncryptor) Encrypt(output, plainText, contentID []byte) ([]byte, error) {
-	return symmetricEncrypt(output, fi.createCipher, contentID, plainText)
-}
-
-func (fi ctrEncryptor) Decrypt(output, cipherText, contentID []byte) ([]byte, error) {
-	return symmetricEncrypt(output, fi.createCipher, contentID, cipherText)
-}
-
-func (fi ctrEncryptor) IsAuthenticated() bool {
-	return false
-}
-
-func (fi ctrEncryptor) IsDeprecated() bool {
-	return true
-}
-
-func (fi ctrEncryptor) MaxOverhead() int {
-	return 0
-}
-
-func symmetricEncrypt(output []byte, createCipher func() (cipher.Block, error), iv, b []byte) ([]byte, error) {
-	blockCipher, err := createCipher()
-	if err != nil {
-		return nil, err
-	}
-
-	if len(iv) < blockCipher.BlockSize() {
-		return nil, errors.Errorf("IV too short: %v expected >= %v", len(iv), blockCipher.BlockSize())
-	}
-
-	ctr := cipher.NewCTR(blockCipher, iv[0:blockCipher.BlockSize()])
-
-	result, out := sliceForAppend(output, len(b))
-	ctr.XORKeyStream(out, b)
-
-	return result, nil
-}
-
-func adjustKey(masterKey []byte, desiredKeySize int) ([]byte, error) {
-	if len(masterKey) == desiredKeySize {
-		return masterKey, nil
-	}
-
-	if desiredKeySize < len(masterKey) {
-		return masterKey[0:desiredKeySize], nil
-	}
-
-	return nil, errors.Errorf("required key too long %v, but only have %v", desiredKeySize, len(masterKey))
-}
-
-// newCTREncryptorFactory returns new EncryptorFactory that uses CTR with symmetric encryption (such as AES) and a given key size.
-func newCTREncryptorFactory(keySize int, createCipherWithKey func(key []byte) (cipher.Block, error)) EncryptorFactory {
-	return func(o Parameters) (Encryptor, error) {
-		key, err := adjustKey(o.GetMasterKey(), keySize)
-		if err != nil {
-			return nil, errors.Wrap(err, "unable to get encryption key")
-		}
-
-		return ctrEncryptor{
-			createCipher: func() (cipher.Block, error) {
-				return createCipherWithKey(key)
-			},
-		}, nil
-	}
-}
-
-func init() {
-	Register("AES-128-CTR", "DEPRECATED: AES-128 in CTR mode", true, newCTREncryptorFactory(aes128KeyLength, aes.NewCipher))
-	Register("AES-192-CTR", "DEPRECATED: AES-192 in CTR mode", true, newCTREncryptorFactory(aes192KeyLength, aes.NewCipher))
-	Register("AES-256-CTR", "DEPRECATED: AES-256 in CTR mode", true, newCTREncryptorFactory(aes256KeyLength, aes.NewCipher))
-}
diff --git a/repo/encryption/deprecated_salsa_encryptor.go b/repo/encryption/deprecated_salsa_encryptor.go
deleted file mode 100644
index c2394278..00000000
--- a/repo/encryption/deprecated_salsa_encryptor.go
+++ /dev/null
@@ -1,100 +0,0 @@
-package encryption
-
-import (
-	"crypto/sha256"
-
-	"github.com/pkg/errors"
-	"golang.org/x/crypto/salsa20"
-
-	"github.com/kopia/kopia/internal/hmac"
-)
-
-const (
-	purposeEncryptionKey = "encryption"
-	purposeHMACSecret    = "hmac"
-	hmacLength           = 32
-	salsaKeyLength       = 32
-)
-
-type salsaEncryptor struct {
-	nonceSize  int
-	key        *[32]byte
-	hmacSecret []byte
-}
-
-func (s salsaEncryptor) Decrypt(output, input, contentID []byte) ([]byte, error) {
-	if s.hmacSecret != nil {
-		var err error
-
-		input, err = hmac.VerifyAndStrip(input, s.hmacSecret)
-		if err != nil {
-			return nil, errors.Wrap(err, "hmac.VerifyAndStrip")
-		}
-	}
-
-	return s.encryptDecrypt(output, input, contentID)
-}
-
-func (s salsaEncryptor) Encrypt(output, input, contentID []byte) ([]byte, error) {
-	v, err := s.encryptDecrypt(output, input, contentID)
-	if err != nil {
-		return nil, errors.Wrap(err, "decrypt")
-	}
-
-	if s.hmacSecret == nil {
-		return v, nil
-	}
-
-	return hmac.Append(v, s.hmacSecret), nil
-}
-
-func (s salsaEncryptor) IsAuthenticated() bool {
-	return s.hmacSecret != nil
-}
-
-func (s salsaEncryptor) MaxOverhead() int {
-	if s.hmacSecret == nil {
-		return 0
-	}
-
-	return sha256.Size
-}
-
-func (s salsaEncryptor) encryptDecrypt(output, input, contentID []byte) ([]byte, error) {
-	if len(contentID) < s.nonceSize {
-		return nil, errors.Errorf("hash too short, expected >=%v bytes, got %v", s.nonceSize, len(contentID))
-	}
-
-	result, out := sliceForAppend(output, len(input))
-	nonce := contentID[0:s.nonceSize]
-	salsa20.XORKeyStream(out, input, nonce, s.key)
-
-	return result, nil
-}
-
-func (s salsaEncryptor) IsDeprecated() bool {
-	return true
-}
-
-func init() {
-	Register("SALSA20", "DEPRECATED: SALSA20 using shared key and 64-bit nonce", true, func(p Parameters) (Encryptor, error) {
-		var k [salsaKeyLength]byte
-		copy(k[:], p.GetMasterKey()[0:salsaKeyLength])
-		return salsaEncryptor{8, &k, nil}, nil
-	})
-
-	Register("SALSA20-HMAC", "DEPRECATED: SALSA20 with HMAC-SHA256 using shared key and 64-bit nonce", true, func(p Parameters) (Encryptor, error) {
-		encryptionKey, err := deriveKey(p, []byte(purposeEncryptionKey), salsaKeyLength)
-		if err != nil {
-			return nil, err
-		}
-		hmacSecret, err := deriveKey(p, []byte(purposeHMACSecret), hmacLength)
-		if err != nil {
-			return nil, err
-		}
-
-		var k [salsaKeyLength]byte
-		copy(k[:], encryptionKey)
-		return salsaEncryptor{8, &k, hmacSecret}, nil
-	})
-}
diff --git a/repo/encryption/encryption.go b/repo/encryption/encryption.go
index 299a68e1..027cb3ac 100644
--- a/repo/encryption/encryption.go
+++ b/repo/encryption/encryption.go
@@ -10,7 +10,11 @@
 	"golang.org/x/crypto/hkdf"
 )
 
-const minDerivedKeyLength = 32
+const (
+	minDerivedKeyLength = 32
+
+	purposeEncryptionKey = "encryption"
+)
 
 // Encryptor performs encryption and decryption of contents of data.
 type Encryptor interface {
@@ -23,15 +27,8 @@ type Encryptor interface {
 	// authenticity check before decrypting.
 	Decrypt(output, cipherText, contentID []byte) ([]byte, error)
 
-	// IsAuthenticated returns true if encryption is authenticated.
-	// In this case Decrypt() is expected to perform authenticity check.
-	IsAuthenticated() bool
-
-	// IsDeprecated returns true if encryption is not recommended for new repositories.
-	IsDeprecated() bool
-
-	// MaxOverhead is the maximum number of bytes of overhead added by Encrypt()
-	MaxOverhead() int
+	// Overhead is the number of bytes of overhead added by Encrypt()
+	Overhead() int
 }
 
 // Parameters encapsulates all encryption parameters.
@@ -56,9 +53,6 @@ func CreateEncryptor(p Parameters) (Encryptor, error) {
 // DefaultAlgorithm is the name of the default encryption algorithm.
 const DefaultAlgorithm = "AES256-GCM-HMAC-SHA256"
 
-// DeprecatedNoneAlgorithm is the name of the algorithm that does not encrypt.
-const DeprecatedNoneAlgorithm = "NONE"
-
 // SupportedAlgorithms returns the names of the supported encryption
 // methods.
 func SupportedAlgorithms(includeDeprecated bool) []string {
@@ -95,7 +89,6 @@ type encryptorInfo struct {
 var encryptors = map[string]*encryptorInfo{}
 
 // deriveKey uses HKDF to derive a key of a given length and a given purpose from parameters.
-// nolint:unparam
 func deriveKey(p Parameters, purpose []byte, length int) ([]byte, error) {
 	if length < minDerivedKeyLength {
 		return nil, errors.Errorf("derived key must be at least 32 bytes, was %v", length)
@@ -107,23 +100,3 @@ func deriveKey(p Parameters, purpose []byte, length int) ([]byte, error) {
 
 	return key, nil
 }
-
-// sliceForAppend takes a slice and a requested number of bytes. It returns a
-// slice with the contents of the given slice followed by that many bytes and a
-// second slice that aliases into it and contains only the extra bytes. If the
-// original slice has sufficient capacity then no allocation is performed.
-//
-// From: https://golang.org/src/crypto/cipher/gcm.go
-// Copyright 2013 The Go Authors. All rights reserved.
-func sliceForAppend(in []byte, n int) (head, tail []byte) {
-	if total := len(in) + n; cap(in) >= total {
-		head = in[:total]
-	} else {
-		head = make([]byte, total)
-		copy(head, in)
-	}
-
-	tail = head[len(in):]
-
-	return
-}
diff --git a/repo/encryption/null_encryptor.go b/repo/encryption/null_encryptor.go
deleted file mode 100644
index 84173e4b..00000000
--- a/repo/encryption/null_encryptor.go
+++ /dev/null
@@ -1,30 +0,0 @@
-package encryption
-
-// nullEncryptor implements non-encrypted format.
-type nullEncryptor struct{}
-
-func (fi nullEncryptor) Encrypt(output, plainText, contentID []byte) ([]byte, error) {
-	return append(output, plainText...), nil
-}
-
-func (fi nullEncryptor) Decrypt(output, cipherText, contentID []byte) ([]byte, error) {
-	return append(output, cipherText...), nil
-}
-
-func (fi nullEncryptor) IsAuthenticated() bool {
-	return false
-}
-
-func (fi nullEncryptor) IsDeprecated() bool {
-	return false
-}
-
-func (fi nullEncryptor) MaxOverhead() int {
-	return 0
-}
-
-func init() {
-	Register(DeprecatedNoneAlgorithm, "No encryption", true, func(p Parameters) (Encryptor, error) {
-		return nullEncryptor{}, nil
-	})
-}
diff --git a/snapshot/restore/local_fs_output_linux.go b/snapshot/restore/local_fs_output_unix.go
similarity index 95%
rename from snapshot/restore/local_fs_output_linux.go
rename to snapshot/restore/local_fs_output_unix.go
index f745c601..9c4da7e0 100644
--- a/snapshot/restore/local_fs_output_linux.go
+++ b/snapshot/restore/local_fs_output_unix.go
@@ -1,3 +1,5 @@
+// +build linux freebsd
+
 package restore
 
 import (


Test patch:
diff --git a/repo/content/index_blob_manager_test.go b/repo/content/index_blob_manager_test.go
index bbac98b9..85e1f8a9 100644
--- a/repo/content/index_blob_manager_test.go
+++ b/repo/content/index_blob_manager_test.go
@@ -748,7 +748,7 @@ func newIndexBlobManagerForTesting(t *testing.T, st blob.Storage, localTimeNow f
 	t.Helper()
 
 	p := &FormattingOptions{
-		Encryption: encryption.DeprecatedNoneAlgorithm,
+		Encryption: encryption.DefaultAlgorithm,
 		Hash:       hashing.DefaultAlgorithm,
 	}
 
diff --git a/repo/encryption/encryption_test.go b/repo/encryption/encryption_test.go
index 2b661a23..682f94d1 100644
--- a/repo/encryption/encryption_test.go
+++ b/repo/encryption/encryption_test.go
@@ -45,15 +45,13 @@ func TestRoundTrip(t *testing.T) {
 				t.Errorf("invalid response from Encrypt: %v %v", cipherText1, err)
 			}
 
-			if !e.IsDeprecated() && encryptionAlgo != encryption.DeprecatedNoneAlgorithm {
-				cipherText1b, err2 := e.Encrypt(nil, data, contentID1)
-				if err2 != nil || cipherText1b == nil {
-					t.Errorf("invalid response from Encrypt: %v %v", cipherText1, err2)
-				}
+			cipherText1b, err2 := e.Encrypt(nil, data, contentID1)
+			if err2 != nil || cipherText1b == nil {
+				t.Errorf("invalid response from Encrypt: %v %v", cipherText1, err2)
+			}
 
-				if bytes.Equal(cipherText1, cipherText1b) {
-					t.Errorf("multiple Encrypt returned the same ciphertext: %x", cipherText1)
-				}
+			if bytes.Equal(cipherText1, cipherText1b) {
+				t.Errorf("multiple Encrypt returned the same ciphertext: %x", cipherText1)
 			}
 
 			plainText1, err := e.Decrypt(nil, cipherText1, contentID1)
@@ -90,33 +88,19 @@ func TestRoundTrip(t *testing.T) {
 				t.Errorf("Encrypt()/Decrypt() does not round-trip: %x %x", plainText2, data)
 			}
 
-			if encryptionAlgo != encryption.DeprecatedNoneAlgorithm {
-				if bytes.Equal(cipherText1, cipherText2) {
-					t.Errorf("ciphertexts should be different, were %x", cipherText1)
-				}
-
-				// decrypt using wrong content ID
-				badPlainText2, err := e.Decrypt(nil, cipherText2, contentID1)
-				if e.IsAuthenticated() {
-					if err == nil && encryptionAlgo != "SALSA20-HMAC" {
-						// "SALSA20-HMAC" is deprecated & wrong, and only validates that checksum is
-						// valid for some content, but does not validate that we decrypted the
-						// intended content.
-						t.Errorf("expected decrypt to fail for authenticated encryption")
-					}
-				} else {
-					if bytes.Equal(badPlainText2, plainText2) {
-						t.Errorf("decrypted plaintext matches, but it should not: %x", plainText2)
-					}
-				}
-
-				// flip some bits in the cipherText
-				if e.IsAuthenticated() {
-					cipherText2[mathrand.Intn(len(cipherText2))] ^= byte(1 + mathrand.Intn(254))
-					if _, err := e.Decrypt(nil, cipherText2, contentID1); err == nil {
-						t.Errorf("expected decrypt failure on invalid ciphertext, got success")
-					}
-				}
+			if bytes.Equal(cipherText1, cipherText2) {
+				t.Errorf("ciphertexts should be different, were %x", cipherText1)
+			}
+
+			// decrypt using wrong content ID
+			if _, err := e.Decrypt(nil, cipherText2, contentID1); err == nil {
+				t.Fatalf("expected decrypt to fail for authenticated encryption")
+			}
+
+			// flip some bits in the cipherText
+			cipherText2[mathrand.Intn(len(cipherText2))] ^= byte(1 + mathrand.Intn(254))
+			if _, err := e.Decrypt(nil, cipherText2, contentID1); err == nil {
+				t.Errorf("expected decrypt failure on invalid ciphertext, got success")
 			}
 		})
 	}
@@ -136,17 +120,8 @@ func TestCiphertextSamples(t *testing.T) {
 
 			// samples of base16-encoded ciphertexts of payload encrypted with masterKey & contentID
 			samples: map[string]string{
-				"NONE": hex.EncodeToString([]byte("foo")),
-
 				"AES256-GCM-HMAC-SHA256":        "e43ba07f85a6d70c5f1102ca06cf19c597e5f91e527b21f00fb76e8bec3fd1",
 				"CHACHA20-POLY1305-HMAC-SHA256": "118359f3d4d589d939efbbc3168ae4c77c51bcebce6845fe6ef5d11342faa6",
-
-				// deprecated
-				"AES-128-CTR":  "54cd8d",
-				"AES-192-CTR":  "2d084b",
-				"AES-256-CTR":  "8a580a",
-				"SALSA20":      "bf5ec3",
-				"SALSA20-HMAC": "8bf37fd9ec69843c3c2ac2a2cfdd59f36077206a15289efde640d0e677d03e6ac8f8ec",
 			},
 		},
 		{
@@ -156,17 +131,8 @@ func TestCiphertextSamples(t *testing.T) {
 
 			// samples of base16-encoded ciphertexts of payload encrypted with masterKey & contentID
 			samples: map[string]string{
-				"NONE": hex.EncodeToString([]byte("quick brown fox jumps over the lazy dog")),
-
 				"AES256-GCM-HMAC-SHA256":        "eaad755a238f1daa4052db2e5ccddd934790b6cca415b3ccfd46ac5746af33d9d30f4400ffa9eb3a64fb1ce21b888c12c043bf6787d4a5c15ad10f21f6a6027ee3afe0",
 				"CHACHA20-POLY1305-HMAC-SHA256": "836d2ba87892711077adbdbe1452d3b2c590bbfdf6fd3387dc6810220a32ec19de862e1a4f865575e328424b5f178afac1b7eeff11494f719d119b7ebb924d1d0846a3",
-
-				// deprecated
-				"AES-128-CTR":  "974c5c1782076e3de7255deabe8706a509b5772a8b7a8e7f83d01de7098c945934417071ec5351",
-				"AES-192-CTR":  "1200e755ec14125e87136b5281957895eeb429be673b2241da261f949283aea59fd2fa64387764",
-				"AES-256-CTR":  "39f13367828efb5fb22b97865ca0dbaad352d0c1a3083ff056bc771b812239445ed8af022f3760",
-				"SALSA20":      "65ce12b14739aecbf9e6a9b9b9c4a72ffa8886fe0b071c0abdfb3d3e5c336b90f9af411ba69faf",
-				"SALSA20-HMAC": "a1dc47f250def4d97a422d505fb5e9a9a13699762cb32cfe7705982fa68ce71f54544ab932a1045fb0601087159954d563f0de0aaa15690d93ea63748bf91889e577daeeed5cf8",
 			},
 		},
 	}
diff --git a/repo/maintenance/blob_gc_test.go b/repo/maintenance/blob_gc_test.go
index 9257cabc..29864575 100644
--- a/repo/maintenance/blob_gc_test.go
+++ b/repo/maintenance/blob_gc_test.go
@@ -11,6 +11,7 @@
 
 	"github.com/google/go-cmp/cmp"
 	"github.com/pkg/errors"
+	"github.com/stretchr/testify/require"
 
 	"github.com/kopia/kopia/internal/clock"
 	"github.com/kopia/kopia/internal/faketime"
@@ -20,11 +21,14 @@
 	"github.com/kopia/kopia/repo"
 	"github.com/kopia/kopia/repo/blob"
 	"github.com/kopia/kopia/repo/content"
+	"github.com/kopia/kopia/repo/encryption"
 	"github.com/kopia/kopia/repo/object"
 )
 
 var testHMACSecret = []byte{1, 2, 3}
 
+var testMasterKey = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
+
 func TestDeleteUnreferencedBlobs(t *testing.T) {
 	// set up fake clock which is initially synchronized to wall clock time
 	// and moved at the same speed but which can be moved forward.
@@ -35,7 +39,8 @@ func TestDeleteUnreferencedBlobs(t *testing.T) {
 			o.TimeNowFunc = ta.NowFunc()
 		},
 		NewRepositoryOptions: func(nro *repo.NewRepositoryOptions) {
-			nro.BlockFormat.Encryption = "NONE"
+			nro.BlockFormat.Encryption = encryption.DefaultAlgorithm
+			nro.BlockFormat.MasterKey = testMasterKey
 			nro.BlockFormat.Hash = "HMAC-SHA256"
 			nro.BlockFormat.HMACSecret = testHMACSecret
 		},
@@ -190,11 +195,22 @@ func mustPutDummySessionBlob(t *testing.T, st blob.Storage, sessionIDSuffix blob
 	h := hmac.New(sha256.New, testHMACSecret)
 	h.Write(j)
 
-	blobID := blob.ID(fmt.Sprintf("s%x-%v", h.Sum(nil)[16:32], sessionIDSuffix))
+	iv := h.Sum(nil)[16:32]
 
-	if err := st.PutBlob(testlogging.Context(t), blobID, gather.FromSlice(j)); err != nil {
-		t.Fatal(err)
-	}
+	blobID := blob.ID(fmt.Sprintf("s%x-%v", iv, sessionIDSuffix))
+
+	e, err := encryption.CreateEncryptor(&content.FormattingOptions{
+		Encryption: encryption.DefaultAlgorithm,
+		MasterKey:  testMasterKey,
+		HMACSecret: testHMACSecret,
+	})
+
+	require.NoError(t, err)
+
+	enc, err := e.Encrypt(nil, j, iv)
+	require.NoError(t, err)
+
+	require.NoError(t, st.PutBlob(testlogging.Context(t), blobID, gather.FromSlice(enc)))
 
 	return blobID
 }
diff --git a/tests/stress_test/stress_test.go b/tests/stress_test/stress_test.go
index 57dd6bec..5511c594 100644
--- a/tests/stress_test/stress_test.go
+++ b/tests/stress_test/stress_test.go
@@ -14,6 +14,7 @@
 	"github.com/kopia/kopia/internal/testlogging"
 	"github.com/kopia/kopia/repo/blob"
 	"github.com/kopia/kopia/repo/content"
+	"github.com/kopia/kopia/repo/encryption"
 )
 
 const goroutineCount = 16
@@ -43,7 +44,7 @@ func stressTestWithStorage(t *testing.T, st blob.Storage, duration time.Duration
 		return content.NewManager(ctx, st, &content.FormattingOptions{
 			Version:     1,
 			Hash:        "HMAC-SHA256-128",
-			Encryption:  "AES-256-CTR",
+			Encryption:  encryption.DefaultAlgorithm,
 			MaxPackSize: 20000000,
 			MasterKey:   []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
 		}, nil, nil)