lockbox

password manager
Log | Files | Refs | README | LICENSE

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:
Minternal/encrypt/aesgcm.go | 4++++
Minternal/encrypt/core.go | 13++++++++++++-
Minternal/encrypt/core_test.go | 32++++++++++++++++++++++++++++++++
Minternal/encrypt/secretbox.go | 4++++
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" }