Skip to content

Commit

Permalink
Move aead to base and alias the aead module (#63)
Browse files Browse the repository at this point in the history
  • Loading branch information
jefferai authored Mar 14, 2022
1 parent f65c2c8 commit 12389d3
Show file tree
Hide file tree
Showing 11 changed files with 313 additions and 264 deletions.
265 changes: 265 additions & 0 deletions aead/aead.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
package aead

import (
"context"
"crypto/aes"
"crypto/cipher"
"crypto/sha256"
"errors"
"fmt"
"hash"

wrapping "github.com/hashicorp/go-kms-wrapping/v2"
"github.com/hashicorp/go-uuid"
"golang.org/x/crypto/hkdf"
)

// Wrapper implements the wrapping.Wrapper interface for AEAD
type Wrapper struct {
keyId string
keyBytes []byte
aead cipher.AEAD
}

// ShamirWrapper is here for backwards compatibility for Vault; it reports a
// type of "shamir" instead of "aead"
type ShamirWrapper struct {
*Wrapper
}

// Ensure that we are implementing Wrapper
var (
_ wrapping.Wrapper = (*Wrapper)(nil)
_ wrapping.Wrapper = (*ShamirWrapper)(nil)
)

// NewWrapper creates a new Wrapper. No options are supported.
func NewWrapper() *Wrapper {
return new(Wrapper)
}

// Deprecated: NewShamirWrapper returns a type of "shamir" instead of "aead" and
// is for backwards compatibility with old versions of Vault. Do not use in new
// code.
func NewShamirWrapper() *ShamirWrapper {
return &ShamirWrapper{
Wrapper: NewWrapper(),
}
}

// NewDerivedWrapper returns an aead.Wrapper whose key is set to an hkdf-based
// derivation from the original wrapper
//
// Supported options:
//
// * wrapping.WithKeyId: The key ID, if any, to set on the derived wrapper
//
// * wrapping.WithConfigMap: A struct containing the following:
//
// ** "aead_type": The type of AEAD to use as a string, defaults to
// wrapping.AeadTypeAesGcm.String()
//
// ** "hash": The type of hash function to use for derivation as a string,
// defaults to wrapping.HashTypeSha256.String()
//
// ** "info": The info value, if any, to use in the derivation, as a
// base64-encoded byte slice
//
// ** "salt": The salt value, if any, to use in the derivation, as a
// base64-encoded byte slice
//
// The values in WithConfigMap can also be set via the package's native
// With* functions.
func (s *Wrapper) NewDerivedWrapper(opt ...wrapping.Option) (*Wrapper, error) {
if len(s.keyBytes) == 0 {
return nil, errors.New("cannot create a sub-wrapper when key bytes are not set")
}

opts, err := getOpts(opt...)
if err != nil {
return nil, err
}

var h func() hash.Hash
switch opts.WithHashType {
case wrapping.HashTypeSha256:
h = sha256.New
default:
return nil, fmt.Errorf("not a supported hash type: %d", opts.WithHashType)
}

ret := &Wrapper{
keyId: opts.WithKeyId,
}
reader := hkdf.New(h, s.keyBytes, opts.WithSalt, opts.WithInfo)

switch opts.WithAeadType {
case wrapping.AeadTypeAesGcm:
ret.keyBytes = make([]byte, len(s.keyBytes))
n, err := reader.Read(ret.keyBytes)
if err != nil {
return nil, fmt.Errorf("error reading bytes from derived reader: %w", err)
}
if n != len(s.keyBytes) {
return nil, fmt.Errorf("expected to read %d bytes, but read %d bytes from derived reader", len(s.keyBytes), n)
}
if err := ret.SetAesGcmKeyBytes(ret.keyBytes); err != nil {
return nil, fmt.Errorf("error setting derived AES GCM key: %w", err)
}

default:
return nil, fmt.Errorf("not a supported aead type: %d", opts.WithAeadType)
}

return ret, nil
}

// SetConfig sets the fields on the Wrapper object
//
// Supported options:
//
// * wrapping.WithKeyId: The key ID, if any, to set on the wrapper
//
// * wrapping.WithConfigMap: A struct containing the following:
//
// ** "aead_type": The type of AEAD to use, defaults to wrapping.AeadTypeAesGcm
//
// ** "key": A base-64 encoded string value containing the key to use
//
// The values in WithConfigMap can also be set via the package's native
// With* functions.
func (s *Wrapper) SetConfig(_ context.Context, opt ...wrapping.Option) (*wrapping.WrapperConfig, error) {
opts, err := getOpts(opt...)
if err != nil {
return nil, err
}

s.keyId = opts.WithKeyId

if len(opts.WithKey) == 0 {
return nil, nil
}

switch opts.WithAeadType {
case wrapping.AeadTypeAesGcm:
if err := s.SetAesGcmKeyBytes(opts.WithKey); err != nil {
return nil, fmt.Errorf("error setting AES GCM key: %w", err)
}

default:
return nil, fmt.Errorf("unsupported aead_type %q", opts.WithAeadType.String())
}

// Map that holds non-sensitive configuration info
wrapConfig := new(wrapping.WrapperConfig)
wrapConfig.Metadata = make(map[string]string)
wrapConfig.Metadata["aead_type"] = opts.WithAeadType.String()

return wrapConfig, nil
}

// GetKeyBytes returns the current key bytes
func (s *Wrapper) GetKeyBytes() []byte {
return s.keyBytes
}

// SetAead allows directly setting an AEAD to use
func (s *Wrapper) SetAead(aead cipher.AEAD) {
s.aead = aead
}

// SetAesGcmKeyBytes takes in a byte slice and constucts an AES-GCM AEAD from it
func (s *Wrapper) SetAesGcmKeyBytes(key []byte) error {
aesCipher, err := aes.NewCipher(key)
if err != nil {
return err
}

aead, err := cipher.NewGCM(aesCipher)
if err != nil {
return err
}

s.keyBytes = key
s.aead = aead
return nil
}

// Type returns the seal type for this particular Wrapper implementation
func (s *Wrapper) Type(_ context.Context) (wrapping.WrapperType, error) {
return wrapping.WrapperTypeAead, nil
}

func (s *ShamirWrapper) Type(_ context.Context) (wrapping.WrapperType, error) {
return wrapping.WrapperTypeShamir, nil
}

// KeyId returns the last known key id
func (s *Wrapper) KeyId(_ context.Context) (string, error) {
return s.keyId, nil
}

// Encrypt is used to encrypt the plaintext using the AEAD held by the wrapper
//
// Supported options:
//
// * wrapping.WithAad: Additional authenticated data that should be sourced from
// a separate location, and must also be provided during decryption
func (s *Wrapper) Encrypt(_ context.Context, plaintext []byte, opt ...wrapping.Option) (*wrapping.BlobInfo, error) {
if plaintext == nil {
return nil, errors.New("given plaintext for encryption is nil")
}

if s.aead == nil {
return nil, errors.New("aead is not configured in the seal")
}

opts, err := getOpts(opt...)
if err != nil {
return nil, err
}

iv, err := uuid.GenerateRandomBytes(12)
if err != nil {
return nil, err
}

ciphertext := s.aead.Seal(nil, iv, plaintext, opts.WithAad)

return &wrapping.BlobInfo{
Ciphertext: append(iv, ciphertext...),
KeyInfo: &wrapping.KeyInfo{
KeyId: s.keyId,
},
}, nil
}

// Decrypt is used to decrypt the ciphertext using the AEAD held by the wrapper
//
// Supported options:
//
// * wrapping.WithAad: Additional authenticated data that should be sourced from
// a separate location, and must match what was provided during encryption
func (s *Wrapper) Decrypt(_ context.Context, in *wrapping.BlobInfo, opt ...wrapping.Option) ([]byte, error) {
if in == nil {
return nil, errors.New("given plaintext for encryption is nil")
}

if s.aead == nil {
return nil, errors.New("aead is not configured in the seal")
}

opts, err := getOpts(opt...)
if err != nil {
return nil, err
}

iv, ciphertext := in.Ciphertext[:12], in.Ciphertext[12:]

plaintext, err := s.aead.Open(nil, iv, ciphertext, opts.WithAad)
if err != nil {
return nil, err
}

return plaintext, nil
}
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.17
require (
github.com/hashicorp/go-uuid v1.0.2
github.com/stretchr/testify v1.7.0
golang.org/x/crypto v0.0.0-20220313003712-b769efc7c000
google.golang.org/protobuf v1.27.1
)

Expand Down
9 changes: 9 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/crypto v0.0.0-20220313003712-b769efc7c000 h1:SL+8VVnkqyshUSz5iNnXtrBQzvFF2SkROm6t5RczFAE=
golang.org/x/crypto v0.0.0-20220313003712-b769efc7c000/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package aead_test
package multi_test

import (
"context"
"crypto/rand"
"testing"

wrapping "github.com/hashicorp/go-kms-wrapping/v2"
"github.com/hashicorp/go-kms-wrapping/v2/aead"
"github.com/hashicorp/go-kms-wrapping/v2/multi"
"github.com/hashicorp/go-kms-wrapping/wrappers/aead/v2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package aead_test
package structwrapping_test

import (
"context"
"testing"

wrapping "github.com/hashicorp/go-kms-wrapping/v2"
"github.com/hashicorp/go-kms-wrapping/v2/aead"
"github.com/hashicorp/go-kms-wrapping/v2/structwrapping"
"github.com/hashicorp/go-kms-wrapping/wrappers/aead/v2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
Expand Down
Loading

0 comments on commit 12389d3

Please sign in to comment.