Skip to content

Commit

Permalink
add HMAC API and use KMS secret key crypto (#433)
Browse files Browse the repository at this point in the history
  • Loading branch information
aead authored Jan 12, 2024
1 parent bd277c4 commit 480ab49
Show file tree
Hide file tree
Showing 18 changed files with 1,437 additions and 681 deletions.
1 change: 1 addition & 0 deletions api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ func testListAPIDefaults(t *testing.T) {
"/v1/key/generate/": {Method: http.MethodPut, MaxBody: 1 * mem.MB, Timeout: 15 * time.Second},
"/v1/key/encrypt/": {Method: http.MethodPut, MaxBody: 1 * mem.MB, Timeout: 15 * time.Second},
"/v1/key/decrypt/": {Method: http.MethodPut, MaxBody: 1 * mem.MB, Timeout: 15 * time.Second},
"/v1/key/hmac/": {Method: http.MethodPut, MaxBody: 1 * mem.MB, Timeout: 15 * time.Second},

"/v1/policy/describe/": {Method: http.MethodGet, MaxBody: 0, Timeout: 15 * time.Second},
"/v1/policy/read/": {Method: http.MethodGet, MaxBody: 0, Timeout: 15 * time.Second},
Expand Down
1 change: 1 addition & 0 deletions internal/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const (
PathKeyGenerate = "/v1/key/generate/"
PathKeyEncrypt = "/v1/key/encrypt/"
PathKeyDecrypt = "/v1/key/decrypt/"
PathKeyHMAC = "/v1/key/hmac/"

PathPolicyDescribe = "/v1/policy/describe/"
PathPolicyRead = "/v1/policy/read/"
Expand Down
5 changes: 5 additions & 0 deletions internal/api/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,8 @@ type DecryptKeyRequest struct {
Ciphertext []byte `json:"ciphertext"`
Context []byte `json:"context"` // optional
}

// HMACRequest is the request sent by clients when calling the HMAC API.
type HMACRequest struct {
Message []byte `json:"message"`
}
5 changes: 5 additions & 0 deletions internal/api/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ type DecryptKeyResponse struct {
Plaintext []byte `json:"plaintext"`
}

// HMACResponse is the response sent to clients by the HMAC API.
type HMACResponse struct {
Sum []byte `json:"hmac"`
}

// ReadPolicyResponse is the response sent to clients by the ReadPolicy API.
type ReadPolicyResponse struct {
Name string `json:"name"`
Expand Down
67 changes: 29 additions & 38 deletions internal/key/ciphertext.go → internal/crypto/ciphertext.go
Original file line number Diff line number Diff line change
@@ -1,43 +1,50 @@
// Copyright 2022 - MinIO, Inc. All rights reserved.
// Copyright 2024 - MinIO, Inc. All rights reserved.
// Use of this source code is governed by the AGPLv3
// license that can be found in the LICENSE file.

package key
package crypto

import (
"encoding/json"
"slices"

"github.com/minio/kes-go"
"github.com/tinylib/msgp/msgp"
)

// decodeCiphertext parses the given bytes as
// ciphertext. If it fails to unmarshal the
// given bytes, decodeCiphertext returns
// ErrDecrypt.
func decodeCiphertext(bytes []byte) (ciphertext, error) {
if len(bytes) == 0 {
return ciphertext{}, kes.ErrDecrypt
// parseCiphertext parses and converts a ciphertext into
// the format expected by a SecretKey.
//
// Previous implementations of a SecretKey produced a structured
// ciphertext. parseCiphertext converts all previously generated
// formats into the one that SecretKey.Decrypt expects.
func parseCiphertext(b []byte) []byte {
if len(b) == 0 {
return b
}

var c ciphertext
switch bytes[0] {
switch b[0] {
case 0x95: // msgp first byte
if err := c.UnmarshalBinary(bytes); err != nil {
return ciphertext{}, kes.ErrDecrypt
if err := c.UnmarshalBinary(b); err != nil {
return b
}

b = b[:0]
b = append(b, c.Bytes...)
b = append(b, c.IV...)
b = append(b, c.Nonce...)
case 0x7b: // JSON first byte
if err := c.UnmarshalJSON(bytes); err != nil {
return ciphertext{}, kes.ErrDecrypt
}
default:
if err := c.UnmarshalBinary(bytes); err != nil {
if err = c.UnmarshalJSON(bytes); err != nil {
return ciphertext{}, kes.ErrDecrypt
}
if err := c.UnmarshalJSON(b); err != nil {
return b
}

b = b[:0]
b = append(b, c.Bytes...)
b = append(b, c.IV...)
b = append(b, c.Nonce...)
}
return c, nil
return b
}

// ciphertext is a structure that contains the encrypted
Expand All @@ -51,22 +58,6 @@ type ciphertext struct {
Bytes []byte
}

// MarshalBinary returns the ciphertext's binary representation.
func (c *ciphertext) MarshalBinary() ([]byte, error) {
// We encode a ciphertext simply as message-pack
// flat array.
const Items = 5

var b []byte
b = msgp.AppendArrayHeader(b, Items)
b = msgp.AppendString(b, c.Algorithm.String())
b = msgp.AppendString(b, c.ID)
b = msgp.AppendBytes(b, c.IV)
b = msgp.AppendBytes(b, c.Nonce)
b = msgp.AppendBytes(b, c.Bytes)
return b, nil
}

// UnmarshalBinary parses b as binary-encoded ciphertext.
func (c *ciphertext) UnmarshalBinary(b []byte) error {
const (
Expand Down Expand Up @@ -117,7 +108,7 @@ func (c *ciphertext) UnmarshalBinary(b []byte) error {
c.ID = id
c.IV = iv[:]
c.Nonce = nonce[:]
c.Bytes = clone(bytes...)
c.Bytes = slices.Clone(bytes)
return nil
}

Expand Down
Loading

0 comments on commit 480ab49

Please sign in to comment.