feat: add a new subcommand - encrypt (#16)
This commit is contained in:
parent
f59e1db9a8
commit
7632df40da
|
@ -22,7 +22,7 @@ const (
|
|||
minIterations = 140000
|
||||
)
|
||||
|
||||
func Encrypt(password, plaintext []byte) ([]byte, error) {
|
||||
func Encrypt(plaintext, password []byte) ([]byte, error) {
|
||||
iter := make([]byte, iterationLen)
|
||||
iv := make([]byte, ivLen)
|
||||
salt := make([]byte, saltLen)
|
||||
|
@ -74,7 +74,7 @@ func randIterations() (int, error) {
|
|||
return int(iterations.Int64() + minIterations), nil
|
||||
}
|
||||
|
||||
func Decrypt(password, text []byte) ([]byte, error) {
|
||||
func Decrypt(text, password []byte) ([]byte, error) {
|
||||
iterations := text[:iterationLen]
|
||||
salt := text[iterationLen : iterationLen+saltLen]
|
||||
iv := text[iterationLen+saltLen : iterationLen+saltLen+ivLen]
|
||||
|
@ -112,8 +112,8 @@ type Entry struct {
|
|||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
func DecryptAsEntries(password, text []byte) ([]Entry, error) {
|
||||
result, err := Decrypt(password, text)
|
||||
func DecryptAsEntries(text, password []byte) ([]Entry, error) {
|
||||
result, err := Decrypt(text, password)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decrypt: %w", err)
|
||||
}
|
||||
|
|
|
@ -28,17 +28,17 @@ func TestEncryptDecrypt(t *testing.T) {
|
|||
assert.Nil(t, err)
|
||||
password := []byte("password22231")
|
||||
|
||||
encrypted, err := internal.Encrypt(password, entriesJSON)
|
||||
encrypted, err := internal.Encrypt(entriesJSON, password)
|
||||
assert.Nil(t, err)
|
||||
|
||||
decrypted, err := internal.Decrypt(password, encrypted)
|
||||
decrypted, err := internal.Decrypt(encrypted, password)
|
||||
assert.Nil(t, err)
|
||||
var result []internal.Entry
|
||||
err = json.Unmarshal(decrypted, &result)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, entries, result)
|
||||
|
||||
decryptedEntries, err := internal.DecryptAsEntries(password, encrypted)
|
||||
decryptedEntries, err := internal.DecryptAsEntries(encrypted, password)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, entries, decryptedEntries)
|
||||
}
|
||||
|
|
101
main.go
101
main.go
|
@ -37,11 +37,7 @@ func newApp() (*cli.App, error) {
|
|||
Usage: "2FA App compatible with andOTP backup file format",
|
||||
Version: Version,
|
||||
Action: func(c *cli.Context) error {
|
||||
var err error
|
||||
password := []byte(c.String("password"))
|
||||
if len(password) == 0 {
|
||||
password, err = readPasswordFromStdin()
|
||||
}
|
||||
password, err := getPassword(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -51,7 +47,7 @@ func newApp() (*cli.App, error) {
|
|||
return fmt.Errorf("something went wrong while reading file: %w", err)
|
||||
}
|
||||
|
||||
entries, err := internal.DecryptAsEntries(password, b)
|
||||
entries, err := internal.DecryptAsEntries(b, password)
|
||||
if err != nil {
|
||||
return fmt.Errorf("something went wrong while decrypting file: %w", err)
|
||||
}
|
||||
|
@ -67,7 +63,7 @@ func newApp() (*cli.App, error) {
|
|||
&cli.StringFlag{
|
||||
Name: "path",
|
||||
Aliases: []string{"p"},
|
||||
Usage: "path to andotp backup file",
|
||||
Usage: "path to andOTP backup file",
|
||||
Required: false,
|
||||
DefaultText: "$HOME/.otp_accounts.json",
|
||||
Value: path.Join(dirname, ".otp_accounts.json"),
|
||||
|
@ -80,6 +76,7 @@ func newApp() (*cli.App, error) {
|
|||
},
|
||||
EnableBashCompletion: true,
|
||||
Commands: []*cli.Command{
|
||||
newEncryptCommand(),
|
||||
newDecryptCommand(),
|
||||
},
|
||||
}, nil
|
||||
|
@ -87,39 +84,9 @@ func newApp() (*cli.App, error) {
|
|||
|
||||
func newDecryptCommand() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "decrypt",
|
||||
Usage: "Decrypts backup file generated by andotp",
|
||||
Action: func(c *cli.Context) error {
|
||||
var err error
|
||||
password := []byte(c.String("password"))
|
||||
if len(password) == 0 {
|
||||
password, err = readPasswordFromStdin()
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := os.ReadFile(c.String("path"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("something went wrong while reading file: %w", err)
|
||||
}
|
||||
|
||||
result, err := internal.Decrypt(password, b)
|
||||
if err != nil {
|
||||
return fmt.Errorf("something went wrong while decrypting file: %w", err)
|
||||
}
|
||||
|
||||
output := c.String("output")
|
||||
if output != "" {
|
||||
if err := os.WriteFile(output, result, 0600); err != nil {
|
||||
return fmt.Errorf("something went wrong while saving file: %w", err)
|
||||
}
|
||||
} else {
|
||||
fmt.Print(string(result))
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
Name: "decrypt",
|
||||
Usage: "Decrypts the specified backup file",
|
||||
Action: newEncryptDecryptActionFunc(internal.Decrypt),
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "output",
|
||||
|
@ -131,6 +98,60 @@ func newDecryptCommand() *cli.Command {
|
|||
}
|
||||
}
|
||||
|
||||
func newEncryptCommand() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "encrypt",
|
||||
Usage: "Encrypts the specified file file using AES-256",
|
||||
Action: newEncryptDecryptActionFunc(internal.Encrypt),
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "output",
|
||||
Usage: "Write to file instead of stdout",
|
||||
Aliases: []string{"o"},
|
||||
Required: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func newEncryptDecryptActionFunc(fn func(text, password []byte) ([]byte, error)) cli.ActionFunc {
|
||||
return func(c *cli.Context) error {
|
||||
password, err := getPassword(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := os.ReadFile(c.String("path"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("something went wrong while reading file: %w", err)
|
||||
}
|
||||
|
||||
result, err := fn(b, password)
|
||||
if err != nil {
|
||||
return fmt.Errorf("something went wrong while processing file: %w", err)
|
||||
}
|
||||
|
||||
output := c.String("output")
|
||||
if output != "" {
|
||||
if err := os.WriteFile(output, result, 0600); err != nil {
|
||||
return fmt.Errorf("something went wrong while saving result: %w", err)
|
||||
}
|
||||
} else {
|
||||
fmt.Print(string(result))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func getPassword(c *cli.Context) ([]byte, error) {
|
||||
password := []byte(c.String("password"))
|
||||
if len(password) == 0 {
|
||||
return readPasswordFromStdin()
|
||||
}
|
||||
return password, nil
|
||||
}
|
||||
|
||||
func readPasswordFromStdin() ([]byte, error) {
|
||||
fmt.Print("Password: ")
|
||||
|
||||
|
|
Reference in New Issue