Skip to content

Commit

Permalink
refactor: simplify API usage with higher level methods
Browse files Browse the repository at this point in the history
Signed-off-by: Pierre-Henri Symoneaux <[email protected]>
  • Loading branch information
phsym committed Oct 24, 2024
1 parent 258a014 commit 2f434c2
Show file tree
Hide file tree
Showing 17 changed files with 324 additions and 170 deletions.
16 changes: 5 additions & 11 deletions apis.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
// ANY KIND, either express or implied. See the License for the specific language
// governing permissions and limitations under the License.

// Package okms is a client for interacting with OVHcloud KMS REST-API.
package okms

import (
Expand All @@ -16,17 +17,18 @@ import (
"github.com/ovh/okms-sdk-go/types"
)

var _ Client = (*RestAPIClient)(nil)
var _ API = (*Client)(nil)

// Client is the interface abstracting the KMS clients methods.
type Client interface {
// API is the interface abstracting the KMS clients methods.
type API interface {
// RandomApi
DataKeyApi
SignatureApi
EncryptionApi
ServiceKeyApi
// SecretApi
// Ping(ctx context.Context) error
SetCustomHeader(key, value string)
}

// type RandomApi interface {
Expand Down Expand Up @@ -74,18 +76,10 @@ type ServiceKeyApi interface {
// ListServiceKeys returns a page of service keys. The response contains a continuationToken that must be passed to the
// subsequent calls in order to get the next page. The state parameter when no nil is used to query keys having a specific state.
ListServiceKeys(ctx context.Context, continuationToken *string, maxKey *int32, state *types.KeyStates) (*types.ListServiceKeysResponse, error)
// ListAllServiceKeys returns an iterator to go through all the keys without having to deal with pagination.
ListAllServiceKeys(pageSize *int32, state *types.KeyStates) KeyIter
// UpdateServiceKey updates some service key metadata.
UpdateServiceKey(ctx context.Context, keyId uuid.UUID, body types.PatchServiceKeyRequest) (*types.GetServiceKeyResponse, error)
}

// type ServiceKeyApi2 interface {
// GenerateSymmetricKey(ctx context.Context, name string, size types.KeySizes, usage ...types.CryptographicUsages) (*types.GetServiceKeyResponse, error)
// GenerateRSAKeyPair(ctx context.Context, name string, size types.KeySizes, usage ...types.CryptographicUsages) (*types.GetServiceKeyResponse, error)
// GenerateECDSAKeyPair(ctx context.Context, name string, curve types.Curves, usage ...types.CryptographicUsages) (*types.GetServiceKeyResponse, error)
// }

// type SecretApi interface {
// GetSecretsMetadata(ctx context.Context, path string, list bool) (*types.GetMetadataResponse, error)
// PatchSecretMetadata(ctx context.Context, path string, body types.SecretUpdatableMetadata) error
Expand Down
253 changes: 202 additions & 51 deletions client.go

Large diffs are not rendered by default.

13 changes: 9 additions & 4 deletions datakey.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,15 @@ import (
"math"

"github.com/google/uuid"
"github.com/ovh/okms-sdk-go/internal/utils"
"github.com/ovh/okms-sdk-go/internal/xcrypto"
)

// DataKeys creates a new datakey provider for the given service key.
func (client *Client) DataKeys(serviceKeyID uuid.UUID) *DataKeyProvider {
return newDataKeyProvider(client, serviceKeyID)
}

// DataKeyProvider is a helper provider that wraps an API client
// and provides helpers functions to repeatedly generate or decrypt datakeys
// protected by the same service key.
Expand All @@ -33,9 +39,9 @@ type DataKeyProvider struct {
keyId uuid.UUID
}

// NewDataKeyProvider creates a new datakey provider for the given service key,
// newDataKeyProvider creates a new datakey provider for the given service key,
// using the given [DataKeyApi] api client.
func NewDataKeyProvider(api DataKeyApi, keyId uuid.UUID) *DataKeyProvider {
func newDataKeyProvider(api DataKeyApi, keyId uuid.UUID) *DataKeyProvider {
return &DataKeyProvider{
api: api,
keyId: keyId,
Expand All @@ -52,8 +58,7 @@ func (sk *DataKeyProvider) GenerateDataKey(ctx context.Context, name string, siz
return nil, nil, errors.New("key size is out of bound")
}
// Let's first ask the KMS to generate a new DK
//nolint:gosec // integer bounds are checked right before
plain, encryptedKey, err := sk.api.GenerateDataKey(ctx, sk.keyId, name, int32(size))
plain, encryptedKey, err := sk.api.GenerateDataKey(ctx, sk.keyId, name, utils.ToInt32(size))
if err != nil {
return nil, nil, err
}
Expand Down
3 changes: 2 additions & 1 deletion errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"errors"
"fmt"

"github.com/ovh/okms-sdk-go/internal/utils"
"github.com/ovh/okms-sdk-go/types"
)

Expand Down Expand Up @@ -204,7 +205,7 @@ func newKmsErrorFromRestResponse(resp types.ErrorResponse) *KmsError {
kmsErr.ErrorId = *resp.ErrorId
}
if resp.ErrorCode != nil {
kmsErr.ErrorCode = ErrorCode(*resp.ErrorCode)
kmsErr.ErrorCode = ErrorCode(utils.ToUint32(*resp.ErrorCode))
}
if resp.Errors != nil {
for _, er := range *resp.Errors {
Expand Down
54 changes: 27 additions & 27 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ func ExampleNewRestAPIClientWithHttp() {
}

// Generate an 256 bits AES key
func ExampleRestAPIClient_CreateImportServiceKey_generateAES() {
var kmsClient *okms.RestAPIClient // Initialize client
func ExampleClient_CreateImportServiceKey_generateAES() {
var kmsClient *okms.Client // Initialize client
kType := types.Oct
kSize := types.N256
ops := []types.CryptographicUsages{types.Encrypt, types.Decrypt, types.WrapKey, types.UnwrapKey}
Expand All @@ -67,13 +67,13 @@ func ExampleRestAPIClient_CreateImportServiceKey_generateAES() {
}

// Generate a 2048 bits RSA key pair
func ExampleRestAPIClient_CreateImportServiceKey_generateRSA() {
var kmsClient *okms.RestAPIClient // Initialize client
func ExampleClient_CreateImportServiceKey_generateRSA() {
var kmsClient *okms.Client // Initialize client
kType := types.RSA
kSize := types.N2048
ops := []types.CryptographicUsages{types.Sign, types.Verify}
// Create a new RSA 2048 key-pair
respAes, err := kmsClient.CreateImportServiceKey(context.Background(), nil, types.CreateImportServiceKeyRequest{
respRSA, err := kmsClient.CreateImportServiceKey(context.Background(), nil, types.CreateImportServiceKeyRequest{
Name: "RSA key-pair example",
Type: &kType,
Size: &kSize,
Expand All @@ -82,17 +82,17 @@ func ExampleRestAPIClient_CreateImportServiceKey_generateRSA() {
if err != nil {
panic(err)
}
fmt.Println("RSA KEY:", respAes.Id)
fmt.Println("RSA KEY:", respRSA.Id)
}

// Generate an ECDSA key pair on the P-256 curve
func ExampleRestAPIClient_CreateImportServiceKey_generateECDSA() {
var kmsClient *okms.RestAPIClient // Initialize client
func ExampleClient_CreateImportServiceKey_generateECDSA() {
var kmsClient *okms.Client // Initialize client
kType := types.EC
curve := types.P256
ops := []types.CryptographicUsages{types.Sign, types.Verify}
// Create a new ECDSA P-256 key-pair
respAes, err := kmsClient.CreateImportServiceKey(context.Background(), nil, types.CreateImportServiceKeyRequest{
respEC, err := kmsClient.CreateImportServiceKey(context.Background(), nil, types.CreateImportServiceKeyRequest{
Name: "ECDSA key-pair example",
Type: &kType,
Curve: &curve,
Expand All @@ -101,23 +101,23 @@ func ExampleRestAPIClient_CreateImportServiceKey_generateECDSA() {
if err != nil {
panic(err)
}
fmt.Println("ECDSA KEY:", respAes.Id)
fmt.Println("ECDSA KEY:", respEC.Id)
}

func ExampleRestAPIClient_Sign() {
var kmsClient *okms.RestAPIClient // Initialize client
data := "Hello World !!!" // Data to sign
func ExampleClient_Sign() {
var kmsClient *okms.Client // Initialize client
data := "Hello World !!!" // Data to sign
signResponse, err := kmsClient.Sign(context.Background(), uuid.MustParse("2dab95dc-d7d3-482b-a07b-6b4dfae89d58"), types.ES256, false, []byte(data))
if err != nil {
panic(err)
}
fmt.Println("Signature:", signResponse)
}

func ExampleRestAPIClient_Verify() {
var kmsClient *okms.RestAPIClient // Initialize client
var signature string // Base64 encoded signature
data := "Hello World !!!" // Data to sign
func ExampleClient_Verify() {
var kmsClient *okms.Client // Initialize client
var signature string // Base64 encoded signature
data := "Hello World !!!" // Data to sign
result, err := kmsClient.Verify(context.Background(), uuid.MustParse("2dab95dc-d7d3-482b-a07b-6b4dfae89d58"), types.ES256, false, []byte(data), signature)
if err != nil {
panic(err)
Expand All @@ -126,10 +126,10 @@ func ExampleRestAPIClient_Verify() {
}

func ExampleDataKeyProvider_helpers() {
var kmsClient *okms.RestAPIClient // Initialize client
var kmsClient *okms.Client // Initialize client

data := "Hello World !!!" // Data to encrypt
dkProvider := okms.NewDataKeyProvider(kmsClient, uuid.MustParse("2dab95dc-d7d3-482b-a07b-6b4dfae89d58"))
dkProvider := kmsClient.DataKeys(uuid.MustParse("2dab95dc-d7d3-482b-a07b-6b4dfae89d58"))

// Unless you want to use another algorithm than AES-GCM 256 bits, you can use the 2 following helper methods:
encryptedData, encryptedKey, nonce, err := dkProvider.EncryptGCM(context.Background(), "Example DK", []byte(data), []byte("Some additional data"))
Expand All @@ -145,9 +145,9 @@ func ExampleDataKeyProvider_helpers() {
}

func ExampleDataKeyProvider_GenerateDataKey() {
var kmsClient *okms.RestAPIClient // Initialize client
data := "Hello World !!!" // Data to encrypt
dkProvider := okms.NewDataKeyProvider(kmsClient, uuid.MustParse("2dab95dc-d7d3-482b-a07b-6b4dfae89d58"))
var kmsClient *okms.Client // Initialize client
data := "Hello World !!!" // Data to encrypt
dkProvider := kmsClient.DataKeys(uuid.MustParse("2dab95dc-d7d3-482b-a07b-6b4dfae89d58"))

// Generate a new datakey
plain, encrypted, err := dkProvider.GenerateDataKey(context.Background(), "Example DK", 256)
Expand Down Expand Up @@ -178,11 +178,11 @@ func ExampleDataKeyProvider_GenerateDataKey() {
}

func ExampleDataKeyProvider_DecryptDataKey() {
var kmsClient *okms.RestAPIClient // Initialize client
var encryptedData []byte // Some encrypted data
var encryptedKey []byte // Encrypted datakey
var nonce []byte // Nonce used for data encryption
dkProvider := okms.NewDataKeyProvider(kmsClient, uuid.MustParse("2dab95dc-d7d3-482b-a07b-6b4dfae89d58"))
var kmsClient *okms.Client // Initialize client
var encryptedData []byte // Some encrypted data
var encryptedKey []byte // Encrypted datakey
var nonce []byte // Nonce used for data encryption
dkProvider := kmsClient.DataKeys(uuid.MustParse("2dab95dc-d7d3-482b-a07b-6b4dfae89d58"))

// Decrypt data key
plain, err := dkProvider.DecryptDataKey(context.Background(), encryptedKey)
Expand Down
33 changes: 9 additions & 24 deletions examples/datakeys.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,16 @@ import (
"github.com/ovh/okms-sdk-go/types"
)

func dataKeyEncryptDecrypt(ctx context.Context, kmsClient okms.Client) {
func dataKeyEncryptDecrypt(ctx context.Context, kmsClient *okms.Client) {
// Create a new AES 256 key
respAes, err := kmsClient.CreateImportServiceKey(ctx, nil, types.CreateImportServiceKeyRequest{
Name: "AES key example",
Type: ptrTo(types.Oct),
Size: ptrTo(types.N256),
Operations: ptrTo([]types.CryptographicUsages{types.Encrypt, types.Decrypt, types.WrapKey, types.UnwrapKey}),
})
respAes, err := kmsClient.GenerateSymmetricKey(ctx, types.N256, "AES key example", "", types.WrapKey, types.UnwrapKey)
if err != nil {
panic(err)
}

data := "Hello World !!!" // Data to encrypt

dkProvider := okms.NewDataKeyProvider(kmsClient, respAes.Id)
dkProvider := kmsClient.DataKeys(respAes.Id)

// ENCRYPTION

Expand Down Expand Up @@ -108,19 +103,14 @@ func dataKeyEncryptDecrypt(ctx context.Context, kmsClient okms.Client) {
fmt.Println("Decrypted:", string(plainData))
}

func dataKeyEncryptStream(ctx context.Context, kmsClient okms.Client) {
func dataKeyEncryptStream(ctx context.Context, kmsClient *okms.Client) {
// Create a new AES 256 key
respAes, err := kmsClient.CreateImportServiceKey(ctx, nil, types.CreateImportServiceKeyRequest{
Name: "AES key example",
Type: ptrTo(types.Oct),
Size: ptrTo(types.N256),
Operations: ptrTo([]types.CryptographicUsages{types.Encrypt, types.Decrypt, types.WrapKey, types.UnwrapKey}),
})
respAes, err := kmsClient.GenerateSymmetricKey(ctx, types.N256, "AES key example", "", types.WrapKey, types.UnwrapKey)
if err != nil {
panic(err)
}

dkProvider := okms.NewDataKeyProvider(kmsClient, respAes.Id)
dkProvider := kmsClient.DataKeys(respAes.Id)

sourceFile, err := os.Open("10GB_Plain_File.txt")
if err != nil {
Expand All @@ -146,19 +136,14 @@ func dataKeyEncryptStream(ctx context.Context, kmsClient okms.Client) {
}
}

func dataKeyDecryptStream(ctx context.Context, kmsClient okms.Client) {
func dataKeyDecryptStream(ctx context.Context, kmsClient *okms.Client) {
// Create a new AES 256 key
respAes, err := kmsClient.CreateImportServiceKey(ctx, nil, types.CreateImportServiceKeyRequest{
Name: "AES key example",
Type: ptrTo(types.Oct),
Size: ptrTo(types.N256),
Operations: ptrTo([]types.CryptographicUsages{types.Encrypt, types.Decrypt, types.WrapKey, types.UnwrapKey}),
})
respAes, err := kmsClient.GenerateSymmetricKey(ctx, types.N256, "AES key example", "", types.WrapKey, types.UnwrapKey)
if err != nil {
panic(err)
}

dkProvider := okms.NewDataKeyProvider(kmsClient, respAes.Id)
dkProvider := kmsClient.DataKeys(respAes.Id)

sourceFile, err := os.Create("Encrypted_File.bin")
if err != nil {
Expand Down
9 changes: 2 additions & 7 deletions examples/encrypt_decrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,9 @@ import (
"github.com/ovh/okms-sdk-go/types"
)

func encryptDecrypt(ctx context.Context, kmsClient okms.Client) {
func encryptDecrypt(ctx context.Context, kmsClient *okms.Client) {
// Create a new AES 256 key
respAes, err := kmsClient.CreateImportServiceKey(ctx, nil, types.CreateImportServiceKeyRequest{
Name: "AES key example",
Type: ptrTo(types.Oct),
Size: ptrTo(types.N256),
Operations: ptrTo([]types.CryptographicUsages{types.Encrypt, types.Decrypt, types.WrapKey, types.UnwrapKey}),
})
respAes, err := kmsClient.GenerateSymmetricKey(ctx, types.N256, "AES key example", "", types.Encrypt, types.Decrypt)
if err != nil {
panic(err)
}
Expand Down
23 changes: 4 additions & 19 deletions examples/generate_keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,38 +17,23 @@ import (
"github.com/ovh/okms-sdk-go/types"
)

func generateKeys(ctx context.Context, kmsClient okms.Client) {
func generateKeys(ctx context.Context, kmsClient *okms.Client) {
// Create a new AES 256 key
respAes, err := kmsClient.CreateImportServiceKey(ctx, nil, types.CreateImportServiceKeyRequest{
Name: "AES key example",
Type: ptrTo(types.Oct),
Size: ptrTo(types.N256),
Operations: ptrTo([]types.CryptographicUsages{types.Encrypt, types.Decrypt, types.WrapKey, types.UnwrapKey}),
})
respAes, err := kmsClient.GenerateSymmetricKey(ctx, types.N256, "AES key example", "", types.Encrypt, types.Decrypt, types.WrapKey, types.UnwrapKey)
if err != nil {
panic(err)
}
fmt.Println("AES KEY:", respAes.Id)

// Create a new RSA 2048 key-pair
respRSA, err := kmsClient.CreateImportServiceKey(ctx, nil, types.CreateImportServiceKeyRequest{
Name: "RSA key-pair example",
Type: ptrTo(types.RSA),
Size: ptrTo(types.N2048),
Operations: ptrTo([]types.CryptographicUsages{types.Sign, types.Verify}),
})
respRSA, err := kmsClient.GenerateRSAKeyPair(ctx, types.N2048, "RSA key-pair example", "", types.Sign, types.Verify)
if err != nil {
panic(err)
}
fmt.Println("RSA KEY:", respRSA.Id)

// Create a new ECDSA P-256 key-pair
respECDSA, err := kmsClient.CreateImportServiceKey(ctx, nil, types.CreateImportServiceKeyRequest{
Name: "ECDSA key-pair example",
Type: ptrTo(types.EC),
Curve: ptrTo(types.P256),
Operations: ptrTo([]types.CryptographicUsages{types.Sign, types.Verify}),
})
respECDSA, err := kmsClient.GenerateECKeyPair(ctx, types.P256, "ECDSA key-pair example", "", types.Sign, types.Verify)
if err != nil {
panic(err)
}
Expand Down
11 changes: 3 additions & 8 deletions examples/list_get.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
"github.com/ovh/okms-sdk-go/types"
)

func listKeys(ctx context.Context, kmsClient okms.Client) {
func listKeys(ctx context.Context, kmsClient *okms.Client) {
it := kmsClient.ListAllServiceKeys(nil, nil)
for it.Next(ctx) {
key, err := it.Value()
Expand All @@ -36,14 +36,9 @@ func listKeys(ctx context.Context, kmsClient okms.Client) {
}
}

func getKey(ctx context.Context, kmsClient okms.Client) {
func getKey(ctx context.Context, kmsClient *okms.Client) {
// Create a new AES 256 key
respAes, err := kmsClient.CreateImportServiceKey(ctx, nil, types.CreateImportServiceKeyRequest{
Name: "AES key example",
Type: ptrTo(types.Oct),
Size: ptrTo(types.N256),
Operations: ptrTo([]types.CryptographicUsages{types.Encrypt, types.Decrypt, types.WrapKey, types.UnwrapKey}),
})
respAes, err := kmsClient.GenerateSymmetricKey(ctx, types.N256, "AES key example", "", types.Encrypt, types.Decrypt, types.WrapKey, types.UnwrapKey)
if err != nil {
panic(err)
}
Expand Down
Loading

0 comments on commit 2f434c2

Please sign in to comment.