Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor envelope to use cryptobytes #69249

Merged
merged 1 commit into from
Oct 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions staging/src/k8s.io/apiserver/Godeps/Godeps.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ go_library(
"//staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/github.com/hashicorp/golang-lru:go_default_library",
"//vendor/golang.org/x/crypto/cryptobyte:go_default_library",
"//vendor/google.golang.org/grpc:go_default_library",
],
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ import (
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"encoding/binary"
"fmt"
"time"

"k8s.io/apiserver/pkg/storage/value"

lru "github.com/hashicorp/golang-lru"
"golang.org/x/crypto/cryptobyte"
)

// defaultCacheSize is the number of decrypted DEKs which would be cached by the transformer.
Expand Down Expand Up @@ -80,12 +80,13 @@ func (t *envelopeTransformer) TransformFromStorage(data []byte, context value.Co
// Read the 16 bit length-of-DEK encoded at the start of the encrypted DEK. 16 bits can
// represent a maximum key length of 65536 bytes. We are using a 256 bit key, whose
// length cannot fit in 8 bits (1 byte). Thus, we use 16 bits (2 bytes) to store the length.
keyLen := int(binary.BigEndian.Uint16(data[:2]))
if keyLen+2 > len(data) {
return nil, false, fmt.Errorf("invalid data encountered by envelope transformer, length longer than available bytes: %q", data)
var encKey cryptobyte.String
s := cryptobyte.String(data)
if ok := s.ReadUint16LengthPrefixed(&encKey); !ok {
return nil, false, fmt.Errorf("invalid data encountered by envelope transformer: failed to read uint16 length prefixed data")
}
encKey := data[2 : keyLen+2]
encData := data[2+keyLen:]

encData := []byte(s)

// Look up the decrypted DEK from cache or Envelope.
transformer := t.getTransformer(encKey)
Expand Down Expand Up @@ -120,21 +121,18 @@ func (t *envelopeTransformer) TransformToStorage(data []byte, context value.Cont
return nil, err
}

// Append the length of the encrypted DEK as the first 2 bytes.
encKeyLen := make([]byte, 2)
encKeyBytes := []byte(encKey)
binary.BigEndian.PutUint16(encKeyLen, uint16(len(encKeyBytes)))

prefix := append(encKeyLen, encKeyBytes...)

prefixedData := make([]byte, len(prefix), len(data)+len(prefix))
copy(prefixedData, prefix)
result, err := transformer.TransformToStorage(data, context)
if err != nil {
return nil, err
}
prefixedData = append(prefixedData, result...)
return prefixedData, nil
// Append the length of the encrypted DEK as the first 2 bytes.
b := cryptobyte.NewBuilder(nil)
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
b.AddBytes([]byte(encKey))
})
b.AddBytes(result)

return b.Bytes()
}

var _ value.Transformer = &envelopeTransformer{}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"bytes"
"crypto/aes"
"encoding/base64"
"encoding/binary"
"fmt"
"strconv"
"strings"
Expand Down Expand Up @@ -201,3 +202,70 @@ func benchmarkRead(b *testing.B, transformer value.Transformer, valueLength int)
}
b.StopTimer()
}

// remove after 1.13
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is probably useful indefinitely to make sure the current implementation matches a known storage format, no?

func TestBackwardsCompatibility(t *testing.T) {
envelopeService := newTestEnvelopeService()
envelopeTransformerInst, err := NewEnvelopeTransformer(envelopeService, testEnvelopeCacheSize, aestransformer.NewCBCTransformer)
if err != nil {
t.Fatalf("failed to initialize envelope transformer: %v", err)
}
context := value.DefaultContext([]byte(testContextText))
originalText := []byte(testText)

transformedData, err := oldTransformToStorage(envelopeTransformerInst.(*envelopeTransformer), originalText, context)
if err != nil {
t.Fatalf("envelopeTransformer: error while transforming data to storage: %s", err)
}
untransformedData, _, err := envelopeTransformerInst.TransformFromStorage(transformedData, context)
if err != nil {
t.Fatalf("could not decrypt Envelope transformer's encrypted data even once: %v", err)
}
if bytes.Compare(untransformedData, originalText) != 0 {
t.Fatalf("envelopeTransformer transformed data incorrectly. Expected: %v, got %v", originalText, untransformedData)
}

envelopeService.SetDisabledStatus(true)
// Subsequent read for the same data should work fine due to caching.
untransformedData, _, err = envelopeTransformerInst.TransformFromStorage(transformedData, context)
if err != nil {
t.Fatalf("could not decrypt Envelope transformer's encrypted data using just cache: %v", err)
}
if bytes.Compare(untransformedData, originalText) != 0 {
t.Fatalf("envelopeTransformer transformed data incorrectly using cache. Expected: %v, got %v", originalText, untransformedData)
}
}

// remove after 1.13
func oldTransformToStorage(t *envelopeTransformer, data []byte, context value.Context) ([]byte, error) {
newKey, err := generateKey(32)
if err != nil {
return nil, err
}

encKey, err := t.envelopeService.Encrypt(newKey)
if err != nil {
return nil, err
}

transformer, err := t.addTransformer(encKey, newKey)
if err != nil {
return nil, err
}

// Append the length of the encrypted DEK as the first 2 bytes.
encKeyLen := make([]byte, 2)
encKeyBytes := []byte(encKey)
binary.BigEndian.PutUint16(encKeyLen, uint16(len(encKeyBytes)))

prefix := append(encKeyLen, encKeyBytes...)

prefixedData := make([]byte, len(prefix), len(data)+len(prefix))
copy(prefixedData, prefix)
result, err := transformer.TransformToStorage(data, context)
if err != nil {
return nil, err
}
prefixedData = append(prefixedData, result...)
return prefixedData, nil
}