diff --git a/cmd/stbak/cmd/archive.go b/cmd/stbak/cmd/archive.go index 570ca04..ef4c326 100644 --- a/cmd/stbak/cmd/archive.go +++ b/cmd/stbak/cmd/archive.go @@ -43,6 +43,7 @@ const ( recipientFlag = "recipient" identityFlag = "identity" + passwordFlag = "password" compressionLevelFastest = "fastest" compressionLevelBalanced = "balanced" diff --git a/cmd/stbak/cmd/recovery_fetch.go b/cmd/stbak/cmd/recovery_fetch.go index e02715e..383d7da 100644 --- a/cmd/stbak/cmd/recovery_fetch.go +++ b/cmd/stbak/cmd/recovery_fetch.go @@ -75,6 +75,7 @@ var recoveryFetchCmd = &cobra.Command{ viper.GetString(compressionFlag), viper.GetString(encryptionFlag), privkey, + viper.GetString(passwordFlag), ) }, } @@ -90,6 +91,7 @@ func restoreFromRecordAndBlock( compressionFormat string, encryptionFormat string, privkey []byte, + password string, ) error { f, isRegular, err := openTapeReadOnly(tape) if err != nil { @@ -125,7 +127,7 @@ func restoreFromRecordAndBlock( return err } - if err := decryptHeader(hdr, encryptionFormat, privkey); err != nil { + if err := decryptHeader(hdr, encryptionFormat, privkey, password); err != nil { return err } @@ -166,7 +168,7 @@ func restoreFromRecordAndBlock( return nil } - decryptor, err := decrypt(tr, encryptionFormat, privkey) + decryptor, err := decrypt(tr, encryptionFormat, privkey, password) if err != nil { return err } @@ -244,6 +246,7 @@ func decryptHeader( hdr *tar.Header, encryptionFormat string, privkey []byte, + password string, ) error { if encryptionFormat == encryptionFormatNoneKey { return nil @@ -258,7 +261,7 @@ func decryptHeader( return errEmbeddedHeaderMissing } - embeddedHeader, err := decryptString(encryptedEmbeddedHeader, encryptionFormat, privkey) + embeddedHeader, err := decryptString(encryptedEmbeddedHeader, encryptionFormat, privkey, password) if err != nil { return err } @@ -277,6 +280,7 @@ func decryptString( src string, encryptionFormat string, privkey []byte, + password string, ) (string, error) { switch encryptionFormat { case encryptionFormatAgeKey: @@ -302,17 +306,31 @@ func decryptString( return out.String(), nil case encryptionFormatPGPKey: - identity, err := openpgp.ReadKeyRing(bytes.NewBuffer(privkey)) + identities, err := openpgp.ReadKeyRing(bytes.NewBuffer(privkey)) if err != nil { return "", err } + if password != "" { + for _, identity := range identities { + if err := identity.PrivateKey.Decrypt([]byte(password)); err != nil { + return "", err + } + + for _, subkey := range identity.Subkeys { + if err := subkey.PrivateKey.Decrypt([]byte(password)); err != nil { + return "", err + } + } + } + } + decoded, err := base64.StdEncoding.DecodeString(src) if err != nil { return "", err } - r, err := openpgp.ReadMessage(bytes.NewBufferString(string(decoded)), identity, nil, nil) + r, err := openpgp.ReadMessage(bytes.NewBufferString(string(decoded)), identities, nil, nil) if err != nil { return "", err } @@ -334,6 +352,7 @@ func decrypt( src io.Reader, encryptionFormat string, privkey []byte, + password string, ) (io.ReadCloser, error) { switch encryptionFormat { case encryptionFormatAgeKey: @@ -349,12 +368,26 @@ func decrypt( return io.NopCloser(r), nil case encryptionFormatPGPKey: - identity, err := openpgp.ReadKeyRing(bytes.NewBuffer(privkey)) + identities, err := openpgp.ReadKeyRing(bytes.NewBuffer(privkey)) if err != nil { return nil, err } - r, err := openpgp.ReadMessage(src, identity, nil, nil) + if password != "" { + for _, identity := range identities { + if err := identity.PrivateKey.Decrypt([]byte(password)); err != nil { + return nil, err + } + + for _, subkey := range identity.Subkeys { + if err := subkey.PrivateKey.Decrypt([]byte(password)); err != nil { + return nil, err + } + } + } + } + + r, err := openpgp.ReadMessage(src, identities, nil, nil) if err != nil { return nil, err } @@ -372,8 +405,9 @@ func init() { recoveryFetchCmd.PersistentFlags().IntP(recordFlag, "k", 0, "Record to seek too") recoveryFetchCmd.PersistentFlags().IntP(blockFlag, "b", 0, "Block in record to seek too") recoveryFetchCmd.PersistentFlags().StringP(dstFlag, "d", "", "File to restore to (archived name by default)") - recoveryFetchCmd.PersistentFlags().BoolP(previewFlag, "p", false, "Only read the header") + recoveryFetchCmd.PersistentFlags().BoolP(previewFlag, "w", false, "Only read the header") recoveryFetchCmd.PersistentFlags().StringP(identityFlag, "i", "", "Path to private key of recipient that has been encrypted for") + recoveryFetchCmd.PersistentFlags().StringP(passwordFlag, "p", "", "Password for the private key") viper.AutomaticEnv() diff --git a/cmd/stbak/cmd/recovery_index.go b/cmd/stbak/cmd/recovery_index.go index 5caea2e..f26c51e 100644 --- a/cmd/stbak/cmd/recovery_index.go +++ b/cmd/stbak/cmd/recovery_index.go @@ -58,7 +58,7 @@ var recoveryIndexCmd = &cobra.Command{ viper.GetString(encryptionFlag), privkey, func(hdr *tar.Header, encryptionFormat string, privkey []byte, i int) error { - return decryptHeader(hdr, encryptionFormat, privkey) + return decryptHeader(hdr, encryptionFormat, privkey, viper.GetString(passwordFlag)) }, 0, ) @@ -292,6 +292,7 @@ func init() { recoveryIndexCmd.PersistentFlags().IntP(blockFlag, "b", 0, "Block in record to seek too before counting") recoveryIndexCmd.PersistentFlags().BoolP(overwriteFlag, "o", false, "Remove the old index before starting to index") recoveryIndexCmd.PersistentFlags().StringP(identityFlag, "i", "", "Path to private key of recipient that has been encrypted for") + recoveryIndexCmd.PersistentFlags().StringP(passwordFlag, "p", "", "Password for the private key") viper.AutomaticEnv() diff --git a/cmd/stbak/cmd/recovery_query.go b/cmd/stbak/cmd/recovery_query.go index ae29ed6..3d5f588 100644 --- a/cmd/stbak/cmd/recovery_query.go +++ b/cmd/stbak/cmd/recovery_query.go @@ -46,6 +46,7 @@ var recoveryQueryCmd = &cobra.Command{ viper.GetInt(recordSizeFlag), viper.GetString(encryptionFlag), privkey, + viper.GetString(passwordFlag), ) }, } @@ -57,6 +58,7 @@ func query( recordSize int, encryptionFormat string, privkey []byte, + password string, ) error { f, isRegular, err := openTapeReadOnly(tape) if err != nil { @@ -124,7 +126,7 @@ func query( break } - if err := decryptHeader(hdr, encryptionFormat, privkey); err != nil { + if err := decryptHeader(hdr, encryptionFormat, privkey, password); err != nil { return err } @@ -207,7 +209,7 @@ func query( } } - if err := decryptHeader(hdr, encryptionFormat, privkey); err != nil { + if err := decryptHeader(hdr, encryptionFormat, privkey, password); err != nil { return err } @@ -246,6 +248,7 @@ func init() { recoveryQueryCmd.PersistentFlags().IntP(recordFlag, "k", 0, "Record to seek too before counting") recoveryQueryCmd.PersistentFlags().IntP(blockFlag, "b", 0, "Block in record to seek too before counting") recoveryQueryCmd.PersistentFlags().StringP(identityFlag, "i", "", "Path to private key of recipient that has been encrypted for") + recoveryQueryCmd.PersistentFlags().StringP(passwordFlag, "p", "", "Password for the private key") viper.AutomaticEnv() diff --git a/cmd/stbak/cmd/restore.go b/cmd/stbak/cmd/restore.go index b0b3197..50b7951 100644 --- a/cmd/stbak/cmd/restore.go +++ b/cmd/stbak/cmd/restore.go @@ -118,6 +118,7 @@ var restoreCmd = &cobra.Command{ viper.GetString(compressionFlag), viper.GetString(encryptionFlag), privkey, + viper.GetString(passwordFlag), ); err != nil { return err } @@ -133,6 +134,7 @@ func init() { restoreCmd.PersistentFlags().StringP(dstFlag, "d", "", "File or directory restore to (archived name by default)") restoreCmd.PersistentFlags().BoolP(flattenFlag, "f", false, "Ignore the folder hierarchy on the tape or tar file") restoreCmd.PersistentFlags().StringP(identityFlag, "i", "", "Path to private key of recipient that has been encrypted for") + restoreCmd.PersistentFlags().StringP(passwordFlag, "p", "", "Password for the private key") viper.AutomaticEnv()