aboutsummaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorFrank Denis2025-02-25 15:03:50 +0100
committerJakob Unterwurzacher2025-03-12 20:43:23 +0100
commit779a850e0fb967aac79124c7e18b14706d5f2652 (patch)
tree5220a72c4b22a01c74f8d48f4787c4dae9cb1cbe /internal
parent106470d940f7d9fa584463c92f7b2f4f51bce215 (diff)
Add optional support for AEGIS encryption
AEGIS is a new family of authenticated encryption algorithms that offers stronger security, higher usage limits, and better performance than AES-GCM. This pull request adds support for a new `-aegis` command-line flag, allowing AEGIS-128X2 to be used as an alternative to AES-GCM on CPUs with AES acceleration. It also introduces the ability to use ciphers with different key sizes. More information on AEGIS is available here: - https://cfrg.github.io/draft-irtf-cfrg-aegis-aead/draft-irtf-cfrg-aegis-aead.html - https://github.com/cfrg/draft-irtf-cfrg-aegis-aead gocryptfs -speed speed on Apple M1: AES-GCM-256-OpenSSL 3718.79 MB/s AES-GCM-256-Go 5083.43 MB/s (selected in auto mode) AES-SIV-512-Go 625.20 MB/s XChaCha20-Poly1305-OpenSSL 1358.63 MB/s (selected in auto mode) XChaCha20-Poly1305-Go 832.11 MB/s Aegis128X2-Go 11818.73 MB/s gocryptfs -speed speed on AMD Zen 4: AES-GCM-256-OpenSSL 5215.86 MB/s AES-GCM-256-Go 6918.01 MB/s (selected in auto mode) AES-SIV-512-Go 449.61 MB/s XChaCha20-Poly1305-OpenSSL 2643.48 MB/s XChaCha20-Poly1305-Go 3727.46 MB/s (selected in auto mode) Aegis128X2-Go 28109.92 MB/s
Diffstat (limited to 'internal')
-rw-r--r--internal/configfile/config_file.go16
-rw-r--r--internal/configfile/feature_flags.go3
-rw-r--r--internal/configfile/scrypt.go8
-rw-r--r--internal/configfile/validate.go7
-rw-r--r--internal/contentenc/content_test.go9
-rw-r--r--internal/contentenc/offsets_test.go3
-rw-r--r--internal/cryptocore/cryptocore.go48
-rw-r--r--internal/exitcodes/exitcodes.go2
-rw-r--r--internal/fusefrontend/xattr_unit_test.go3
-rw-r--r--internal/nametransform/longnames_test.go3
-rw-r--r--internal/speed/speed.go9
-rw-r--r--internal/stupidgcm/Makefile8
-rw-r--r--internal/stupidgcm/aegis.go57
-rw-r--r--internal/stupidgcm/aegis_test.go16
-rw-r--r--internal/stupidgcm/chacha.go4
-rw-r--r--internal/stupidgcm/chacha_test.go4
-rw-r--r--internal/stupidgcm/common.go4
-rw-r--r--internal/stupidgcm/common_test.go2
-rw-r--r--internal/stupidgcm/doc.go6
-rw-r--r--internal/stupidgcm/gcm.go4
-rw-r--r--internal/stupidgcm/gcm_test.go4
-rw-r--r--internal/stupidgcm/locking.go4
-rw-r--r--internal/stupidgcm/openssl.go4
-rw-r--r--internal/stupidgcm/without_aegis.go28
-rw-r--r--internal/stupidgcm/without_openssl.go4
-rw-r--r--internal/stupidgcm/xchacha.go4
-rw-r--r--internal/stupidgcm/xchacha_test.go4
27 files changed, 217 insertions, 51 deletions
diff --git a/internal/configfile/config_file.go b/internal/configfile/config_file.go
index 995a0c8..5e10228 100644
--- a/internal/configfile/config_file.go
+++ b/internal/configfile/config_file.go
@@ -32,7 +32,7 @@ type FIDO2Params struct {
// FIDO2 credential
CredentialID []byte
// FIDO2 hmac-secret salt
- HMACSalt []byte
+ HMACSalt []byte
AssertOptions []string
}
@@ -75,6 +75,7 @@ type CreateArgs struct {
Fido2AssertOptions []string
DeterministicNames bool
XChaCha20Poly1305 bool
+ Aegis bool
LongNameMax uint8
Masterkey []byte
}
@@ -92,6 +93,8 @@ func Create(args *CreateArgs) error {
cf.setFeatureFlag(FlagHKDF)
if args.XChaCha20Poly1305 {
cf.setFeatureFlag(FlagXChaCha20Poly1305)
+ } else if args.Aegis {
+ cf.setFeatureFlag(FlagAegis)
} else {
// 128-bit IVs are mandatory for AES-GCM (default is 96!) and AES-SIV,
// XChaCha20Poly1305 uses even an even longer IV of 192 bits.
@@ -119,9 +122,9 @@ func Create(args *CreateArgs) error {
if len(args.Fido2CredentialID) > 0 {
cf.setFeatureFlag(FlagFIDO2)
cf.FIDO2 = &FIDO2Params{
- CredentialID: args.Fido2CredentialID,
- HMACSalt: args.Fido2HmacSalt,
- AssertOptions: args.Fido2AssertOptions,
+ CredentialID: args.Fido2CredentialID,
+ HMACSalt: args.Fido2HmacSalt,
+ AssertOptions: args.Fido2AssertOptions,
}
}
// Catch bugs and invalid cli flag combinations early
@@ -133,7 +136,7 @@ func Create(args *CreateArgs) error {
key := args.Masterkey
if key == nil {
// Generate new random master key
- key = cryptocore.RandBytes(cryptocore.KeyLen)
+ key = cryptocore.RandBytes(cryptocore.MaxKeyLen)
}
tlog.PrintMasterkeyReminder(key)
// Encrypt it using the password
@@ -327,6 +330,9 @@ func (cf *ConfFile) ContentEncryption() (algo cryptocore.AEADTypeEnum, err error
if cf.IsFeatureFlagSet(FlagXChaCha20Poly1305) {
return cryptocore.BackendXChaCha20Poly1305, nil
}
+ if cf.IsFeatureFlagSet(FlagAegis) {
+ return cryptocore.BackendAegis, nil
+ }
if cf.IsFeatureFlagSet(FlagAESSIV) {
return cryptocore.BackendAESSIV, nil
}
diff --git a/internal/configfile/feature_flags.go b/internal/configfile/feature_flags.go
index d6627a5..2722831 100644
--- a/internal/configfile/feature_flags.go
+++ b/internal/configfile/feature_flags.go
@@ -34,6 +34,8 @@ const (
FlagFIDO2
// FlagXChaCha20Poly1305 means we use XChaCha20-Poly1305 file content encryption
FlagXChaCha20Poly1305
+ // FlagAegis means we use Aegis file content encryption
+ FlagAegis
)
// knownFlags stores the known feature flags and their string representation
@@ -49,6 +51,7 @@ var knownFlags = map[flagIota]string{
FlagHKDF: "HKDF",
FlagFIDO2: "FIDO2",
FlagXChaCha20Poly1305: "XChaCha20Poly1305",
+ FlagAegis: "AEGIS",
}
// isFeatureFlagKnown verifies that we understand a feature flag.
diff --git a/internal/configfile/scrypt.go b/internal/configfile/scrypt.go
index 0ce8777..b82a431 100644
--- a/internal/configfile/scrypt.go
+++ b/internal/configfile/scrypt.go
@@ -49,7 +49,7 @@ type ScryptKDF struct {
// NewScryptKDF returns a new instance of ScryptKDF.
func NewScryptKDF(logN int) ScryptKDF {
var s ScryptKDF
- s.Salt = cryptocore.RandBytes(cryptocore.KeyLen)
+ s.Salt = cryptocore.RandBytes(cryptocore.MaxKeyLen)
if logN <= 0 {
s.N = 1 << ScryptDefaultLogN
} else {
@@ -57,7 +57,7 @@ func NewScryptKDF(logN int) ScryptKDF {
}
s.R = 8 // Always 8
s.P = 1 // Always 1
- s.KeyLen = cryptocore.KeyLen
+ s.KeyLen = cryptocore.MaxKeyLen
return s
}
@@ -98,8 +98,8 @@ func (s *ScryptKDF) validateParams() error {
if len(s.Salt) < scryptMinSaltLen {
return fmt.Errorf("Fatal: scrypt salt length below minimum: value=%d, min=%d", len(s.Salt), scryptMinSaltLen)
}
- if s.KeyLen < cryptocore.KeyLen {
- return fmt.Errorf("Fatal: scrypt parameter KeyLen below minimum: value=%d, min=%d", s.KeyLen, cryptocore.KeyLen)
+ if s.KeyLen < cryptocore.MinKeyLen {
+ return fmt.Errorf("Fatal: scrypt parameter KeyLen below minimum: value=%d, min=%d", s.KeyLen, cryptocore.MinKeyLen)
}
return nil
}
diff --git a/internal/configfile/validate.go b/internal/configfile/validate.go
index ab8917d..333eea6 100644
--- a/internal/configfile/validate.go
+++ b/internal/configfile/validate.go
@@ -38,8 +38,13 @@ func (cf *ConfFile) Validate() error {
return fmt.Errorf("XChaCha20Poly1305 requires HKDF feature flag")
}
}
+ if cf.IsFeatureFlagSet(FlagAegis) {
+ if cf.IsFeatureFlagSet(FlagGCMIV128) {
+ return fmt.Errorf("AEGIS conflicts with GCMIV128 feature flag")
+ }
+ }
// The absence of other flags means AES-GCM (oldest algorithm)
- if !cf.IsFeatureFlagSet(FlagXChaCha20Poly1305) && !cf.IsFeatureFlagSet(FlagAESSIV) {
+ if !cf.IsFeatureFlagSet(FlagAegis) && !cf.IsFeatureFlagSet(FlagXChaCha20Poly1305) && !cf.IsFeatureFlagSet(FlagAESSIV) {
if !cf.IsFeatureFlagSet(FlagGCMIV128) {
return fmt.Errorf("AES-GCM requires GCMIV128 feature flag")
}
diff --git a/internal/contentenc/content_test.go b/internal/contentenc/content_test.go
index b20ccb1..2a34307 100644
--- a/internal/contentenc/content_test.go
+++ b/internal/contentenc/content_test.go
@@ -22,7 +22,8 @@ func TestSplitRange(t *testing.T) {
{6654, 8945},
}
- key := make([]byte, cryptocore.KeyLen)
+ keyLen := cryptocore.BackendGoGCM.KeyLen
+ key := make([]byte, keyLen)
cc := cryptocore.New(key, cryptocore.BackendGoGCM, DefaultIVBits, true)
f := New(cc, DefaultBS)
@@ -50,7 +51,8 @@ func TestCiphertextRange(t *testing.T) {
{6654, 8945},
}
- key := make([]byte, cryptocore.KeyLen)
+ keyLen := cryptocore.BackendGoGCM.KeyLen
+ key := make([]byte, keyLen)
cc := cryptocore.New(key, cryptocore.BackendGoGCM, DefaultIVBits, true)
f := New(cc, DefaultBS)
@@ -73,7 +75,8 @@ func TestCiphertextRange(t *testing.T) {
}
func TestBlockNo(t *testing.T) {
- key := make([]byte, cryptocore.KeyLen)
+ keyLen := cryptocore.BackendGoGCM.KeyLen
+ key := make([]byte, keyLen)
cc := cryptocore.New(key, cryptocore.BackendGoGCM, DefaultIVBits, true)
f := New(cc, DefaultBS)
diff --git a/internal/contentenc/offsets_test.go b/internal/contentenc/offsets_test.go
index b35964a..0118c5e 100644
--- a/internal/contentenc/offsets_test.go
+++ b/internal/contentenc/offsets_test.go
@@ -9,7 +9,8 @@ import (
// TestSizeToSize tests CipherSizeToPlainSize and PlainSizeToCipherSize
func TestSizeToSize(t *testing.T) {
- key := make([]byte, cryptocore.KeyLen)
+ keyLen := cryptocore.BackendGoGCM.KeyLen
+ key := make([]byte, keyLen)
cc := cryptocore.New(key, cryptocore.BackendGoGCM, DefaultIVBits, true)
ce := New(cc, DefaultBS)
diff --git a/internal/cryptocore/cryptocore.go b/internal/cryptocore/cryptocore.go
index 72c9c23..0848096 100644
--- a/internal/cryptocore/cryptocore.go
+++ b/internal/cryptocore/cryptocore.go
@@ -11,6 +11,7 @@ import (
"golang.org/x/crypto/chacha20poly1305"
+ "github.com/aegis-aead/go-libaegis/aegis128x2"
"github.com/rfjakob/eme"
"github.com/rfjakob/gocryptfs/v2/internal/siv_aead"
@@ -19,11 +20,13 @@ import (
)
const (
- // KeyLen is the cipher key length in bytes. All backends use 32 bytes.
- KeyLen = 32
// AuthTagLen is the length of a authentication tag in bytes.
// All backends use 16 bytes.
AuthTagLen = 16
+ // Minimum key length
+ MinKeyLen = 16
+ // Maximum key length
+ MaxKeyLen = 32
)
// AEADTypeEnum indicates the type of AEAD backend in use.
@@ -32,6 +35,7 @@ type AEADTypeEnum struct {
Algo string
// Lib is the library where Algo is implemented. Either "Go" or "OpenSSL".
Lib string
+ KeyLen int
NonceSize int
}
@@ -42,22 +46,24 @@ func (a AEADTypeEnum) String() string {
// BackendOpenSSL specifies the OpenSSL AES-256-GCM backend.
// "AES-GCM-256-OpenSSL" in gocryptfs -speed.
-var BackendOpenSSL = AEADTypeEnum{"AES-GCM-256", "OpenSSL", 16}
+var BackendOpenSSL = AEADTypeEnum{"AES-GCM-256", "OpenSSL", 32, 16}
// BackendGoGCM specifies the Go based AES-256-GCM backend.
// "AES-GCM-256-Go" in gocryptfs -speed.
-var BackendGoGCM = AEADTypeEnum{"AES-GCM-256", "Go", 16}
+var BackendGoGCM = AEADTypeEnum{"AES-GCM-256", "Go", 32, 16}
// BackendAESSIV specifies an AESSIV backend.
// "AES-SIV-512-Go" in gocryptfs -speed.
-var BackendAESSIV = AEADTypeEnum{"AES-SIV-512", "Go", siv_aead.NonceSize}
+var BackendAESSIV = AEADTypeEnum{"AES-SIV-512", "Go", 32, siv_aead.NonceSize}
// BackendXChaCha20Poly1305 specifies XChaCha20-Poly1305-Go.
// "XChaCha20-Poly1305-Go" in gocryptfs -speed.
-var BackendXChaCha20Poly1305 = AEADTypeEnum{"XChaCha20-Poly1305", "Go", chacha20poly1305.NonceSizeX}
+var BackendXChaCha20Poly1305 = AEADTypeEnum{"XChaCha20-Poly1305", "Go", 32, chacha20poly1305.NonceSizeX}
// BackendXChaCha20Poly1305OpenSSL specifies XChaCha20-Poly1305-OpenSSL.
-var BackendXChaCha20Poly1305OpenSSL = AEADTypeEnum{"XChaCha20-Poly1305", "OpenSSL", chacha20poly1305.NonceSizeX}
+var BackendXChaCha20Poly1305OpenSSL = AEADTypeEnum{"XChaCha20-Poly1305", "OpenSSL", 32, chacha20poly1305.NonceSizeX}
+
+var BackendAegis = AEADTypeEnum{"Aegis128X2", "Go", 16, aegis128x2.NonceSize}
// CryptoCore is the low level crypto implementation.
type CryptoCore struct {
@@ -85,9 +91,14 @@ func New(key []byte, aeadType AEADTypeEnum, IVBitLen int, useHKDF bool) *CryptoC
tlog.Debug.Printf("cryptocore.New: key=%d bytes, aeadType=%v, IVBitLen=%d, useHKDF=%v",
len(key), aeadType, IVBitLen, useHKDF)
- if len(key) != KeyLen {
+ keyLen := aeadType.KeyLen
+ if keyLen < MinKeyLen || keyLen > MaxKeyLen {
+ log.Panicf("Unsupported key length of %d bytes", keyLen)
+ }
+ if len(key) < keyLen {
log.Panicf("Unsupported key length of %d bytes", len(key))
}
+ key = key[:keyLen] // keys can safely be truncated
if IVBitLen != 96 && IVBitLen != 128 && IVBitLen != chacha20poly1305.NonceSizeX*8 {
log.Panicf("Unsupported IV length of %d bits", IVBitLen)
}
@@ -98,7 +109,7 @@ func New(key []byte, aeadType AEADTypeEnum, IVBitLen int, useHKDF bool) *CryptoC
{
var emeBlockCipher cipher.Block
if useHKDF {
- emeKey := hkdfDerive(key, hkdfInfoEMENames, KeyLen)
+ emeKey := hkdfDerive(key, hkdfInfoEMENames, keyLen)
emeBlockCipher, err = aes.NewCipher(emeKey)
for i := range emeKey {
emeKey[i] = 0
@@ -117,7 +128,7 @@ func New(key []byte, aeadType AEADTypeEnum, IVBitLen int, useHKDF bool) *CryptoC
if aeadType == BackendOpenSSL || aeadType == BackendGoGCM {
var gcmKey []byte
if useHKDF {
- gcmKey = hkdfDerive(key, hkdfInfoGCMContent, KeyLen)
+ gcmKey = hkdfDerive(key, hkdfInfoGCMContent, keyLen)
} else {
// Filesystems created by gocryptfs v0.7 through v1.2 don't use HKDF.
// Example: tests/example_filesystems/v0.9
@@ -183,6 +194,23 @@ func New(key []byte, aeadType AEADTypeEnum, IVBitLen int, useHKDF bool) *CryptoC
if err != nil {
log.Panic(err)
}
+ } else if aeadType == BackendAegis {
+ if stupidgcm.BuiltWithoutAegis {
+ log.Panic("AEGIS is not available")
+ }
+ if IVBitLen != 128 {
+ log.Panicf("AEGIS must use 128-bit IVs, you wanted %d", IVBitLen)
+ }
+ var aegisKey []byte
+ if useHKDF {
+ aegisKey = hkdfDerive(key, hkdfInfoGCMContent, keyLen)
+ } else {
+ aegisKey = append([]byte{}, key...)
+ }
+ aeadCipher = stupidgcm.NewAegis(aegisKey)
+ for i := range aegisKey {
+ aegisKey[i] = 0
+ }
} else {
log.Panicf("unknown cipher backend %q", aeadType)
}
diff --git a/internal/exitcodes/exitcodes.go b/internal/exitcodes/exitcodes.go
index 508ba38..6bf7672 100644
--- a/internal/exitcodes/exitcodes.go
+++ b/internal/exitcodes/exitcodes.go
@@ -72,6 +72,8 @@ const (
DevNull = 30
// FIDO2Error - an error was encountered while interacting with a FIDO2 token
FIDO2Error = 31
+ // Aegis means you tried to enable Aegis, but we were compiled without it.
+ Aegis = 32
)
// Err wraps an error with an associated numeric exit code
diff --git a/internal/fusefrontend/xattr_unit_test.go b/internal/fusefrontend/xattr_unit_test.go
index 86c87a7..5f69e00 100644
--- a/internal/fusefrontend/xattr_unit_test.go
+++ b/internal/fusefrontend/xattr_unit_test.go
@@ -16,7 +16,8 @@ import (
func newTestFS(args Args) *RootNode {
// Init crypto backend
- key := make([]byte, cryptocore.KeyLen)
+ keyLen := cryptocore.BackendGoGCM.KeyLen
+ key := make([]byte, keyLen)
cCore := cryptocore.New(key, cryptocore.BackendGoGCM, contentenc.DefaultIVBits, true)
cEnc := contentenc.New(cCore, contentenc.DefaultBS)
n := nametransform.New(cCore.EMECipher, true, 0, true, nil, false)
diff --git a/internal/nametransform/longnames_test.go b/internal/nametransform/longnames_test.go
index 7a4e915..be18f92 100644
--- a/internal/nametransform/longnames_test.go
+++ b/internal/nametransform/longnames_test.go
@@ -34,7 +34,8 @@ func TestRemoveLongNameSuffix(t *testing.T) {
}
func newLognamesTestInstance(longNameMax uint8) *NameTransform {
- key := make([]byte, cryptocore.KeyLen)
+ keyLen := cryptocore.BackendGoGCM.KeyLen
+ key := make([]byte, keyLen)
cCore := cryptocore.New(key, cryptocore.BackendGoGCM, contentenc.DefaultIVBits, true)
return New(cCore.EMECipher, true, longNameMax, true, nil, false)
}
diff --git a/internal/speed/speed.go b/internal/speed/speed.go
index d6fa12e..e60e37d 100644
--- a/internal/speed/speed.go
+++ b/internal/speed/speed.go
@@ -47,13 +47,14 @@ func Run() {
{name: cryptocore.BackendAESSIV.String(), f: bAESSIV, preferred: false},
{name: cryptocore.BackendXChaCha20Poly1305OpenSSL.String(), f: bStupidXchacha, preferred: stupidgcm.PreferOpenSSLXchacha20poly1305()},
{name: cryptocore.BackendXChaCha20Poly1305.String(), f: bXchacha20poly1305, preferred: !stupidgcm.PreferOpenSSLXchacha20poly1305()},
+ {name: cryptocore.BackendAegis.String(), f: bAegis, preferred: false},
}
testing.Init()
for _, b := range bTable {
fmt.Printf("%-26s\t", b.name)
mbs := mbPerSec(testing.Benchmark(b.f))
if mbs > 0 {
- fmt.Printf("%7.2f MB/s", mbs)
+ fmt.Printf("%8.2f MB/s", mbs)
} else {
fmt.Printf(" N/A")
}
@@ -168,3 +169,9 @@ func bStupidXchacha(b *testing.B) {
}
bEncrypt(b, stupidgcm.NewXchacha20poly1305(randBytes(32)))
}
+
+// bAegis benchmarks Aegis from github.com/aegis-aead/go-libaegis
+func bAegis(b *testing.B) {
+ c := stupidgcm.NewAegis(randBytes(16))
+ bEncrypt(b, c)
+}
diff --git a/internal/stupidgcm/Makefile b/internal/stupidgcm/Makefile
index 143819d..d8f7d2e 100644
--- a/internal/stupidgcm/Makefile
+++ b/internal/stupidgcm/Makefile
@@ -3,11 +3,15 @@ test: gcc
# All three ways of building this must work
go build
go build -tags without_openssl
- CGO_ENABLED=0 go build -tags without_openssl
+ go build -tags without_aegis
+ go build -tags without_openssl,without_aegis
+ CGO_ENABLED=0 go build -tags without_openssl,without_aegis
# Likewise, all three ways of testing this must work
go test -v
go test -v -tags without_openssl
- CGO_ENABLED=0 go test -v -tags without_openssl
+ go test -v -tags without_aegis
+ go test -v -tags without_openssl,without_aegis
+ CGO_ENABLED=0 go test -v -tags without_openssl,without_aegis
.PHONY: gcc
gcc:
diff --git a/internal/stupidgcm/aegis.go b/internal/stupidgcm/aegis.go
new file mode 100644
index 0000000..8975055
--- /dev/null
+++ b/internal/stupidgcm/aegis.go
@@ -0,0 +1,57 @@
+//go:build !without_aegis && cgo
+// +build !without_aegis,cgo
+
+package stupidgcm
+
+import (
+ "crypto/cipher"
+ "log"
+
+ "github.com/aegis-aead/go-libaegis/aegis128x2"
+ "github.com/aegis-aead/go-libaegis/common"
+)
+
+const (
+ // BuiltWithoutAegis indicates if aegis been disabled at compile-time
+ BuiltWithoutAegis = !common.Available
+
+ // Aegis supports 16 and 32 bit tags
+ AegisTagLen = 16
+)
+
+type stupidAegis struct {
+ aead cipher.AEAD
+}
+
+// Verify that we satisfy the cipher.AEAD interface
+var _ cipher.AEAD = &stupidAegis{}
+
+func (*stupidAegis) NonceSize() int {
+ return aegis128x2.NonceSize
+}
+
+func (*stupidAegis) Overhead() int {
+ return AegisTagLen
+}
+
+func NewAegis(key []byte) cipher.AEAD {
+ aead, err := aegis128x2.New(key, AegisTagLen)
+ if err != nil {
+ log.Panic(err)
+ }
+ return &stupidAegis{
+ aead: aead,
+ }
+}
+
+func (x *stupidAegis) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
+ return x.aead.Seal(dst, nonce, plaintext, additionalData)
+}
+
+func (x *stupidAegis) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+ return x.aead.Open(dst, nonce, ciphertext, additionalData)
+}
+
+func (x *stupidAegis) Wipe() {
+ x.aead.(*aegis128x2.Aegis128X2).Wipe()
+}
diff --git a/internal/stupidgcm/aegis_test.go b/internal/stupidgcm/aegis_test.go
new file mode 100644
index 0000000..36ef763
--- /dev/null
+++ b/internal/stupidgcm/aegis_test.go
@@ -0,0 +1,16 @@
+//go:build !without_aegis && cgo
+// +build !without_aegis,cgo
+
+package stupidgcm
+
+import "testing"
+
+func TestStupidAegis(t *testing.T) {
+ if BuiltWithoutAegis {
+ t.Skip("Aegis support has been disabled at compile-time")
+ }
+ key := randBytes(16)
+ c := NewAegis(key)
+
+ testCiphers(t, c, c)
+}
diff --git a/internal/stupidgcm/chacha.go b/internal/stupidgcm/chacha.go
index de0c2e8..dcdcb3a 100644
--- a/internal/stupidgcm/chacha.go
+++ b/internal/stupidgcm/chacha.go
@@ -1,5 +1,5 @@
-//go:build !without_openssl
-// +build !without_openssl
+//go:build !without_openssl && cgo
+// +build !without_openssl,cgo
package stupidgcm
diff --git a/internal/stupidgcm/chacha_test.go b/internal/stupidgcm/chacha_test.go
index 542ff15..4fa038b 100644
--- a/internal/stupidgcm/chacha_test.go
+++ b/internal/stupidgcm/chacha_test.go
@@ -1,5 +1,5 @@
-//go:build !without_openssl
-// +build !without_openssl
+//go:build !without_openssl && cgo
+// +build !without_openssl,cgo
package stupidgcm
diff --git a/internal/stupidgcm/common.go b/internal/stupidgcm/common.go
index d88dc62..c5dd338 100644
--- a/internal/stupidgcm/common.go
+++ b/internal/stupidgcm/common.go
@@ -1,5 +1,5 @@
-//go:build !without_openssl
-// +build !without_openssl
+//go:build !without_openssl && cgo
+// +build !without_openssl,cgo
package stupidgcm
diff --git a/internal/stupidgcm/common_test.go b/internal/stupidgcm/common_test.go
index 7f38e90..47fee7c 100644
--- a/internal/stupidgcm/common_test.go
+++ b/internal/stupidgcm/common_test.go
@@ -246,6 +246,8 @@ func testWipe(t *testing.T, c cipher.AEAD) {
t.Fatal("c2.key is not zeroed")
}
}
+ case *stupidAegis:
+ c2.Wipe() // AEGIS has its own Wipe method
default:
t.Fatalf("BUG: unhandled type %T", c2)
}
diff --git a/internal/stupidgcm/doc.go b/internal/stupidgcm/doc.go
index dce82ae..f5d4177 100644
--- a/internal/stupidgcm/doc.go
+++ b/internal/stupidgcm/doc.go
@@ -1,5 +1,5 @@
-// Package stupidgcm wraps OpenSSL to provide a cipher.AEAD interface for
-// authenticated encryption algorithms.
+// Package stupidgcm wraps OpenSSL and libaegis to provide a cipher.AEAD
+// interface for authenticated encryption algorithms.
//
// The supported algorithms are:
//
@@ -9,6 +9,8 @@
//
// (3) XChaCha20-Poly1305 (OpenSSL EVP_chacha20_poly1305 + Go HChaCha20)
//
+// (4) AEGIS (go-libaegis)
+//
// The golang.org/x/crypto libraries provides implementations for all algorithms,
// and the test suite verifies that the implementation in this package gives
// the exact same results.
diff --git a/internal/stupidgcm/gcm.go b/internal/stupidgcm/gcm.go
index 2e5aac4..738021e 100644
--- a/internal/stupidgcm/gcm.go
+++ b/internal/stupidgcm/gcm.go
@@ -1,5 +1,5 @@
-//go:build !without_openssl
-// +build !without_openssl
+//go:build !without_openssl && cgo
+// +build !without_openssl,cgo
package stupidgcm
diff --git a/internal/stupidgcm/gcm_test.go b/internal/stupidgcm/gcm_test.go
index c730a87..6c15287 100644
--- a/internal/stupidgcm/gcm_test.go
+++ b/internal/stupidgcm/gcm_test.go
@@ -1,5 +1,5 @@
-//go:build !without_openssl
-// +build !without_openssl
+//go:build !without_openssl && cgo
+// +build !without_openssl,cgo
// We compare against Go's built-in GCM implementation. Since stupidgcm only
// supports 128-bit IVs and Go only supports that from 1.5 onward, we cannot
diff --git a/internal/stupidgcm/locking.go b/internal/stupidgcm/locking.go
index 04cf232..29f8332 100644
--- a/internal/stupidgcm/locking.go
+++ b/internal/stupidgcm/locking.go
@@ -1,5 +1,5 @@
-//go:build !without_openssl
-// +build !without_openssl
+//go:build !without_openssl && cgo
+// +build !without_openssl,cgo
package stupidgcm
diff --git a/internal/stupidgcm/openssl.go b/internal/stupidgcm/openssl.go
index 8c950f8..0360629 100644
--- a/internal/stupidgcm/openssl.go
+++ b/internal/stupidgcm/openssl.go
@@ -1,5 +1,5 @@
-//go:build !without_openssl
-// +build !without_openssl
+//go:build !without_openssl && cgo
+// +build !without_openssl,cgo
package stupidgcm
diff --git a/internal/stupidgcm/without_aegis.go b/internal/stupidgcm/without_aegis.go
new file mode 100644
index 0000000..efd665c
--- /dev/null
+++ b/internal/stupidgcm/without_aegis.go
@@ -0,0 +1,28 @@
+//go:build without_aegis || !cgo
+// +build without_aegis !cgo
+
+package stupidgcm
+
+import (
+ "fmt"
+ "os"
+
+ "crypto/cipher"
+
+ "github.com/rfjakob/gocryptfs/v2/internal/exitcodes"
+)
+
+const (
+ // BuiltWithoutAegis indicates if openssl been disabled at compile-time
+ BuiltWithoutAegis = true
+)
+
+type stupidAegis struct {
+ aead cipher.AEAD
+}
+
+func NewAegis(_ []byte) cipher.AEAD {
+ fmt.Fprintln(os.Stderr, "I have been compiled without aegis support but you are still trying to use aegis")
+ os.Exit(exitcodes.Aegis)
+ return nil
+}
diff --git a/internal/stupidgcm/without_openssl.go b/internal/stupidgcm/without_openssl.go
index fcef793..1901c78 100644
--- a/internal/stupidgcm/without_openssl.go
+++ b/internal/stupidgcm/without_openssl.go
@@ -1,5 +1,5 @@
-//go:build without_openssl
-// +build without_openssl
+//go:build without_openssl || !cgo
+// +build without_openssl !cgo
package stupidgcm
diff --git a/internal/stupidgcm/xchacha.go b/internal/stupidgcm/xchacha.go
index 3c121ba..0187da8 100644
--- a/internal/stupidgcm/xchacha.go
+++ b/internal/stupidgcm/xchacha.go
@@ -1,5 +1,5 @@
-//go:build !without_openssl
-// +build !without_openssl
+//go:build !without_openssl && cgo
+// +build !without_openssl,cgo
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
diff --git a/internal/stupidgcm/xchacha_test.go b/internal/stupidgcm/xchacha_test.go
index 676a023..bd62c04 100644
--- a/internal/stupidgcm/xchacha_test.go
+++ b/internal/stupidgcm/xchacha_test.go
@@ -1,5 +1,5 @@
-//go:build !without_openssl
-// +build !without_openssl
+//go:build !without_openssl && cgo
+// +build !without_openssl,cgo
package stupidgcm