1
0
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:
Adrian Utrilla
2016-08-24 14:38:05 -07:00
parent e1f2dc1f66
commit 341da25219
3 changed files with 25 additions and 15 deletions

View File

@@ -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)

View File

@@ -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
View File

@@ -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)
}