commit a82ae406619704ec696dab12c0dc15e84ab475a9
parent 9fd038815b9bbe14b433182e68a309b67754fc5f
Author: Sean Enck <sean@ttypty.com>
Date: Sat, 17 Sep 2022 13:18:01 -0400
better error handling/tests added for some
Diffstat:
4 files changed, 52 insertions(+), 1 deletion(-)
diff --git a/internal/encrypt/aesgcm.go b/internal/encrypt/aesgcm.go
@@ -58,6 +58,10 @@ func (a aesGCMAlgorithm) encrypt(key, data []byte) ([]byte, error) {
return d, nil
}
+func (a aesGCMAlgorithm) dataSize() int {
+ return aesGCMAlgorithmSaltLength
+}
+
func (a aesGCMAlgorithm) decrypt(key, encrypted []byte) ([]byte, error) {
var salt [aesGCMAlgorithmSaltLength]byte
copy(salt[:], encrypted[0:aesGCMAlgorithmSaltLength])
diff --git a/internal/encrypt/core.go b/internal/encrypt/core.go
@@ -14,6 +14,7 @@ import (
const (
keyLength = 32
+ algorithmBaseVersion = 0
secretBoxAlgorithmVersion algorithmVersions = iota
aesGCMAlgorithmVersion
)
@@ -44,6 +45,7 @@ type (
decrypt(k, d []byte) ([]byte, error)
version() algorithmVersions
name() string
+ dataSize() int
}
)
@@ -74,7 +76,7 @@ func newAlgorithm(mode string) algorithm {
}
func algoVersion(v uint8) []byte {
- return []byte{0, v}
+ return []byte{algorithmBaseVersion, v}
}
func pad(salt, key []byte) ([keyLength]byte, error) {
@@ -130,6 +132,9 @@ func (l Lockbox) Encrypt(datum []byte) error {
}
data = b
}
+ if len(data) == 0 {
+ return errors.New("no data given")
+ }
box := newAlgorithm(l.algo)
if box == nil {
return errors.New("unknown algorithm detected")
@@ -156,9 +161,15 @@ func (l Lockbox) Decrypt() ([]byte, error) {
return nil, errors.New("invalid decryption data")
}
data := encrypted[version:]
+ if encrypted[0] != algorithmBaseVersion {
+ return nil, errors.New("unknown input data header")
+ }
box := newAlgorithmFromVersion(algorithmVersions(encrypted[1]))
if box == nil {
return nil, errors.New("unable to detect algorithm")
}
+ if len(data) <= box.dataSize() {
+ return nil, errors.New("data is invalid for decryption")
+ }
return box.decrypt(l.secret[:], data)
}
diff --git a/internal/encrypt/core_test.go b/internal/encrypt/core_test.go
@@ -127,3 +127,35 @@ func TestEncryptDecryptAESBox(t *testing.T) {
t.Error("data mismatch")
}
}
+
+func TestEncryptErrors(t *testing.T) {
+ e, _ := encrypt.NewLockbox(encrypt.LockboxOptions{Key: "plain", KeyMode: inputs.PlainKeyMode, File: setupData(t)})
+ if err := e.Encrypt([]byte{}); err.Error() != "no data given" {
+ t.Errorf("no data expected: %v", err)
+ }
+ e, _ = encrypt.NewLockbox(encrypt.LockboxOptions{Key: "plain", KeyMode: inputs.PlainKeyMode, File: setupData(t), Algorithm: "bad"})
+ if err := e.Encrypt([]byte{0, 10, 10, 10, 10, 10, 10, 10, 1}); err.Error() != "unknown algorithm detected" {
+ t.Errorf("unknown algorithm expected: %v", err)
+ }
+}
+
+func TestDecryptErrors(t *testing.T) {
+ d := setupData(t)
+ e, _ := encrypt.NewLockbox(encrypt.LockboxOptions{Key: "plain", KeyMode: inputs.PlainKeyMode, File: d})
+ os.WriteFile(d, []byte{}, 0600)
+ if _, err := e.Decrypt(); err.Error() != "invalid decryption data" {
+ t.Errorf("failed to decrypt, invalid: %v", err)
+ }
+ os.WriteFile(d, []byte{1, 80, 1}, 0600)
+ if _, err := e.Decrypt(); err.Error() != "unknown input data header" {
+ t.Errorf("failed to decrypt, bad base: %v", err)
+ }
+ os.WriteFile(d, []byte{0, 80, 1}, 0600)
+ if _, err := e.Decrypt(); err.Error() != "unable to detect algorithm" {
+ t.Errorf("failed to decrypt, bad algorithm: %v", err)
+ }
+ os.WriteFile(d, []byte{0, 2, 1}, 0600)
+ if _, err := e.Decrypt(); err.Error() != "data is invalid for decryption" {
+ t.Errorf("failed to decrypt, bad data: %v", err)
+ }
+}
diff --git a/internal/encrypt/secretbox.go b/internal/encrypt/secretbox.go
@@ -20,6 +20,10 @@ const (
secretBoxAlgorithmSaltLength = 16
)
+func (s secretBoxAlgorithm) dataSize() int {
+ return secretBoxAlgorithmSaltLength + secretBoxAlgorithmNonceLength
+}
+
func (s secretBoxAlgorithm) name() string {
return "secretbox"
}