mirror of
https://github.com/getsops/sops.git
synced 2026-02-05 12:45:21 +01:00
Added DataKeyCipher interface
This commit is contained in:
@@ -19,6 +19,8 @@ type encryptedValue struct {
|
||||
|
||||
const nonceSize int = 32
|
||||
|
||||
type Cipher struct{}
|
||||
|
||||
var encre = regexp.MustCompile(`^ENC\[AES256_GCM,data:(.+),iv:(.+),tag:(.+),type:(.+)\]`)
|
||||
|
||||
func parse(value string) (*encryptedValue, error) {
|
||||
@@ -44,7 +46,7 @@ func parse(value string) (*encryptedValue, error) {
|
||||
}
|
||||
|
||||
// Decrypt takes a sops-format value string and a key and returns the decrypted value.
|
||||
func Decrypt(value string, key []byte, additionalAuthData []byte) (interface{}, error) {
|
||||
func (c Cipher) Decrypt(value string, key []byte, additionalAuthData []byte) (interface{}, error) {
|
||||
encryptedValue, err := parse(value)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -82,7 +84,7 @@ func Decrypt(value string, key []byte, additionalAuthData []byte) (interface{},
|
||||
}
|
||||
|
||||
// Encrypt takes one of (string, int, float, bool) and encrypts it with the provided key and additional auth data, returning a sops-format encrypted string.
|
||||
func Encrypt(value interface{}, key []byte, additionalAuthData []byte) (string, error) {
|
||||
func (c Cipher) Encrypt(value interface{}, key []byte, additionalAuthData []byte) (string, error) {
|
||||
aescipher, err := cryptoaes.NewCipher(key)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Could not initialize AES GCM encryption cipher: %s", err)
|
||||
|
||||
15
main/main.go
15
main/main.go
@@ -205,11 +205,12 @@ func decrypt(c *cli.Context, file string, fileBytes []byte, output io.Writer) er
|
||||
return cli.NewExitError(fmt.Sprintf("Error loading file: %s", err), exitCouldNotReadInputFile)
|
||||
}
|
||||
tree := sops.Tree{Branch: branch, Metadata: metadata}
|
||||
mac, err := tree.Decrypt(key)
|
||||
cipher := aes.Cipher{}
|
||||
mac, err := tree.Decrypt(key, cipher)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Sprintf("Error decrypting tree: %s", err), exitErrorDecryptingTree)
|
||||
}
|
||||
originalMac, err := aes.Decrypt(metadata.MessageAuthenticationCode, key, []byte(metadata.LastModified.Format(time.RFC3339)))
|
||||
originalMac, err := cipher.Decrypt(metadata.MessageAuthenticationCode, key, []byte(metadata.LastModified.Format(time.RFC3339)))
|
||||
if originalMac != mac && !c.Bool("ignore-mac") {
|
||||
return cli.NewExitError("MAC mismatch.", 9)
|
||||
}
|
||||
@@ -259,7 +260,8 @@ func encrypt(c *cli.Context, file string, fileBytes []byte, output io.Writer) er
|
||||
}
|
||||
}
|
||||
tree := sops.Tree{Branch: branch, Metadata: metadata}
|
||||
mac, err := tree.Encrypt(key)
|
||||
cipher := aes.Cipher{}
|
||||
mac, err := tree.Encrypt(key, cipher)
|
||||
metadata.MessageAuthenticationCode = mac
|
||||
out, err := store.DumpWithMetadata(tree.Branch, metadata)
|
||||
_, err = output.Write([]byte(out))
|
||||
@@ -284,11 +286,12 @@ func rotate(c *cli.Context, file string, fileBytes []byte, output io.Writer) err
|
||||
return cli.NewExitError(fmt.Sprintf("Error loading file: %s", err), exitCouldNotReadInputFile)
|
||||
}
|
||||
tree := sops.Tree{Branch: branch, Metadata: metadata}
|
||||
mac, err := tree.Decrypt(key)
|
||||
cipher := aes.Cipher{}
|
||||
mac, err := tree.Decrypt(key, cipher)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Sprintf("Error decrypting tree: %s", err), 8)
|
||||
}
|
||||
originalMac, err := aes.Decrypt(metadata.MessageAuthenticationCode, key, []byte(metadata.LastModified.Format(time.RFC3339)))
|
||||
originalMac, err := cipher.Decrypt(metadata.MessageAuthenticationCode, key, []byte(metadata.LastModified.Format(time.RFC3339)))
|
||||
if originalMac != mac && !c.Bool("ignore-mac") {
|
||||
return cli.NewExitError("MAC mismatch.", 9)
|
||||
}
|
||||
@@ -302,7 +305,7 @@ func rotate(c *cli.Context, file string, fileBytes []byte, output io.Writer) err
|
||||
k.Encrypt(newKey)
|
||||
}
|
||||
}
|
||||
_, err = tree.Encrypt(newKey)
|
||||
_, err = tree.Encrypt(newKey, cipher)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Sprintf("Error encrypting tree: %s", err), exitErrorEncryptingTree)
|
||||
}
|
||||
|
||||
19
sops.go
19
sops.go
@@ -3,7 +3,6 @@ package sops
|
||||
import (
|
||||
"crypto/sha512"
|
||||
"fmt"
|
||||
"go.mozilla.org/sops/aes"
|
||||
"go.mozilla.org/sops/kms"
|
||||
"go.mozilla.org/sops/pgp"
|
||||
"strconv"
|
||||
@@ -21,6 +20,12 @@ func (e sopsError) Error() string { return string(e) }
|
||||
// MacMismatch occurs when the computed MAC does not match the expected ones
|
||||
const MacMismatch = sopsError("MAC mismatch")
|
||||
|
||||
// DataKeyCipher provides a way to encrypt and decrypt the data key used to encrypt and decrypt sops files, so that the data key can be stored alongside the encrypted content. A DataKeyCipher must be able to decrypt the values it encrypts.
|
||||
type DataKeyCipher interface {
|
||||
Encrypt(value interface{}, key []byte, additionalAuthData []byte) (string, error)
|
||||
Decrypt(value string, key []byte, additionalAuthData []byte) (interface{}, error)
|
||||
}
|
||||
|
||||
// TreeItem is an item inside sops's tree
|
||||
type TreeItem struct {
|
||||
Key string
|
||||
@@ -75,14 +80,14 @@ func (tree TreeBranch) walkBranch(in TreeBranch, path []string, onLeaves func(in
|
||||
return in, nil
|
||||
}
|
||||
|
||||
// Encrypt walks over the tree and encrypts all values, except those whose key ends with the UnencryptedSuffix specified on the Metadata struct. If encryption is successful, it returns the MAC for the encrypted tree.
|
||||
func (tree Tree) Encrypt(key []byte) (string, error) {
|
||||
// Encrypt walks over the tree and encrypts all values with the provided cipher, except those whose key ends with the UnencryptedSuffix specified on the Metadata struct. If encryption is successful, it returns the MAC for the encrypted tree.
|
||||
func (tree Tree) Encrypt(key []byte, cipher DataKeyCipher) (string, error) {
|
||||
hash := sha512.New()
|
||||
_, err := tree.Branch.walkBranch(tree.Branch, make([]string, 0), func(in interface{}, path []string) (interface{}, error) {
|
||||
bytes, err := toBytes(in)
|
||||
if !strings.HasSuffix(path[len(path)-1], tree.Metadata.UnencryptedSuffix) {
|
||||
var err error
|
||||
in, err = aes.Encrypt(in, key, []byte(strings.Join(path, ":")+":"))
|
||||
in, err = cipher.Encrypt(in, key, []byte(strings.Join(path, ":")+":"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Could not encrypt value: %s", err)
|
||||
}
|
||||
@@ -99,14 +104,14 @@ func (tree Tree) Encrypt(key []byte) (string, error) {
|
||||
return fmt.Sprintf("%X", hash.Sum(nil)), nil
|
||||
}
|
||||
|
||||
// Decrypt walks over the tree and decrypts all values, except those whose key ends with the UnencryptedSuffix specified on the Metadata struct. If decryption is successful, it returns the MAC for the decrypted tree.
|
||||
func (tree Tree) Decrypt(key []byte) (string, error) {
|
||||
// Decrypt walks over the tree and decrypts all values with the provided cipher, except those whose key ends with the UnencryptedSuffix specified on the Metadata struct. If decryption is successful, it returns the MAC for the decrypted tree.
|
||||
func (tree Tree) Decrypt(key []byte, cipher DataKeyCipher) (string, error) {
|
||||
hash := sha512.New()
|
||||
_, err := tree.Branch.walkBranch(tree.Branch, make([]string, 0), func(in interface{}, path []string) (interface{}, error) {
|
||||
var v interface{}
|
||||
if !strings.HasSuffix(path[len(path)-1], tree.Metadata.UnencryptedSuffix) {
|
||||
var err error
|
||||
v, err = aes.Decrypt(in.(string), key, []byte(strings.Join(path, ":")+":"))
|
||||
v, err = cipher.Decrypt(in.(string), key, []byte(strings.Join(path, ":")+":"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Could not decrypt value: %s", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user