lockbox

password manager
Log | Files | Refs | README | LICENSE

commit 9a4b0a076c0c0f0b35b4a0a4a1562c2c55741990
parent bd900945f0f8c11f24a2e0046ae66a3d20744241
Author: Sean Enck <sean@ttypty.com>
Date:   Sat, 17 Sep 2022 12:26:33 -0400

more algorithm support

Diffstat:
Dinternal/encrypt/algorithms.go | 67-------------------------------------------------------------------
Minternal/encrypt/core.go | 56+++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Minternal/encrypt/core_test.go | 2+-
Minternal/inputs/env.go | 2+-
Minternal/subcommands/readwrite.go | 3++-
Minternal/subcommands/rekey.go | 6++++--
6 files changed, 63 insertions(+), 73 deletions(-)

diff --git a/internal/encrypt/algorithms.go b/internal/encrypt/algorithms.go @@ -1,67 +0,0 @@ -package encrypt - -import ( - "crypto/sha512" - "errors" - random "math/rand" - "time" - - "github.com/enckse/lockbox/internal/inputs" - "golang.org/x/crypto/pbkdf2" -) - -const ( - secretBoxAlgorithmVersion uint8 = 1 - isSecretBox = "secretbox" - aesGCMAlgorithmVersion uint8 = 2 -) - -type ( - algorithm interface { - encrypt(k, d []byte) ([]byte, error) - decrypt(k, d []byte) ([]byte, error) - version() []byte - } -) - -func init() { - random.Seed(time.Now().UnixNano()) -} - -func newAlgorithmFromVersion(vers uint8) algorithm { - switch vers { - case secretBoxAlgorithmVersion: - return secretBoxAlgorithm{} - case aesGCMAlgorithmVersion: - return aesGCMAlgorithm{} - } - return nil -} - -func newAlgorithm(mode string) algorithm { - useMode := mode - if mode == "" { - useMode = inputs.EnvOrDefault(inputs.EncryptModeEnv, isSecretBox) - } - switch useMode { - case isSecretBox: - return secretBoxAlgorithm{} - case "aes": - return aesGCMAlgorithm{} - } - return nil -} - -func algoVersion(v uint8) []byte { - return []byte{0, v} -} - -func pad(salt, key []byte) ([keyLength]byte, error) { - d := pbkdf2.Key(key, salt, 4096, keyLength, sha512.New) - if len(d) != keyLength { - return [keyLength]byte{}, errors.New("invalid key result from pad") - } - var obj [keyLength]byte - copy(obj[:], d[:keyLength]) - return obj, nil -} diff --git a/internal/encrypt/core.go b/internal/encrypt/core.go @@ -2,14 +2,21 @@ package encrypt import ( + "crypto/sha512" "errors" + random "math/rand" "os" + "time" "github.com/enckse/lockbox/internal/inputs" + "golang.org/x/crypto/pbkdf2" ) const ( - keyLength = 32 + keyLength = 32 + secretBoxAlgorithmVersion uint8 = 1 + isSecretBox = "secretbox" + aesGCMAlgorithmVersion uint8 = 2 ) type ( @@ -27,8 +34,55 @@ type ( File string Algorithm string } + algorithm interface { + encrypt(k, d []byte) ([]byte, error) + decrypt(k, d []byte) ([]byte, error) + version() []byte + } ) +func init() { + random.Seed(time.Now().UnixNano()) +} + +func newAlgorithmFromVersion(vers uint8) algorithm { + switch vers { + case secretBoxAlgorithmVersion: + return secretBoxAlgorithm{} + case aesGCMAlgorithmVersion: + return aesGCMAlgorithm{} + } + return nil +} + +func newAlgorithm(mode string) algorithm { + useMode := mode + if mode == "" { + useMode = inputs.EnvOrDefault(inputs.EncryptModeEnv, isSecretBox) + } + switch useMode { + case isSecretBox: + return secretBoxAlgorithm{} + case "aesgcm": + return aesGCMAlgorithm{} + } + return nil +} + +func algoVersion(v uint8) []byte { + return []byte{0, v} +} + +func pad(salt, key []byte) ([keyLength]byte, error) { + d := pbkdf2.Key(key, salt, 4096, keyLength, sha512.New) + if len(d) != keyLength { + return [keyLength]byte{}, errors.New("invalid key result from pad") + } + var obj [keyLength]byte + copy(obj[:], d[:keyLength]) + return obj, nil +} + // FromFile decrypts a file-system based encrypted file. func FromFile(file string) ([]byte, error) { l, err := NewLockbox(LockboxOptions{File: file}) diff --git a/internal/encrypt/core_test.go b/internal/encrypt/core_test.go @@ -111,7 +111,7 @@ func TestEncryptDecryptSecretBox(t *testing.T) { } func TestEncryptDecryptAESBox(t *testing.T) { - e, err := encrypt.NewLockbox(encrypt.LockboxOptions{Key: "plain", KeyMode: inputs.PlainKeyMode, File: setupData(t), Algorithm: "aes"}) + e, err := encrypt.NewLockbox(encrypt.LockboxOptions{Key: "plain", KeyMode: inputs.PlainKeyMode, File: setupData(t), Algorithm: "aesgcm"}) if err != nil { t.Errorf("failed to create lockbox: %v", err) } diff --git a/internal/inputs/env.go b/internal/inputs/env.go @@ -35,7 +35,7 @@ const ( // ColorBetweenEnv is a comma-delimited list of times to color totp outputs (e.g. 0:5,30:35 which is the default). ColorBetweenEnv = prefixKey + "TOTPBETWEEN" // EncryptModeEnv indicates the underlying algorith to use for encryption. - EncryptModeEnv = prefixKey + "ALGORITHM" + EncryptModeEnv = prefixKey + "ALGORITHM" // PlainKeyMode is plaintext based key resolution. PlainKeyMode = "plaintext" // CommandKeyMode will run an external command to get the key (from stdout). diff --git a/internal/subcommands/readwrite.go b/internal/subcommands/readwrite.go @@ -16,11 +16,12 @@ func ReadWrite(args []string) error { key := flags.String("key", "", "security key") file := flags.String("file", "", "file to process") keyMode := flags.String("keymode", "", "key lookup mode") + algo := flags.String("algorithm", "", "algorithm to use") if err := flags.Parse(args); err != nil { return err } - l, err := encrypt.NewLockbox(encrypt.LockboxOptions{Key: *key, KeyMode: *keyMode, File: *file}) + l, err := encrypt.NewLockbox(encrypt.LockboxOptions{Key: *key, KeyMode: *keyMode, File: *file, Algorithm: *algo}) if err != nil { return err } diff --git a/internal/subcommands/rekey.go b/internal/subcommands/rekey.go @@ -17,6 +17,8 @@ func Rekey(args []string) error { outKey := flags.String("outkey", "", "output encryption key to update values with") inMode := flags.String("inmode", "", "input encryption key mode") outMode := flags.String("outmode", "", "output encryption key mode") + inAlgo := flags.String("inalgorithm", "", "input encryption algorithm") + outAlgo := flags.String("outalgorithm", "", "output encryption algorithm") if err := flags.Parse(args); err != nil { return err } @@ -24,8 +26,8 @@ func Rekey(args []string) error { if err != nil { return err } - inOpts := encrypt.LockboxOptions{Key: *inKey, KeyMode: *inMode} - outOpts := encrypt.LockboxOptions{Key: *outKey, KeyMode: *outMode} + inOpts := encrypt.LockboxOptions{Key: *inKey, KeyMode: *inMode, Algorithm: *inAlgo} + outOpts := encrypt.LockboxOptions{Key: *outKey, KeyMode: *outMode, Algorithm: *outAlgo} for _, file := range found { fmt.Printf("rekeying: %s\n", file) inOpts.File = file