feat: Add support for password-protected PGP keys
This commit is contained in:
@@ -43,6 +43,7 @@ const (
|
||||
|
||||
recipientFlag = "recipient"
|
||||
identityFlag = "identity"
|
||||
passwordFlag = "password"
|
||||
|
||||
compressionLevelFastest = "fastest"
|
||||
compressionLevelBalanced = "balanced"
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user