From 1938e15eefde30969cdf967fb0b5b4f02348f246 Mon Sep 17 00:00:00 2001 From: Felicitas Pojtinger Date: Sat, 4 Dec 2021 15:20:04 +0100 Subject: [PATCH] refactor: Decompose and pull up identity parsing to `cmd`s --- cmd/stbak/cmd/archive.go | 3 +- cmd/stbak/cmd/recovery_fetch.go | 221 +++++++++++++++----------------- cmd/stbak/cmd/recovery_index.go | 16 ++- cmd/stbak/cmd/recovery_query.go | 15 ++- cmd/stbak/cmd/restore.go | 8 +- cmd/stbak/cmd/update.go | 3 +- 6 files changed, 132 insertions(+), 134 deletions(-) diff --git a/cmd/stbak/cmd/archive.go b/cmd/stbak/cmd/archive.go index 84bd97e..2f11a3f 100644 --- a/cmd/stbak/cmd/archive.go +++ b/cmd/stbak/cmd/archive.go @@ -133,8 +133,7 @@ var archiveCmd = &cobra.Command{ viper.GetBool(overwriteFlag), viper.GetString(compressionFlag), viper.GetString(encryptionFlag), - []byte{}, - func(hdr *tar.Header, encryptionFormat string, privkey []byte, i int) error { + func(hdr *tar.Header, encryptionFormat string, i int) error { if len(hdrs) <= i { return errMissingTarHeader } diff --git a/cmd/stbak/cmd/recovery_fetch.go b/cmd/stbak/cmd/recovery_fetch.go index 8be2a39..26231a4 100644 --- a/cmd/stbak/cmd/recovery_fetch.go +++ b/cmd/stbak/cmd/recovery_fetch.go @@ -38,6 +38,8 @@ const ( var ( errEmbeddedHeaderMissing = errors.New("embedded header is missing") + + errIdentityUnparsable = errors.New("recipient could not be parsed") ) var recoveryFetchCmd = &cobra.Command{ @@ -64,6 +66,11 @@ var recoveryFetchCmd = &cobra.Command{ return err } + identity, err := parseIdentity(viper.GetString(encryptionFlag), privkey, viper.GetString(passwordFlag)) + if err != nil { + return err + } + return restoreFromRecordAndBlock( viper.GetString(tapeFlag), viper.GetInt(recordSizeFlag), @@ -74,8 +81,7 @@ var recoveryFetchCmd = &cobra.Command{ true, viper.GetString(compressionFlag), viper.GetString(encryptionFlag), - privkey, - viper.GetString(passwordFlag), + identity, ) }, } @@ -90,8 +96,7 @@ func restoreFromRecordAndBlock( showHeader bool, compressionFormat string, encryptionFormat string, - privkey []byte, - password string, + identity interface{}, ) error { f, isRegular, err := openTapeReadOnly(tape) if err != nil { @@ -127,7 +132,7 @@ func restoreFromRecordAndBlock( return err } - if err := decryptHeader(hdr, encryptionFormat, privkey, password); err != nil { + if err := decryptHeader(hdr, encryptionFormat, identity); err != nil { return err } @@ -168,7 +173,7 @@ func restoreFromRecordAndBlock( return nil } - decryptor, err := decrypt(tr, encryptionFormat, privkey, password) + decryptor, err := decrypt(tr, encryptionFormat, identity) if err != nil { return err } @@ -245,8 +250,7 @@ func decompress( func decryptHeader( hdr *tar.Header, encryptionFormat string, - privkey []byte, - password string, + identity interface{}, ) error { if encryptionFormat == encryptionFormatNoneKey { return nil @@ -261,7 +265,7 @@ func decryptHeader( return errEmbeddedHeaderMissing } - embeddedHeader, err := decryptString(encryptedEmbeddedHeader, encryptionFormat, privkey, password) + embeddedHeader, err := decryptString(encryptedEmbeddedHeader, encryptionFormat, identity) if err != nil { return err } @@ -276,103 +280,11 @@ func decryptHeader( return nil } -func decryptString( - src string, +func parseIdentity( encryptionFormat string, privkey []byte, password string, -) (string, error) { - switch encryptionFormat { - case encryptionFormatAgeKey: - if password != "" { - passwordIdentity, err := age.NewScryptIdentity(password) - if err != nil { - return "", err - } - - r, err := age.Decrypt(bytes.NewBuffer(privkey), passwordIdentity) - if err != nil { - return "", err - } - - out := &bytes.Buffer{} - if _, err := io.Copy(out, r); err != nil { - return "", err - } - - privkey = out.Bytes() - } - - identity, err := age.ParseX25519Identity(string(privkey)) - if err != nil { - return "", err - } - - decoded, err := base64.StdEncoding.DecodeString(src) - if err != nil { - return "", err - } - - r, err := age.Decrypt(bytes.NewBufferString(string(decoded)), identity) - if err != nil { - return "", err - } - - out := &bytes.Buffer{} - if _, err := io.Copy(out, r); err != nil { - return "", err - } - - return out.String(), nil - case encryptionFormatPGPKey: - 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)), identities, nil, nil) - if err != nil { - return "", err - } - - out := &bytes.Buffer{} - if _, err := io.Copy(out, r.UnverifiedBody); err != nil { - return "", err - } - - return out.String(), nil - case encryptionFormatNoneKey: - return src, nil - default: - return "", errUnsupportedEncryptionFormat - } -} - -func decrypt( - src io.Reader, - encryptionFormat string, - privkey []byte, - password string, -) (io.ReadCloser, error) { +) (interface{}, error) { switch encryptionFormat { case encryptionFormatAgeKey: if password != "" { @@ -394,17 +306,7 @@ func decrypt( privkey = out.Bytes() } - identity, err := age.ParseX25519Identity(string(privkey)) - if err != nil { - return nil, err - } - - r, err := age.Decrypt(src, identity) - if err != nil { - return nil, err - } - - return io.NopCloser(r), nil + return age.ParseX25519Identity(string(privkey)) case encryptionFormatPGPKey: identities, err := openpgp.ReadKeyRing(bytes.NewBuffer(privkey)) if err != nil { @@ -425,7 +327,96 @@ func decrypt( } } - r, err := openpgp.ReadMessage(src, identities, nil, nil) + return identities, nil + case encryptionFormatNoneKey: + return privkey, nil + default: + return nil, errUnsupportedEncryptionFormat + } +} + +func decryptString( + src string, + encryptionFormat string, + identity interface{}, +) (string, error) { + switch encryptionFormat { + case encryptionFormatAgeKey: + identity, ok := identity.(*age.X25519Identity) + if !ok { + return "", errIdentityUnparsable + } + + decoded, err := base64.StdEncoding.DecodeString(src) + if err != nil { + return "", err + } + + r, err := age.Decrypt(bytes.NewBufferString(string(decoded)), identity) + if err != nil { + return "", err + } + + out := &bytes.Buffer{} + if _, err := io.Copy(out, r); err != nil { + return "", err + } + + return out.String(), nil + case encryptionFormatPGPKey: + identity, ok := identity.(openpgp.EntityList) + if !ok { + return "", errIdentityUnparsable + } + + decoded, err := base64.StdEncoding.DecodeString(src) + if err != nil { + return "", err + } + + r, err := openpgp.ReadMessage(bytes.NewBufferString(string(decoded)), identity, nil, nil) + if err != nil { + return "", err + } + + out := &bytes.Buffer{} + if _, err := io.Copy(out, r.UnverifiedBody); err != nil { + return "", err + } + + return out.String(), nil + case encryptionFormatNoneKey: + return src, nil + default: + return "", errUnsupportedEncryptionFormat + } +} + +func decrypt( + src io.Reader, + encryptionFormat string, + identity interface{}, +) (io.ReadCloser, error) { + switch encryptionFormat { + case encryptionFormatAgeKey: + identity, ok := identity.(*age.X25519Identity) + if !ok { + return nil, errIdentityUnparsable + } + + r, err := age.Decrypt(src, identity) + if err != nil { + return nil, err + } + + return io.NopCloser(r), nil + case encryptionFormatPGPKey: + identity, ok := identity.(openpgp.EntityList) + if !ok { + return nil, errIdentityUnparsable + } + + r, err := openpgp.ReadMessage(src, identity, nil, nil) if err != nil { return nil, err } diff --git a/cmd/stbak/cmd/recovery_index.go b/cmd/stbak/cmd/recovery_index.go index f26c51e..1a827f1 100644 --- a/cmd/stbak/cmd/recovery_index.go +++ b/cmd/stbak/cmd/recovery_index.go @@ -47,6 +47,11 @@ var recoveryIndexCmd = &cobra.Command{ return err } + identity, err := parseIdentity(viper.GetString(encryptionFlag), privkey, viper.GetString(passwordFlag)) + if err != nil { + return err + } + return index( viper.GetString(tapeFlag), viper.GetString(metadataFlag), @@ -56,9 +61,8 @@ var recoveryIndexCmd = &cobra.Command{ viper.GetBool(overwriteFlag), viper.GetString(compressionFlag), viper.GetString(encryptionFlag), - privkey, - func(hdr *tar.Header, encryptionFormat string, privkey []byte, i int) error { - return decryptHeader(hdr, encryptionFormat, privkey, viper.GetString(passwordFlag)) + func(hdr *tar.Header, encryptionFormat string, i int) error { + return decryptHeader(hdr, encryptionFormat, identity) }, 0, ) @@ -74,11 +78,9 @@ func index( overwrite bool, compressionFormat string, encryptionFormat string, - privkey []byte, decryptHeader func( hdr *tar.Header, encryptionFormat string, - privkey []byte, i int, ) error, offset int, @@ -171,7 +173,7 @@ func index( } if i >= offset { - if err := decryptHeader(hdr, encryptionFormat, privkey, i-offset); err != nil { + if err := decryptHeader(hdr, encryptionFormat, i-offset); err != nil { return err } @@ -253,7 +255,7 @@ func index( } if i >= offset { - if err := decryptHeader(hdr, encryptionFormat, privkey, i-offset); err != nil { + if err := decryptHeader(hdr, encryptionFormat, i-offset); err != nil { return err } diff --git a/cmd/stbak/cmd/recovery_query.go b/cmd/stbak/cmd/recovery_query.go index 3d5f588..a02afb3 100644 --- a/cmd/stbak/cmd/recovery_query.go +++ b/cmd/stbak/cmd/recovery_query.go @@ -39,14 +39,18 @@ var recoveryQueryCmd = &cobra.Command{ return err } + identity, err := parseIdentity(viper.GetString(encryptionFlag), privkey, viper.GetString(passwordFlag)) + if err != nil { + return err + } + return query( viper.GetString(tapeFlag), viper.GetInt(recordFlag), viper.GetInt(blockFlag), viper.GetInt(recordSizeFlag), viper.GetString(encryptionFlag), - privkey, - viper.GetString(passwordFlag), + identity, ) }, } @@ -57,8 +61,7 @@ func query( block int, recordSize int, encryptionFormat string, - privkey []byte, - password string, + identity interface{}, ) error { f, isRegular, err := openTapeReadOnly(tape) if err != nil { @@ -126,7 +129,7 @@ func query( break } - if err := decryptHeader(hdr, encryptionFormat, privkey, password); err != nil { + if err := decryptHeader(hdr, encryptionFormat, identity); err != nil { return err } @@ -209,7 +212,7 @@ func query( } } - if err := decryptHeader(hdr, encryptionFormat, privkey, password); err != nil { + if err := decryptHeader(hdr, encryptionFormat, identity); err != nil { return err } diff --git a/cmd/stbak/cmd/restore.go b/cmd/stbak/cmd/restore.go index 50b7951..30ee1b8 100644 --- a/cmd/stbak/cmd/restore.go +++ b/cmd/stbak/cmd/restore.go @@ -51,6 +51,11 @@ var restoreCmd = &cobra.Command{ return err } + identity, err := parseIdentity(viper.GetString(encryptionFlag), privkey, viper.GetString(passwordFlag)) + if err != nil { + return err + } + headersToRestore := []*models.Header{} src := strings.TrimSuffix(viper.GetString(srcFlag), "/") dbhdr, err := metadataPersister.GetHeader(context.Background(), src) @@ -117,8 +122,7 @@ var restoreCmd = &cobra.Command{ false, viper.GetString(compressionFlag), viper.GetString(encryptionFlag), - privkey, - viper.GetString(passwordFlag), + identity, ); err != nil { return err } diff --git a/cmd/stbak/cmd/update.go b/cmd/stbak/cmd/update.go index cba8554..adb8804 100644 --- a/cmd/stbak/cmd/update.go +++ b/cmd/stbak/cmd/update.go @@ -88,8 +88,7 @@ var updateCmd = &cobra.Command{ false, viper.GetString(compressionFlag), viper.GetString(encryptionFlag), - []byte{}, - func(hdr *tar.Header, encryptionFormat string, privkey []byte, i int) error { + func(hdr *tar.Header, encryptionFormat string, i int) error { if len(hdrs) <= i { return errMissingTarHeader }