encryption: re-use same IVs so that the ciphertext doesn't change when decrypting and reencrypting

Signed-off-by: Andrea Luzzardi <aluzzardi@gmail.com>
This commit is contained in:
Andrea Luzzardi 2021-05-21 16:16:56 -07:00
parent 90abadf0de
commit f374f4c5ea

View File

@ -4,18 +4,21 @@ import (
"context" "context"
"fmt" "fmt"
"os" "os"
"time"
"go.mozilla.org/sops/v3" "go.mozilla.org/sops/v3"
"go.mozilla.org/sops/v3/aes" sopsaes "go.mozilla.org/sops/v3/aes"
sopsage "go.mozilla.org/sops/v3/age" sopsage "go.mozilla.org/sops/v3/age"
"go.mozilla.org/sops/v3/cmd/sops/common" "go.mozilla.org/sops/v3/cmd/sops/common"
"go.mozilla.org/sops/v3/cmd/sops/formats"
sopsdecrypt "go.mozilla.org/sops/v3/decrypt"
sopskeys "go.mozilla.org/sops/v3/keys" sopskeys "go.mozilla.org/sops/v3/keys"
sopsyaml "go.mozilla.org/sops/v3/stores/yaml" sopsyaml "go.mozilla.org/sops/v3/stores/yaml"
"go.mozilla.org/sops/v3/version" "go.mozilla.org/sops/v3/version"
) )
var (
cipher = sopsaes.NewCipher()
)
// setupEnv: hack to inject a SOPS env var for age // setupEnv: hack to inject a SOPS env var for age
func setupEnv() error { func setupEnv() error {
p, err := Path() p, err := Path()
@ -65,7 +68,7 @@ func Encrypt(ctx context.Context, path string, plaintext []byte, key string) ([]
} }
err = common.EncryptTree(common.EncryptTreeOpts{ err = common.EncryptTree(common.EncryptTreeOpts{
DataKey: dataKey, Tree: &tree, Cipher: aes.NewCipher(), DataKey: dataKey, Tree: &tree, Cipher: cipher,
}) })
if err != nil { if err != nil {
return nil, err return nil, err
@ -104,7 +107,7 @@ func Reencrypt(_ context.Context, path string, plaintext []byte) ([]byte, error)
return nil, err return nil, err
} }
err = common.EncryptTree(common.EncryptTreeOpts{ err = common.EncryptTree(common.EncryptTreeOpts{
DataKey: key, Tree: &tree, Cipher: aes.NewCipher(), DataKey: key, Tree: &tree, Cipher: cipher,
}) })
if err != nil { if err != nil {
return nil, err return nil, err
@ -119,5 +122,38 @@ func Decrypt(_ context.Context, encrypted []byte) ([]byte, error) {
return nil, err return nil, err
} }
return sopsdecrypt.DataWithFormat(encrypted, formats.Yaml) store := &sopsyaml.Store{}
// Load SOPS file and access the data key
tree, err := store.LoadEncryptedFile(encrypted)
if err != nil {
return nil, err
}
key, err := tree.Metadata.GetDataKey()
if err != nil {
return nil, err
}
// Decrypt the tree
mac, err := tree.Decrypt(key, cipher)
if err != nil {
return nil, err
}
// Compute the hash of the cleartext tree and compare it with
// the one that was stored in the document. If they match,
// integrity was preserved
originalMac, err := cipher.Decrypt(
tree.Metadata.MessageAuthenticationCode,
key,
tree.Metadata.LastModified.Format(time.RFC3339),
)
if err != nil {
return nil, err
}
if originalMac != mac {
return nil, fmt.Errorf("failed to verify data integrity. expected mac %q, got %q", originalMac, mac)
}
return store.EmitPlainFile(tree.Branches)
} }