зеркало из https://github.com/getsops/sops.git
Support computing MAC only over values which end up encrypted
Signed-off-by: Mitar <mitar.git@tnode.com>
This commit is contained in:
Родитель
73ec51f982
Коммит
051ce028c9
|
@ -1427,6 +1427,9 @@ to any key of a file. When set, all values underneath the key that set the
|
||||||
Note that, while in cleartext, unencrypted content is still added to the
|
Note that, while in cleartext, unencrypted content is still added to the
|
||||||
checksum of the file, and thus cannot be modified outside of SOPS without
|
checksum of the file, and thus cannot be modified outside of SOPS without
|
||||||
breaking the file integrity check.
|
breaking the file integrity check.
|
||||||
|
This behavior can be modified using ``--mac-only-encrypted`` flag or ``.sops.yaml``
|
||||||
|
config file which makes SOPS compute a MAC only over values it encrypted and
|
||||||
|
not all values.
|
||||||
|
|
||||||
The unencrypted suffix can be set to a different value using the
|
The unencrypted suffix can be set to a different value using the
|
||||||
``--unencrypted-suffix`` option.
|
``--unencrypted-suffix`` option.
|
||||||
|
@ -1539,6 +1542,9 @@ In addition to authenticating branches of the tree using keys as additional
|
||||||
data, SOPS computes a MAC on all the values to ensure that no value has been
|
data, SOPS computes a MAC on all the values to ensure that no value has been
|
||||||
added or removed fraudulently. The MAC is stored encrypted with AES_GCM and
|
added or removed fraudulently. The MAC is stored encrypted with AES_GCM and
|
||||||
the data key under tree -> ``sops`` -> ``mac``.
|
the data key under tree -> ``sops`` -> ``mac``.
|
||||||
|
This behavior can be modified using ``--mac-only-encrypted`` flag or ``.sops.yaml``
|
||||||
|
config file which makes SOPS compute a MAC only over values it encrypted and
|
||||||
|
not all values.
|
||||||
|
|
||||||
Motivation
|
Motivation
|
||||||
----------
|
----------
|
||||||
|
|
|
@ -35,6 +35,7 @@ type editExampleOpts struct {
|
||||||
EncryptedSuffix string
|
EncryptedSuffix string
|
||||||
UnencryptedRegex string
|
UnencryptedRegex string
|
||||||
EncryptedRegex string
|
EncryptedRegex string
|
||||||
|
MACOnlyEncrypted bool
|
||||||
KeyGroups []sops.KeyGroup
|
KeyGroups []sops.KeyGroup
|
||||||
GroupThreshold int
|
GroupThreshold int
|
||||||
}
|
}
|
||||||
|
@ -65,6 +66,7 @@ func editExample(opts editExampleOpts) ([]byte, error) {
|
||||||
EncryptedSuffix: opts.EncryptedSuffix,
|
EncryptedSuffix: opts.EncryptedSuffix,
|
||||||
UnencryptedRegex: opts.UnencryptedRegex,
|
UnencryptedRegex: opts.UnencryptedRegex,
|
||||||
EncryptedRegex: opts.EncryptedRegex,
|
EncryptedRegex: opts.EncryptedRegex,
|
||||||
|
MACOnlyEncrypted: opts.MACOnlyEncrypted,
|
||||||
Version: version.Version,
|
Version: version.Version,
|
||||||
ShamirThreshold: opts.GroupThreshold,
|
ShamirThreshold: opts.GroupThreshold,
|
||||||
},
|
},
|
||||||
|
|
|
@ -23,6 +23,7 @@ type encryptOpts struct {
|
||||||
EncryptedSuffix string
|
EncryptedSuffix string
|
||||||
UnencryptedRegex string
|
UnencryptedRegex string
|
||||||
EncryptedRegex string
|
EncryptedRegex string
|
||||||
|
MACOnlyEncrypted bool
|
||||||
KeyGroups []sops.KeyGroup
|
KeyGroups []sops.KeyGroup
|
||||||
GroupThreshold int
|
GroupThreshold int
|
||||||
}
|
}
|
||||||
|
@ -82,6 +83,7 @@ func encrypt(opts encryptOpts) (encryptedFile []byte, err error) {
|
||||||
EncryptedSuffix: opts.EncryptedSuffix,
|
EncryptedSuffix: opts.EncryptedSuffix,
|
||||||
UnencryptedRegex: opts.UnencryptedRegex,
|
UnencryptedRegex: opts.UnencryptedRegex,
|
||||||
EncryptedRegex: opts.EncryptedRegex,
|
EncryptedRegex: opts.EncryptedRegex,
|
||||||
|
MACOnlyEncrypted: opts.MACOnlyEncrypted,
|
||||||
Version: version.Version,
|
Version: version.Version,
|
||||||
ShamirThreshold: opts.GroupThreshold,
|
ShamirThreshold: opts.GroupThreshold,
|
||||||
},
|
},
|
||||||
|
|
|
@ -668,6 +668,10 @@ func main() {
|
||||||
Name: "ignore-mac",
|
Name: "ignore-mac",
|
||||||
Usage: "ignore Message Authentication Code during decryption",
|
Usage: "ignore Message Authentication Code during decryption",
|
||||||
},
|
},
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "mac-only-encrypted",
|
||||||
|
Usage: "compute MAC only over values which end up encrypted",
|
||||||
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "unencrypted-suffix",
|
Name: "unencrypted-suffix",
|
||||||
Usage: "override the unencrypted key suffix.",
|
Usage: "override the unencrypted key suffix.",
|
||||||
|
@ -738,6 +742,7 @@ func main() {
|
||||||
encryptedSuffix := c.String("encrypted-suffix")
|
encryptedSuffix := c.String("encrypted-suffix")
|
||||||
encryptedRegex := c.String("encrypted-regex")
|
encryptedRegex := c.String("encrypted-regex")
|
||||||
unencryptedRegex := c.String("unencrypted-regex")
|
unencryptedRegex := c.String("unencrypted-regex")
|
||||||
|
macOnlyEncrypted := c.Bool("mac-only-encrypted")
|
||||||
conf, err := loadConfig(c, fileName, nil)
|
conf, err := loadConfig(c, fileName, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return toExitError(err)
|
return toExitError(err)
|
||||||
|
@ -756,6 +761,9 @@ func main() {
|
||||||
if unencryptedRegex == "" {
|
if unencryptedRegex == "" {
|
||||||
unencryptedRegex = conf.UnencryptedRegex
|
unencryptedRegex = conf.UnencryptedRegex
|
||||||
}
|
}
|
||||||
|
if !macOnlyEncrypted {
|
||||||
|
macOnlyEncrypted = conf.MACOnlyEncrypted
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cryptRuleCount := 0
|
cryptRuleCount := 0
|
||||||
|
@ -806,6 +814,7 @@ func main() {
|
||||||
EncryptedSuffix: encryptedSuffix,
|
EncryptedSuffix: encryptedSuffix,
|
||||||
UnencryptedRegex: unencryptedRegex,
|
UnencryptedRegex: unencryptedRegex,
|
||||||
EncryptedRegex: encryptedRegex,
|
EncryptedRegex: encryptedRegex,
|
||||||
|
MACOnlyEncrypted: macOnlyEncrypted,
|
||||||
KeyServices: svcs,
|
KeyServices: svcs,
|
||||||
KeyGroups: groups,
|
KeyGroups: groups,
|
||||||
GroupThreshold: threshold,
|
GroupThreshold: threshold,
|
||||||
|
@ -963,6 +972,7 @@ func main() {
|
||||||
EncryptedSuffix: encryptedSuffix,
|
EncryptedSuffix: encryptedSuffix,
|
||||||
UnencryptedRegex: unencryptedRegex,
|
UnencryptedRegex: unencryptedRegex,
|
||||||
EncryptedRegex: encryptedRegex,
|
EncryptedRegex: encryptedRegex,
|
||||||
|
MACOnlyEncrypted: macOnlyEncrypted,
|
||||||
KeyGroups: groups,
|
KeyGroups: groups,
|
||||||
GroupThreshold: threshold,
|
GroupThreshold: threshold,
|
||||||
})
|
})
|
||||||
|
|
|
@ -123,6 +123,7 @@ type creationRule struct {
|
||||||
EncryptedSuffix string `yaml:"encrypted_suffix"`
|
EncryptedSuffix string `yaml:"encrypted_suffix"`
|
||||||
UnencryptedRegex string `yaml:"unencrypted_regex"`
|
UnencryptedRegex string `yaml:"unencrypted_regex"`
|
||||||
EncryptedRegex string `yaml:"encrypted_regex"`
|
EncryptedRegex string `yaml:"encrypted_regex"`
|
||||||
|
MACOnlyEncrypted bool `yaml:"mac_only_encrypted"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load loads a sops config file into a temporary struct
|
// Load loads a sops config file into a temporary struct
|
||||||
|
@ -142,6 +143,7 @@ type Config struct {
|
||||||
EncryptedSuffix string
|
EncryptedSuffix string
|
||||||
UnencryptedRegex string
|
UnencryptedRegex string
|
||||||
EncryptedRegex string
|
EncryptedRegex string
|
||||||
|
MACOnlyEncrypted bool
|
||||||
Destination publish.Destination
|
Destination publish.Destination
|
||||||
OmitExtensions bool
|
OmitExtensions bool
|
||||||
}
|
}
|
||||||
|
@ -265,6 +267,7 @@ func configFromRule(rule *creationRule, kmsEncryptionContext map[string]*string)
|
||||||
EncryptedSuffix: rule.EncryptedSuffix,
|
EncryptedSuffix: rule.EncryptedSuffix,
|
||||||
UnencryptedRegex: rule.UnencryptedRegex,
|
UnencryptedRegex: rule.UnencryptedRegex,
|
||||||
EncryptedRegex: rule.EncryptedRegex,
|
EncryptedRegex: rule.EncryptedRegex,
|
||||||
|
MACOnlyEncrypted: rule.MACOnlyEncrypted,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -158,6 +158,14 @@ creation_rules:
|
||||||
unencrypted_regex: "^dec:"
|
unencrypted_regex: "^dec:"
|
||||||
`)
|
`)
|
||||||
|
|
||||||
|
var sampleConfigWithMACOnlyEncrypted = []byte(`
|
||||||
|
creation_rules:
|
||||||
|
- path_regex: barbar*
|
||||||
|
kms: "1"
|
||||||
|
pgp: "2"
|
||||||
|
mac_only_encrypted: true
|
||||||
|
`)
|
||||||
|
|
||||||
var sampleConfigWithInvalidParameters = []byte(`
|
var sampleConfigWithInvalidParameters = []byte(`
|
||||||
creation_rules:
|
creation_rules:
|
||||||
- path_regex: foobar*
|
- path_regex: foobar*
|
||||||
|
@ -416,6 +424,12 @@ func TestLoadConfigFileWithEncryptedRegex(t *testing.T) {
|
||||||
assert.Equal(t, "^enc:", conf.EncryptedRegex)
|
assert.Equal(t, "^enc:", conf.EncryptedRegex)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLoadConfigFileWithMACOnlyEncrypted(t *testing.T) {
|
||||||
|
conf, err := parseCreationRuleForFile(parseConfigFile(sampleConfigWithMACOnlyEncrypted, t), "/conf/path", "barbar", nil)
|
||||||
|
assert.Equal(t, nil, err)
|
||||||
|
assert.Equal(t, true, conf.MACOnlyEncrypted)
|
||||||
|
}
|
||||||
|
|
||||||
func TestLoadConfigFileWithInvalidParameters(t *testing.T) {
|
func TestLoadConfigFileWithInvalidParameters(t *testing.T) {
|
||||||
_, err := parseCreationRuleForFile(parseConfigFile(sampleConfigWithInvalidParameters, t), "/conf/path", "foobar", nil)
|
_, err := parseCreationRuleForFile(parseConfigFile(sampleConfigWithInvalidParameters, t), "/conf/path", "foobar", nil)
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
|
|
57
sops.go
57
sops.go
|
@ -70,6 +70,12 @@ const MacMismatch = sopsError("MAC mismatch")
|
||||||
// MetadataNotFound occurs when the input file is malformed and doesn't have sops metadata in it
|
// MetadataNotFound occurs when the input file is malformed and doesn't have sops metadata in it
|
||||||
const MetadataNotFound = sopsError("sops metadata not found")
|
const MetadataNotFound = sopsError("sops metadata not found")
|
||||||
|
|
||||||
|
// MACOnlyEncryptedInitialization is a constant and known sequence of 32 bytes used to initialize
|
||||||
|
// MAC which is computed only over values which end up encrypted. That assures that a MAC with the
|
||||||
|
// setting enabled is always different from a MAC with this setting disabled.
|
||||||
|
// The following numbers are taken from the output of `echo -n sops | sha256sum` (shell) or `hashlib.sha256(b'sops').hexdigest()` (Python).
|
||||||
|
var MACOnlyEncryptedInitialization = []byte{0x8a, 0x3f, 0xd2, 0xad, 0x54, 0xce, 0x66, 0x52, 0x7b, 0x10, 0x34, 0xf3, 0xd1, 0x47, 0xbe, 0xb, 0xb, 0x97, 0x5b, 0x3b, 0xf4, 0x4f, 0x72, 0xc6, 0xfd, 0xad, 0xec, 0x81, 0x76, 0xf2, 0x7d, 0x69}
|
||||||
|
|
||||||
var log *logrus.Logger
|
var log *logrus.Logger
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -291,22 +297,21 @@ func (branch TreeBranch) walkBranch(in TreeBranch, path []string, onLeaves func(
|
||||||
// is provided (by default it is not), those not matching EncryptedRegex,
|
// is provided (by default it is not), those not matching EncryptedRegex,
|
||||||
// if EncryptedRegex is provided (by default it is not) or those matching
|
// if EncryptedRegex is provided (by default it is not) or those matching
|
||||||
// UnencryptedRegex, if UnencryptedRegex is provided (by default it is not).
|
// UnencryptedRegex, if UnencryptedRegex is provided (by default it is not).
|
||||||
// If encryption is successful, it returns the MAC for the encrypted tree.
|
// If encryption is successful, it returns the MAC for the encrypted tree
|
||||||
|
// (all values if MACOnlyEncrypted is false, or only over values which end
|
||||||
|
// up encrypted if MACOnlyEncrypted is true).
|
||||||
func (tree Tree) Encrypt(key []byte, cipher Cipher) (string, error) {
|
func (tree Tree) Encrypt(key []byte, cipher Cipher) (string, error) {
|
||||||
audit.SubmitEvent(audit.EncryptEvent{
|
audit.SubmitEvent(audit.EncryptEvent{
|
||||||
File: tree.FilePath,
|
File: tree.FilePath,
|
||||||
})
|
})
|
||||||
hash := sha512.New()
|
hash := sha512.New()
|
||||||
|
if tree.Metadata.MACOnlyEncrypted {
|
||||||
|
// We initialize with known set of bytes so that a MAC with this setting
|
||||||
|
// enabled is always different from a MAC with this setting disabled.
|
||||||
|
hash.Write(MACOnlyEncryptedInitialization)
|
||||||
|
}
|
||||||
walk := func(branch TreeBranch) error {
|
walk := func(branch TreeBranch) error {
|
||||||
_, err := branch.walkBranch(branch, make([]string, 0), func(in interface{}, path []string) (interface{}, error) {
|
_, err := branch.walkBranch(branch, make([]string, 0), func(in interface{}, path []string) (interface{}, error) {
|
||||||
// Only add to MAC if not a comment
|
|
||||||
if _, ok := in.(Comment); !ok {
|
|
||||||
bytes, err := ToBytes(in)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Could not convert %s to bytes: %s", in, err)
|
|
||||||
}
|
|
||||||
hash.Write(bytes)
|
|
||||||
}
|
|
||||||
encrypted := true
|
encrypted := true
|
||||||
if tree.Metadata.UnencryptedSuffix != "" {
|
if tree.Metadata.UnencryptedSuffix != "" {
|
||||||
for _, v := range path {
|
for _, v := range path {
|
||||||
|
@ -344,6 +349,16 @@ func (tree Tree) Encrypt(key []byte, cipher Cipher) (string, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if !tree.Metadata.MACOnlyEncrypted || encrypted {
|
||||||
|
// Only add to MAC if not a comment
|
||||||
|
if _, ok := in.(Comment); !ok {
|
||||||
|
bytes, err := ToBytes(in)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Could not convert %s to bytes: %s", in, err)
|
||||||
|
}
|
||||||
|
hash.Write(bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
if encrypted {
|
if encrypted {
|
||||||
var err error
|
var err error
|
||||||
pathString := strings.Join(path, ":") + ":"
|
pathString := strings.Join(path, ":") + ":"
|
||||||
|
@ -371,13 +386,20 @@ func (tree Tree) Encrypt(key []byte, cipher Cipher) (string, error) {
|
||||||
// those not ending with EncryptedSuffix, if EncryptedSuffix is provided (by default it is not),
|
// those not ending with EncryptedSuffix, if EncryptedSuffix is provided (by default it is not),
|
||||||
// those not matching EncryptedRegex, if EncryptedRegex is provided (by default it is not),
|
// those not matching EncryptedRegex, if EncryptedRegex is provided (by default it is not),
|
||||||
// or those matching UnencryptedRegex, if UnencryptedRegex is provided (by default it is not).
|
// or those matching UnencryptedRegex, if UnencryptedRegex is provided (by default it is not).
|
||||||
// If decryption is successful, it returns the MAC for the decrypted tree.
|
// If decryption is successful, it returns the MAC for the decrypted tree
|
||||||
|
// (all values if MACOnlyEncrypted is false, or only over values which end
|
||||||
|
// up decrypted if MACOnlyEncrypted is true).
|
||||||
func (tree Tree) Decrypt(key []byte, cipher Cipher) (string, error) {
|
func (tree Tree) Decrypt(key []byte, cipher Cipher) (string, error) {
|
||||||
log.Debug("Decrypting tree")
|
log.Debug("Decrypting tree")
|
||||||
audit.SubmitEvent(audit.DecryptEvent{
|
audit.SubmitEvent(audit.DecryptEvent{
|
||||||
File: tree.FilePath,
|
File: tree.FilePath,
|
||||||
})
|
})
|
||||||
hash := sha512.New()
|
hash := sha512.New()
|
||||||
|
if tree.Metadata.MACOnlyEncrypted {
|
||||||
|
// We initialize with known set of bytes so that a MAC with this setting
|
||||||
|
// enabled is always different from a MAC with this setting disabled.
|
||||||
|
hash.Write(MACOnlyEncryptedInitialization)
|
||||||
|
}
|
||||||
walk := func(branch TreeBranch) error {
|
walk := func(branch TreeBranch) error {
|
||||||
_, err := branch.walkBranch(branch, make([]string, 0), func(in interface{}, path []string) (interface{}, error) {
|
_, err := branch.walkBranch(branch, make([]string, 0), func(in interface{}, path []string) (interface{}, error) {
|
||||||
encrypted := true
|
encrypted := true
|
||||||
|
@ -441,13 +463,15 @@ func (tree Tree) Decrypt(key []byte, cipher Cipher) (string, error) {
|
||||||
} else {
|
} else {
|
||||||
v = in
|
v = in
|
||||||
}
|
}
|
||||||
// Only add to MAC if not a comment
|
if !tree.Metadata.MACOnlyEncrypted || encrypted {
|
||||||
if _, ok := v.(Comment); !ok {
|
// Only add to MAC if not a comment
|
||||||
bytes, err := ToBytes(v)
|
if _, ok := v.(Comment); !ok {
|
||||||
if err != nil {
|
bytes, err := ToBytes(v)
|
||||||
return nil, fmt.Errorf("Could not convert %s to bytes: %s", in, err)
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Could not convert %s to bytes: %s", in, err)
|
||||||
|
}
|
||||||
|
hash.Write(bytes)
|
||||||
}
|
}
|
||||||
hash.Write(bytes)
|
|
||||||
}
|
}
|
||||||
return v, nil
|
return v, nil
|
||||||
})
|
})
|
||||||
|
@ -490,6 +514,7 @@ type Metadata struct {
|
||||||
UnencryptedRegex string
|
UnencryptedRegex string
|
||||||
EncryptedRegex string
|
EncryptedRegex string
|
||||||
MessageAuthenticationCode string
|
MessageAuthenticationCode string
|
||||||
|
MACOnlyEncrypted bool
|
||||||
Version string
|
Version string
|
||||||
KeyGroups []KeyGroup
|
KeyGroups []KeyGroup
|
||||||
// ShamirThreshold is the number of key groups required to recover the
|
// ShamirThreshold is the number of key groups required to recover the
|
||||||
|
|
84
sops_test.go
84
sops_test.go
|
@ -242,6 +242,90 @@ func TestUnencryptedRegex(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMACOnlyEncrypted(t *testing.T) {
|
||||||
|
branches := TreeBranches{
|
||||||
|
TreeBranch{
|
||||||
|
TreeItem{
|
||||||
|
Key: "foo_encrypted",
|
||||||
|
Value: "bar",
|
||||||
|
},
|
||||||
|
TreeItem{
|
||||||
|
Key: "bar",
|
||||||
|
Value: TreeBranch{
|
||||||
|
TreeItem{
|
||||||
|
Key: "foo",
|
||||||
|
Value: "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
tree := Tree{Branches: branches, Metadata: Metadata{EncryptedSuffix: "_encrypted", MACOnlyEncrypted: true}}
|
||||||
|
onlyEncrypted := TreeBranches{
|
||||||
|
TreeBranch{
|
||||||
|
TreeItem{
|
||||||
|
Key: "foo_encrypted",
|
||||||
|
Value: "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
treeOnlyEncrypted := Tree{Branches: onlyEncrypted, Metadata: Metadata{EncryptedSuffix: "_encrypted", MACOnlyEncrypted: true}}
|
||||||
|
cipher := reverseCipher{}
|
||||||
|
mac, err := tree.Encrypt(bytes.Repeat([]byte("f"), 32), cipher)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Encrypting the tree failed: %s", err)
|
||||||
|
}
|
||||||
|
macOnlyEncrypted, err := treeOnlyEncrypted.Encrypt(bytes.Repeat([]byte("f"), 32), cipher)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Encrypting the treeOnlyEncrypted failed: %s", err)
|
||||||
|
}
|
||||||
|
if mac != macOnlyEncrypted {
|
||||||
|
t.Errorf("MACs don't match:\ngot \t\t%+v,\nexpected \t\t%+v", mac, macOnlyEncrypted)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMACOnlyEncryptedNoConfusion(t *testing.T) {
|
||||||
|
branches := TreeBranches{
|
||||||
|
TreeBranch{
|
||||||
|
TreeItem{
|
||||||
|
Key: "foo_encrypted",
|
||||||
|
Value: "bar",
|
||||||
|
},
|
||||||
|
TreeItem{
|
||||||
|
Key: "bar",
|
||||||
|
Value: TreeBranch{
|
||||||
|
TreeItem{
|
||||||
|
Key: "foo",
|
||||||
|
Value: "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
tree := Tree{Branches: branches, Metadata: Metadata{EncryptedSuffix: "_encrypted", MACOnlyEncrypted: true}}
|
||||||
|
onlyEncrypted := TreeBranches{
|
||||||
|
TreeBranch{
|
||||||
|
TreeItem{
|
||||||
|
Key: "foo_encrypted",
|
||||||
|
Value: "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
treeOnlyEncrypted := Tree{Branches: onlyEncrypted, Metadata: Metadata{EncryptedSuffix: "_encrypted"}}
|
||||||
|
cipher := reverseCipher{}
|
||||||
|
mac, err := tree.Encrypt(bytes.Repeat([]byte("f"), 32), cipher)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Encrypting the tree failed: %s", err)
|
||||||
|
}
|
||||||
|
macOnlyEncrypted, err := treeOnlyEncrypted.Encrypt(bytes.Repeat([]byte("f"), 32), cipher)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Encrypting the treeOnlyEncrypted failed: %s", err)
|
||||||
|
}
|
||||||
|
if mac == macOnlyEncrypted {
|
||||||
|
t.Errorf("MACs match but they should not")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type MockCipher struct{}
|
type MockCipher struct{}
|
||||||
|
|
||||||
func (m MockCipher) Encrypt(value interface{}, key []byte, path string) (string, error) {
|
func (m MockCipher) Encrypt(value interface{}, key []byte, path string) (string, error) {
|
||||||
|
|
|
@ -51,6 +51,7 @@ type Metadata struct {
|
||||||
EncryptedSuffix string `yaml:"encrypted_suffix,omitempty" json:"encrypted_suffix,omitempty"`
|
EncryptedSuffix string `yaml:"encrypted_suffix,omitempty" json:"encrypted_suffix,omitempty"`
|
||||||
UnencryptedRegex string `yaml:"unencrypted_regex,omitempty" json:"unencrypted_regex,omitempty"`
|
UnencryptedRegex string `yaml:"unencrypted_regex,omitempty" json:"unencrypted_regex,omitempty"`
|
||||||
EncryptedRegex string `yaml:"encrypted_regex,omitempty" json:"encrypted_regex,omitempty"`
|
EncryptedRegex string `yaml:"encrypted_regex,omitempty" json:"encrypted_regex,omitempty"`
|
||||||
|
MACOnlyEncrypted bool `yaml:"mac_only_encrypted,omitempty" json:"mac_only_encrypted,omitempty"`
|
||||||
Version string `yaml:"version" json:"version"`
|
Version string `yaml:"version" json:"version"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,6 +115,7 @@ func MetadataFromInternal(sopsMetadata sops.Metadata) Metadata {
|
||||||
m.UnencryptedRegex = sopsMetadata.UnencryptedRegex
|
m.UnencryptedRegex = sopsMetadata.UnencryptedRegex
|
||||||
m.EncryptedRegex = sopsMetadata.EncryptedRegex
|
m.EncryptedRegex = sopsMetadata.EncryptedRegex
|
||||||
m.MessageAuthenticationCode = sopsMetadata.MessageAuthenticationCode
|
m.MessageAuthenticationCode = sopsMetadata.MessageAuthenticationCode
|
||||||
|
m.MACOnlyEncrypted = sopsMetadata.MACOnlyEncrypted
|
||||||
m.Version = sopsMetadata.Version
|
m.Version = sopsMetadata.Version
|
||||||
m.ShamirThreshold = sopsMetadata.ShamirThreshold
|
m.ShamirThreshold = sopsMetadata.ShamirThreshold
|
||||||
if len(sopsMetadata.KeyGroups) == 1 {
|
if len(sopsMetadata.KeyGroups) == 1 {
|
||||||
|
@ -270,6 +272,7 @@ func (m *Metadata) ToInternal() (sops.Metadata, error) {
|
||||||
EncryptedSuffix: m.EncryptedSuffix,
|
EncryptedSuffix: m.EncryptedSuffix,
|
||||||
UnencryptedRegex: m.UnencryptedRegex,
|
UnencryptedRegex: m.UnencryptedRegex,
|
||||||
EncryptedRegex: m.EncryptedRegex,
|
EncryptedRegex: m.EncryptedRegex,
|
||||||
|
MACOnlyEncrypted: m.MACOnlyEncrypted,
|
||||||
LastModified: lastModified,
|
LastModified: lastModified,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче