Compare commits
1 Commits
master
...
key-versio
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
01cb705c36 |
@@ -555,7 +555,7 @@ func encryptBucketMetadata(ctx context.Context, bucket string, input []byte, kms
|
||||
outbuf := bytes.NewBuffer(nil)
|
||||
objectKey := crypto.GenerateKey(key.Plaintext, rand.Reader)
|
||||
sealedKey := objectKey.Seal(key.Plaintext, crypto.GenerateIV(rand.Reader), crypto.S3.String(), bucket, "")
|
||||
crypto.S3.CreateMetadata(metadata, key.KeyID, key.Ciphertext, sealedKey)
|
||||
crypto.S3.CreateMetadata(metadata, key, sealedKey)
|
||||
_, err = sio.Encrypt(outbuf, bytes.NewBuffer(input), sio.Config{Key: objectKey[:], MinVersion: sio.Version20, CipherSuites: fips.DARECiphers()})
|
||||
if err != nil {
|
||||
return output, metabytes, err
|
||||
|
||||
@@ -293,7 +293,7 @@ func rotateKey(ctx context.Context, oldKey []byte, newKeyID string, newKey []byt
|
||||
return err
|
||||
}
|
||||
sealedKey = objectKey.Seal(newKey.Plaintext, crypto.GenerateIV(rand.Reader), crypto.S3.String(), bucket, object)
|
||||
crypto.S3.CreateMetadata(metadata, newKey.KeyID, newKey.Ciphertext, sealedKey)
|
||||
crypto.S3.CreateMetadata(metadata, newKey, sealedKey)
|
||||
return nil
|
||||
case crypto.S3KMS:
|
||||
if GlobalKMS == nil {
|
||||
@@ -333,7 +333,7 @@ func rotateKey(ctx context.Context, oldKey []byte, newKeyID string, newKey []byt
|
||||
}
|
||||
|
||||
sealedKey := objectKey.Seal(newKey.Plaintext, crypto.GenerateIV(rand.Reader), crypto.S3KMS.String(), bucket, object)
|
||||
crypto.S3KMS.CreateMetadata(metadata, newKey.KeyID, newKey.Ciphertext, sealedKey, cryptoCtx)
|
||||
crypto.S3KMS.CreateMetadata(metadata, newKey, sealedKey, cryptoCtx)
|
||||
return nil
|
||||
case crypto.SSEC:
|
||||
sealedKey, err := crypto.SSEC.ParseMetadata(metadata)
|
||||
@@ -376,7 +376,7 @@ func newEncryptMetadata(ctx context.Context, kind crypto.Type, keyID string, key
|
||||
|
||||
objectKey := crypto.GenerateKey(key.Plaintext, rand.Reader)
|
||||
sealedKey = objectKey.Seal(key.Plaintext, crypto.GenerateIV(rand.Reader), crypto.S3.String(), bucket, object)
|
||||
crypto.S3.CreateMetadata(metadata, key.KeyID, key.Ciphertext, sealedKey)
|
||||
crypto.S3.CreateMetadata(metadata, key, sealedKey)
|
||||
return objectKey, nil
|
||||
case crypto.S3KMS:
|
||||
if GlobalKMS == nil {
|
||||
@@ -409,7 +409,7 @@ func newEncryptMetadata(ctx context.Context, kind crypto.Type, keyID string, key
|
||||
|
||||
objectKey := crypto.GenerateKey(key.Plaintext, rand.Reader)
|
||||
sealedKey = objectKey.Seal(key.Plaintext, crypto.GenerateIV(rand.Reader), crypto.S3KMS.String(), bucket, object)
|
||||
crypto.S3KMS.CreateMetadata(metadata, key.KeyID, key.Ciphertext, sealedKey, cryptoCtx)
|
||||
crypto.S3KMS.CreateMetadata(metadata, key, sealedKey, cryptoCtx)
|
||||
return objectKey, nil
|
||||
case crypto.SSEC:
|
||||
objectKey := crypto.GenerateKey(key, rand.Reader)
|
||||
|
||||
@@ -280,6 +280,7 @@ func (a kmsAPIHandlers) KMSKeyStatusHandler(w http.ResponseWriter, r *http.Reque
|
||||
// 2. Verify that we can indeed decrypt the (encrypted) key
|
||||
decryptedKey, err := GlobalKMS.Decrypt(ctx, &kms.DecryptRequest{
|
||||
Name: key.KeyID,
|
||||
Version: key.Version,
|
||||
Ciphertext: key.Ciphertext,
|
||||
AssociatedData: kmsContext,
|
||||
})
|
||||
|
||||
@@ -758,7 +758,7 @@ func (r *metacacheReader) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// metacacheBlockWriter collects blocks and provides a callaback to store them.
|
||||
// metacacheBlockWriter collects blocks and provides a callback to store them.
|
||||
type metacacheBlockWriter struct {
|
||||
wg sync.WaitGroup
|
||||
streamErr error
|
||||
|
||||
2
go.mod
2
go.mod
@@ -56,7 +56,7 @@ require (
|
||||
github.com/minio/dnscache v0.1.1
|
||||
github.com/minio/dperf v0.6.3
|
||||
github.com/minio/highwayhash v1.0.3
|
||||
github.com/minio/kms-go/kes v0.3.1
|
||||
github.com/minio/kms-go/kes v0.3.2-0.20250505160844-240efef6bb74
|
||||
github.com/minio/kms-go/kms v0.5.1-0.20250225090116-4e64ce8d0f35
|
||||
github.com/minio/madmin-go/v3 v3.0.109
|
||||
github.com/minio/minio-go/v7 v7.0.91
|
||||
|
||||
4
go.sum
4
go.sum
@@ -436,8 +436,8 @@ github.com/minio/filepath v1.0.0/go.mod h1:/nRZA2ldl5z6jT9/KQuvZcQlxZIMQoFFQPvEX
|
||||
github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
|
||||
github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q=
|
||||
github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ=
|
||||
github.com/minio/kms-go/kes v0.3.1 h1:K3sPFAvFbJx33XlCTUBnQo8JRmSZyDvT6T2/MQ2iC3A=
|
||||
github.com/minio/kms-go/kes v0.3.1/go.mod h1:Q9Ct0KUAuN9dH0hSVa0eva45Jg99cahbZpPxeqR9rOQ=
|
||||
github.com/minio/kms-go/kes v0.3.2-0.20250505160844-240efef6bb74 h1:iUY0/rQ66zmowoB94yGBTk3I2ljOoD5jSIKwkhxkwe4=
|
||||
github.com/minio/kms-go/kes v0.3.2-0.20250505160844-240efef6bb74/go.mod h1:Q9Ct0KUAuN9dH0hSVa0eva45Jg99cahbZpPxeqR9rOQ=
|
||||
github.com/minio/kms-go/kms v0.5.1-0.20250225090116-4e64ce8d0f35 h1:ISNz42SPD+heeHhpl9bwMRRusPTCsbYKd1YoED265E0=
|
||||
github.com/minio/kms-go/kms v0.5.1-0.20250225090116-4e64ce8d0f35/go.mod h1:JFQu2srrnWxMn6KcwS5347oTwNKW7nkewgBlrodjF9k=
|
||||
github.com/minio/madmin-go/v3 v3.0.109 h1:hRHlJ6yaIB3tlIj5mz9L9mGcyLC37S9qL1WtFrRtyQ0=
|
||||
|
||||
@@ -92,6 +92,7 @@ func Encrypt(k *kms.KMS, plaintext io.Reader, ctx kms.Context) (io.Reader, error
|
||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
metadata, err := json.Marshal(encryptedObject{
|
||||
KeyID: key.KeyID,
|
||||
Version: key.Version,
|
||||
KMSKey: key.Ciphertext,
|
||||
Algorithm: algorithm,
|
||||
Nonce: nonce,
|
||||
@@ -151,6 +152,7 @@ func Decrypt(k *kms.KMS, ciphertext io.Reader, associatedData kms.Context) (io.R
|
||||
|
||||
key, err := k.Decrypt(context.TODO(), &kms.DecryptRequest{
|
||||
Name: metadata.KeyID,
|
||||
Version: metadata.Version,
|
||||
Ciphertext: metadata.KMSKey,
|
||||
AssociatedData: associatedData,
|
||||
})
|
||||
@@ -168,8 +170,9 @@ func Decrypt(k *kms.KMS, ciphertext io.Reader, associatedData kms.Context) (io.R
|
||||
}
|
||||
|
||||
type encryptedObject struct {
|
||||
KeyID string `json:"keyid"`
|
||||
KMSKey []byte `json:"kmskey"`
|
||||
KeyID string `json:"keyid"`
|
||||
Version string `json:"version"`
|
||||
KMSKey []byte `json:"kmskey"`
|
||||
|
||||
Algorithm sio.Algorithm `json:"algorithm"`
|
||||
Nonce []byte `json:"nonce"`
|
||||
|
||||
@@ -48,6 +48,12 @@ const (
|
||||
// the KMS.
|
||||
MetaDataEncryptionKey = "X-Minio-Internal-Server-Side-Encryption-S3-Kms-Sealed-Key"
|
||||
|
||||
// MetaKeyVersion is the version of the KMS master key used to generate/encrypt
|
||||
// the data encryption key (DEK). When a MinKMS master key is "rotated", it
|
||||
// adds another key version. MinIO has to remember which key version has been
|
||||
// used to encrypt an object.
|
||||
MetaKeyVersion = "X-Minio-Internal-Server-Side-Encryption-S3-Kms-Key-Version"
|
||||
|
||||
// MetaSsecCRC is the encrypted checksum of the SSE-C encrypted object.
|
||||
MetaSsecCRC = "X-Minio-Replication-Ssec-Crc"
|
||||
|
||||
@@ -108,6 +114,7 @@ func RemoveInternalEntries(metadata map[string]string) {
|
||||
delete(metadata, MetaSealedKeyS3)
|
||||
delete(metadata, MetaSealedKeyKMS)
|
||||
delete(metadata, MetaKeyID)
|
||||
delete(metadata, MetaKeyVersion)
|
||||
delete(metadata, MetaDataEncryptionKey)
|
||||
delete(metadata, MetaSsecCRC)
|
||||
}
|
||||
@@ -150,6 +157,9 @@ func IsEncrypted(metadata map[string]string) (Type, bool) {
|
||||
if _, ok := metadata[MetaKeyID]; ok {
|
||||
return nil, true
|
||||
}
|
||||
if _, ok := metadata[MetaKeyVersion]; ok {
|
||||
return nil, true
|
||||
}
|
||||
if _, ok := metadata[MetaDataEncryptionKey]; ok {
|
||||
return nil, true
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/minio/minio/internal/kms"
|
||||
"github.com/minio/minio/internal/logger"
|
||||
)
|
||||
|
||||
@@ -306,7 +307,7 @@ var s3CreateMetadataTests = []struct {
|
||||
SealedDataKey []byte
|
||||
SealedKey SealedKey
|
||||
}{
|
||||
{KeyID: "", SealedDataKey: nil, SealedKey: SealedKey{Algorithm: SealAlgorithm}},
|
||||
{KeyID: "foo", SealedDataKey: make([]byte, 32), SealedKey: SealedKey{Algorithm: SealAlgorithm}},
|
||||
{KeyID: "my-minio-key", SealedDataKey: make([]byte, 48), SealedKey: SealedKey{Algorithm: SealAlgorithm}},
|
||||
{KeyID: "cafebabe", SealedDataKey: make([]byte, 48), SealedKey: SealedKey{Algorithm: SealAlgorithm}},
|
||||
{KeyID: "deadbeef", SealedDataKey: make([]byte, 32), SealedKey: SealedKey{IV: [32]byte{0xf7}, Key: [64]byte{0xea}, Algorithm: SealAlgorithm}},
|
||||
@@ -316,7 +317,7 @@ func TestS3CreateMetadata(t *testing.T) {
|
||||
defer func(l bool) { logger.DisableLog = l }(logger.DisableLog)
|
||||
logger.DisableLog = true
|
||||
for i, test := range s3CreateMetadataTests {
|
||||
metadata := S3.CreateMetadata(nil, test.KeyID, test.SealedDataKey, test.SealedKey)
|
||||
metadata := S3.CreateMetadata(nil, kms.DEK{KeyID: test.KeyID, Ciphertext: test.SealedDataKey}, test.SealedKey)
|
||||
keyID, kmsKey, sealedKey, err := S3.ParseMetadata(metadata)
|
||||
if err != nil {
|
||||
t.Errorf("Test %d: failed to parse metadata: %v", i, err)
|
||||
@@ -344,7 +345,7 @@ func TestS3CreateMetadata(t *testing.T) {
|
||||
t.Errorf("Expected '%s' panic for invalid seal algorithm but got '%s'", logger.ErrCritical, err)
|
||||
}
|
||||
}()
|
||||
_ = S3.CreateMetadata(nil, "", []byte{}, SealedKey{Algorithm: InsecureSealAlgorithm})
|
||||
_ = S3.CreateMetadata(nil, kms.DEK{}, SealedKey{Algorithm: InsecureSealAlgorithm})
|
||||
}
|
||||
|
||||
var ssecCreateMetadataTests = []struct {
|
||||
|
||||
@@ -136,20 +136,15 @@ func (s3 ssekms) UnsealObjectKey(k *kms.KMS, metadata map[string]string, bucket,
|
||||
// the modified metadata. If the keyID and the kmsKey is not empty it encodes
|
||||
// both into the metadata as well. It allocates a new metadata map if metadata
|
||||
// is nil.
|
||||
func (ssekms) CreateMetadata(metadata map[string]string, keyID string, kmsKey []byte, sealedKey SealedKey, ctx kms.Context) map[string]string {
|
||||
func (ssekms) CreateMetadata(metadata map[string]string, dek kms.DEK, sealedKey SealedKey, ctx kms.Context) map[string]string {
|
||||
if sealedKey.Algorithm != SealAlgorithm {
|
||||
logger.CriticalIf(context.Background(), Errorf("The seal algorithm '%s' is invalid for SSE-S3", sealedKey.Algorithm))
|
||||
}
|
||||
|
||||
// There are two possibilities:
|
||||
// - We use a KMS -> There must be non-empty key ID and a KMS data key.
|
||||
// - We use a K/V -> There must be no key ID and no KMS data key.
|
||||
// Otherwise, the caller has passed an invalid argument combination.
|
||||
if keyID == "" && len(kmsKey) != 0 {
|
||||
logger.CriticalIf(context.Background(), errors.New("The key ID must not be empty if a KMS data key is present"))
|
||||
if dek.KeyID == "" {
|
||||
logger.CriticalIf(context.Background(), errors.New("The key ID must not be empty"))
|
||||
}
|
||||
if keyID != "" && len(kmsKey) == 0 {
|
||||
logger.CriticalIf(context.Background(), errors.New("The KMS data key must not be empty if a key ID is present"))
|
||||
if len(dek.Ciphertext) == 0 {
|
||||
logger.CriticalIf(context.Background(), errors.New("The DEK must not be empty"))
|
||||
}
|
||||
|
||||
if metadata == nil {
|
||||
@@ -159,13 +154,18 @@ func (ssekms) CreateMetadata(metadata map[string]string, keyID string, kmsKey []
|
||||
metadata[MetaAlgorithm] = sealedKey.Algorithm
|
||||
metadata[MetaIV] = base64.StdEncoding.EncodeToString(sealedKey.IV[:])
|
||||
metadata[MetaSealedKeyKMS] = base64.StdEncoding.EncodeToString(sealedKey.Key[:])
|
||||
metadata[MetaKeyID] = dek.KeyID
|
||||
metadata[MetaDataEncryptionKey] = base64.StdEncoding.EncodeToString(dek.Ciphertext)
|
||||
|
||||
if len(ctx) > 0 {
|
||||
b, _ := ctx.MarshalText()
|
||||
b, err := ctx.MarshalText()
|
||||
if err != nil {
|
||||
logger.CriticalIf(context.Background(), Errorf("crypto: failed to marshal KMS context: %v", err))
|
||||
}
|
||||
metadata[MetaContext] = base64.StdEncoding.EncodeToString(b)
|
||||
}
|
||||
if len(kmsKey) > 0 && keyID != "" { // We use a KMS -> Store key ID and sealed KMS data key.
|
||||
metadata[MetaKeyID] = keyID
|
||||
metadata[MetaDataEncryptionKey] = base64.StdEncoding.EncodeToString(kmsKey)
|
||||
if dek.Version != "" {
|
||||
metadata[MetaKeyVersion] = dek.Version
|
||||
}
|
||||
return metadata
|
||||
}
|
||||
|
||||
@@ -119,20 +119,15 @@ func (s3 sses3) UnsealObjectKeys(ctx context.Context, k *kms.KMS, metadata []map
|
||||
// the modified metadata. If the keyID and the kmsKey is not empty it encodes
|
||||
// both into the metadata as well. It allocates a new metadata map if metadata
|
||||
// is nil.
|
||||
func (sses3) CreateMetadata(metadata map[string]string, keyID string, kmsKey []byte, sealedKey SealedKey) map[string]string {
|
||||
func (sses3) CreateMetadata(metadata map[string]string, dek kms.DEK, sealedKey SealedKey) map[string]string {
|
||||
if sealedKey.Algorithm != SealAlgorithm {
|
||||
logger.CriticalIf(context.Background(), Errorf("The seal algorithm '%s' is invalid for SSE-S3", sealedKey.Algorithm))
|
||||
}
|
||||
|
||||
// There are two possibilities:
|
||||
// - We use a KMS -> There must be non-empty key ID and a KMS data key.
|
||||
// - We use a K/V -> There must be no key ID and no KMS data key.
|
||||
// Otherwise, the caller has passed an invalid argument combination.
|
||||
if keyID == "" && len(kmsKey) != 0 {
|
||||
logger.CriticalIf(context.Background(), errors.New("The key ID must not be empty if a KMS data key is present"))
|
||||
if dek.KeyID == "" {
|
||||
logger.CriticalIf(context.Background(), errors.New("The key ID must not be empty"))
|
||||
}
|
||||
if keyID != "" && len(kmsKey) == 0 {
|
||||
logger.CriticalIf(context.Background(), errors.New("The KMS data key must not be empty if a key ID is present"))
|
||||
if len(dek.Ciphertext) == 0 {
|
||||
logger.CriticalIf(context.Background(), errors.New("The DEK must not be empty"))
|
||||
}
|
||||
|
||||
if metadata == nil {
|
||||
@@ -142,9 +137,10 @@ func (sses3) CreateMetadata(metadata map[string]string, keyID string, kmsKey []b
|
||||
metadata[MetaAlgorithm] = sealedKey.Algorithm
|
||||
metadata[MetaIV] = base64.StdEncoding.EncodeToString(sealedKey.IV[:])
|
||||
metadata[MetaSealedKeyS3] = base64.StdEncoding.EncodeToString(sealedKey.Key[:])
|
||||
if len(kmsKey) > 0 && keyID != "" { // We use a KMS -> Store key ID and sealed KMS data key.
|
||||
metadata[MetaKeyID] = keyID
|
||||
metadata[MetaDataEncryptionKey] = base64.StdEncoding.EncodeToString(kmsKey)
|
||||
metadata[MetaKeyID] = dek.KeyID
|
||||
metadata[MetaDataEncryptionKey] = base64.StdEncoding.EncodeToString(dek.Ciphertext)
|
||||
if dek.Version != "" {
|
||||
metadata[MetaKeyVersion] = dek.Version
|
||||
}
|
||||
return metadata
|
||||
}
|
||||
|
||||
@@ -19,11 +19,8 @@ package kms
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/minio/madmin-go/v3"
|
||||
)
|
||||
|
||||
@@ -121,47 +118,7 @@ type Status struct {
|
||||
// storage.
|
||||
type DEK struct {
|
||||
KeyID string // Name of the master key
|
||||
Version int // Version of the master key (MinKMS only)
|
||||
Version string // Version of the master key
|
||||
Plaintext []byte // Paintext of the data encryption key
|
||||
Ciphertext []byte // Ciphertext of the data encryption key
|
||||
}
|
||||
|
||||
var (
|
||||
_ encoding.TextMarshaler = (*DEK)(nil)
|
||||
_ encoding.TextUnmarshaler = (*DEK)(nil)
|
||||
)
|
||||
|
||||
// MarshalText encodes the DEK's key ID and ciphertext
|
||||
// as JSON.
|
||||
func (d DEK) MarshalText() ([]byte, error) {
|
||||
type JSON struct {
|
||||
KeyID string `json:"keyid"`
|
||||
Version uint32 `json:"version,omitempty"`
|
||||
Ciphertext []byte `json:"ciphertext"`
|
||||
}
|
||||
return json.Marshal(JSON{
|
||||
KeyID: d.KeyID,
|
||||
Version: uint32(d.Version),
|
||||
Ciphertext: d.Ciphertext,
|
||||
})
|
||||
}
|
||||
|
||||
// UnmarshalText tries to decode text as JSON representation
|
||||
// of a DEK and sets DEK's key ID and ciphertext to the
|
||||
// decoded values.
|
||||
//
|
||||
// It sets DEK's plaintext to nil.
|
||||
func (d *DEK) UnmarshalText(text []byte) error {
|
||||
type JSON struct {
|
||||
KeyID string `json:"keyid"`
|
||||
Version uint32 `json:"version"`
|
||||
Ciphertext []byte `json:"ciphertext"`
|
||||
}
|
||||
var v JSON
|
||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
if err := json.Unmarshal(text, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
d.KeyID, d.Version, d.Plaintext, d.Ciphertext = v.KeyID, int(v.Version), nil, v.Ciphertext
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
// Copyright (c) 2015-2021 MinIO, Inc.
|
||||
//
|
||||
// This file is part of MinIO Object Storage stack
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package kms
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var dekEncodeDecodeTests = []struct {
|
||||
Key DEK
|
||||
}{
|
||||
{
|
||||
Key: DEK{},
|
||||
},
|
||||
{
|
||||
Key: DEK{
|
||||
Plaintext: nil,
|
||||
Ciphertext: mustDecodeB64("eyJhZWFkIjoiQUVTLTI1Ni1HQ00tSE1BQy1TSEEtMjU2IiwiaXYiOiJ3NmhLUFVNZXVtejZ5UlVZL29pTFVBPT0iLCJub25jZSI6IktMSEU3UE1jRGo2N2UweHkiLCJieXRlcyI6Ik1wUkhjQWJaTzZ1Sm5lUGJGcnpKTkxZOG9pdkxwTmlUcTNLZ0hWdWNGYkR2Y0RlbEh1c1lYT29zblJWVTZoSXIifQ=="),
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: DEK{
|
||||
Plaintext: mustDecodeB64("GM2UvLXp/X8lzqq0mibFC0LayDCGlmTHQhYLj7qAy7Q="),
|
||||
Ciphertext: mustDecodeB64("eyJhZWFkIjoiQUVTLTI1Ni1HQ00tSE1BQy1TSEEtMjU2IiwiaXYiOiJ3NmhLUFVNZXVtejZ5UlVZL29pTFVBPT0iLCJub25jZSI6IktMSEU3UE1jRGo2N2UweHkiLCJieXRlcyI6Ik1wUkhjQWJaTzZ1Sm5lUGJGcnpKTkxZOG9pdkxwTmlUcTNLZ0hWdWNGYkR2Y0RlbEh1c1lYT29zblJWVTZoSXIifQ=="),
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: DEK{
|
||||
Version: 3,
|
||||
Plaintext: mustDecodeB64("GM2UvLXp/X8lzqq0mibFC0LayDCGlmTHQhYLj7qAy7Q="),
|
||||
Ciphertext: mustDecodeB64("eyJhZWFkIjoiQUVTLTI1Ni1HQ00tSE1BQy1TSEEtMjU2IiwiaXYiOiJ3NmhLUFVNZXVtejZ5UlVZL29pTFVBPT0iLCJub25jZSI6IktMSEU3UE1jRGo2N2UweHkiLCJieXRlcyI6Ik1wUkhjQWJaTzZ1Sm5lUGJGcnpKTkxZOG9pdkxwTmlUcTNLZ0hWdWNGYkR2Y0RlbEh1c1lYT29zblJWVTZoSXIifQ=="),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestEncodeDecodeDEK(t *testing.T) {
|
||||
for i, test := range dekEncodeDecodeTests {
|
||||
text, err := test.Key.MarshalText()
|
||||
if err != nil {
|
||||
t.Fatalf("Test %d: failed to marshal DEK: %v", i, err)
|
||||
}
|
||||
|
||||
var key DEK
|
||||
if err = key.UnmarshalText(text); err != nil {
|
||||
t.Fatalf("Test %d: failed to unmarshal DEK: %v", i, err)
|
||||
}
|
||||
if key.Plaintext != nil {
|
||||
t.Fatalf("Test %d: unmarshaled DEK contains non-nil plaintext", i)
|
||||
}
|
||||
if !bytes.Equal(key.Ciphertext, test.Key.Ciphertext) {
|
||||
t.Fatalf("Test %d: ciphertext mismatch: got %x - want %x", i, key.Ciphertext, test.Key.Ciphertext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func mustDecodeB64(s string) []byte {
|
||||
b, err := base64.StdEncoding.DecodeString(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
@@ -206,6 +206,7 @@ func (c *kesConn) GenerateKey(ctx context.Context, req *GenerateKeyRequest) (DEK
|
||||
KeyID: name,
|
||||
Plaintext: dek.Plaintext,
|
||||
Ciphertext: dek.Ciphertext,
|
||||
Version: dek.Version,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -235,7 +236,7 @@ func (c *kesConn) Decrypt(ctx context.Context, req *DecryptRequest) ([]byte, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
plaintext, err := c.client.Decrypt(context.Background(), req.Name, req.Ciphertext, aad)
|
||||
plaintext, err := c.client.Decrypt(ctx, req.Name, req.Version, req.Ciphertext, aad)
|
||||
if err != nil {
|
||||
if errors.Is(err, kes.ErrKeyNotFound) {
|
||||
return nil, ErrKeyNotFound
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"slices"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
@@ -90,7 +91,7 @@ type DecryptRequest struct {
|
||||
// Version is the version of the master used for
|
||||
// decryption. If empty, the latest key version
|
||||
// is used.
|
||||
Version int
|
||||
Version string
|
||||
|
||||
// Ciphertext is the encrypted data that gets
|
||||
// decrypted.
|
||||
@@ -383,7 +384,7 @@ func (c *kmsConn) GenerateKey(ctx context.Context, req *GenerateKeyRequest) (DEK
|
||||
|
||||
return DEK{
|
||||
KeyID: name,
|
||||
Version: resp[0].Version,
|
||||
Version: strconv.Itoa(resp[0].Version),
|
||||
Plaintext: resp[0].Plaintext,
|
||||
Ciphertext: resp[0].Ciphertext,
|
||||
}, nil
|
||||
@@ -395,9 +396,17 @@ func (c *kmsConn) Decrypt(ctx context.Context, req *DecryptRequest) ([]byte, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
version := 1
|
||||
if req.Version != "" {
|
||||
if version, err = strconv.Atoi(req.Version); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
ciphertext, _ := parseCiphertext(req.Ciphertext)
|
||||
resp, err := c.client.Decrypt(ctx, c.enclave, &kms.DecryptRequest{
|
||||
Name: req.Name,
|
||||
Version: version,
|
||||
Ciphertext: ciphertext,
|
||||
AssociatedData: aad,
|
||||
})
|
||||
|
||||
@@ -154,7 +154,6 @@ func (s secretKey) GenerateKey(_ context.Context, req *GenerateKeyRequest) (DEK,
|
||||
ciphertext = append(ciphertext, random...)
|
||||
return DEK{
|
||||
KeyID: req.Name,
|
||||
Version: 0,
|
||||
Plaintext: plaintext,
|
||||
Ciphertext: ciphertext,
|
||||
}, nil
|
||||
|
||||
@@ -103,7 +103,7 @@ func (s StubKMS) GenerateKey(_ context.Context, req *GenerateKeyRequest) (DEK, e
|
||||
}
|
||||
return DEK{
|
||||
KeyID: req.Name,
|
||||
Version: 0,
|
||||
Version: "0",
|
||||
Plaintext: []byte("stubplaincharswhichare32bytelong"),
|
||||
Ciphertext: []byte("stubplaincharswhichare32bytelong"),
|
||||
}, nil
|
||||
|
||||
Reference in New Issue
Block a user