From f11dd855bcfbebffe11e3591a0eac3e5da24af42 Mon Sep 17 00:00:00 2001 From: Jess Frazelle Date: Mon, 18 Apr 2016 01:09:18 -0700 Subject: [PATCH] initial aead Signed-off-by: Jess Frazelle --- Makefile | 2 +- cryptar/cryptar.go | 91 ++++++++++++++++++++++++++++++++++++++++++++++ generate.go | 26 +++++++++++-- main.go | 6 ++- rootfs_ops.go | 10 ++++- 5 files changed, 127 insertions(+), 8 deletions(-) create mode 100644 cryptar/cryptar.go diff --git a/Makefile b/Makefile index 8b9952e..1541c40 100644 --- a/Makefile +++ b/Makefile @@ -48,7 +48,7 @@ image.tar: docker export $(shell docker create $(DOCKER_ROOTFS_IMAGE) sh) > $@ rootfs.go: image.tar - GOMAXPROCS=1 go generate + GOMAXPROCS=1 go run generate.go fmt: @echo "+ $@" diff --git a/cryptar/cryptar.go b/cryptar/cryptar.go new file mode 100644 index 0000000..90c08b4 --- /dev/null +++ b/cryptar/cryptar.go @@ -0,0 +1,91 @@ +package cryptar + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "encoding/base64" +) + +// Encrypt takes the contents of a tarball and a key and seals it. +func Encrypt(tarball, key []byte) (string, error) { + gcm, err := keyToGCM(key) + if err != nil { + return "", err + } + + nonce, err := generateNonce(gcm.NonceSize()) + if err != nil { + return "", err + } + + out := gcm.Seal(nonce, nonce, tarball, nil) + + enctar := base64.StdEncoding.EncodeToString(out) + + return enctar, nil +} + +// Decrypt takes an encrypted tarball and key and unseals it. +func Decrypt(enctar string, key []byte) ([]byte, error) { + out, err := base64.StdEncoding.DecodeString(enctar) + if err != nil { + return nil, err + } + + gcm, err := keyToGCM(key) + if err != nil { + return nil, err + } + + size := gcm.NonceSize() + nonce := make([]byte, size) + copy(nonce, out[:]) + + tarball, err := gcm.Open(nil, nonce, out[size:], nil) + if err != nil { + return nil, err + } + + return tarball, nil +} + +func keyToGCM(key []byte) (cipher.AEAD, error) { + /*hash := sha256.New() + if _, err := hash.Write([]byte(key)); err != nil { + return nil, err + } + md := hash.Sum(nil) + mdkey := hex.EncodeToString(md)*/ + + // encrypt the tar with the key + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + gcm, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + + return gcm, err +} + +// generateNonce creates a new random nonce. +func generateNonce(size int) ([]byte, error) { + // Create the nonce. + nonce, err := randBytes(size) + if err != nil { + return nil, err + } + + return nonce, nil +} + +// randBytes returns n bytes of random data. +func randBytes(n int) ([]byte, error) { + b := make([]byte, n) + _, err := rand.Read(b) + return b, err +} diff --git a/generate.go b/generate.go index acbb8f4..e73ef6e 100644 --- a/generate.go +++ b/generate.go @@ -3,14 +3,22 @@ package main import ( + "crypto/rand" "encoding/base64" + "fmt" "io/ioutil" "os" "path/filepath" + + "github.com/jfrazelle/binctr/cryptar" +) + +const ( + nonceSize = 24 ) -// Reads static/index.html and saves as a constant in static.go func main() { + // prompt for key wd, err := os.Getwd() if err != nil { panic(err) @@ -22,15 +30,27 @@ func main() { tarPath := filepath.Join(wd, "image.tar") out.Write([]byte("// This file is autogenerated; DO NOT EDIT DIRECTLY\n// See generate.go for more info\npackage main\n\nconst (\n")) + out.Write([]byte("\t// DATA is the encrypted tarball data\n")) out.Write([]byte("\tDATA = `")) f, err := ioutil.ReadFile(tarPath) if err != nil { panic(err) } - tar := base64.StdEncoding.EncodeToString(f) - out.Write([]byte(tar)) + key := make([]byte, 32) + if _, err := rand.Read(key); err != nil { + panic(err) + } + + gcmOut, err := cryptar.Encrypt(f, key) + if err != nil { + panic(err) + } + + out.Write([]byte(gcmOut)) out.Write([]byte("`\n")) out.Write([]byte(")\n")) + + fmt.Println("key is: ", base64.StdEncoding.EncodeToString(key)) } diff --git a/main.go b/main.go index 2fe302d..48abae9 100644 --- a/main.go +++ b/main.go @@ -34,7 +34,7 @@ const ( ` - defaultRoot = "/run/binctr" + defaultRoot = "/tmp/binctr" defaultRootfsDir = "rootfs" defaultApparmorProfile = "docker-default" ) @@ -44,6 +44,7 @@ var ( containerID string pidFile string root string + passkey string allocateTty bool detach bool @@ -116,6 +117,7 @@ func init() { flag.StringVar(&console, "console", console, "the pty slave path for use with the container") flag.StringVar(&pidFile, "pid-file", "", "specify the file to write the process id to") flag.StringVar(&root, "root", defaultRoot, "root directory of container state, should be tmpfs") + flag.StringVar(&passkey, "key", "", "key to decrypt the embedded tarball") flag.Var(&hookflags, "hook", "Hooks to prefill into spec file. (ex. --hook prestart:netns)") @@ -215,7 +217,7 @@ func main() { }, } - if err := unpackRootfs(spec); err != nil { + if err := unpackRootfs(spec, passkey); err != nil { logrus.Fatal(err) } diff --git a/rootfs_ops.go b/rootfs_ops.go index 2347817..a7ed9c3 100644 --- a/rootfs_ops.go +++ b/rootfs_ops.go @@ -6,11 +6,17 @@ import ( "os" "github.com/docker/docker/pkg/archive" + "github.com/jfrazelle/binctr/cryptar" "github.com/opencontainers/runtime-spec/specs-go" ) -func unpackRootfs(spec *specs.Spec) error { - data, err := base64.StdEncoding.DecodeString(DATA) +func unpackRootfs(spec *specs.Spec, keyin string) error { + key, err := base64.StdEncoding.DecodeString(keyin) + if err != nil { + return err + } + + data, err := cryptar.Decrypt(DATA, key) if err != nil { return err }