Skip to content

How can I generate my own keys for client-side encryption with "amazon-s3-encryption-client-go/v3/client" ?

0

Hi, I want to do my own PutObject and GetObject functions with client-side encryption using the "amazon-s3-encryption-client-go/v3/client" package. In order to do that, I created my own cryptographic materials manager (cmm). But to generate the key to encrypt the file, I need to use the name of the file. The only way I found was to use the context argument to give the filename to my cmm.

cmm := MyMaterials.NewCustomedCryptographicMaterialsManager()

client := client.New(s3Client, cmm)

ctx := context.TODO()

ctx = context.WithValue(ctx, MyMaterials.FavContextKey("x"), []byte(filename))

out, err := client.PutObject(ctx, &s3.PutObjectInput{ Bucket: aws.String(bucket), Key: aws.String(key), Body: bytes.NewReader(body), })

Is it the right way for doing this ? Thank you for your help

asked a year ago631 views
1 Answer
0
Accepted Answer

Using the context.Context to pass additional parameters, such as the filename, to your custom Cryptographic Materials Manager (CMM) in the amazon-s3-encryption-client-go/v3/client package is a valid approach. This allows you to generate keys based on the filename or other context-specific information. Below is a detailed example of how you can achieve this:

Custom Cryptographic Materials Manager (CMM)

First, you need to create a custom CMM that can use the context to generate encryption keys.

package MyMaterials

import (
    "context"
    "crypto/rand"
    "crypto/sha256"
    "fmt"
    "github.com/aws/aws-sdk-go-v2/service/s3/types"
    "github.com/aws/aws-sdk-go-v2/feature/s3/manager"
)

type FavContextKey string

type CustomedCryptographicMaterialsManager struct{}

// NewCustomedCryptographicMaterialsManager creates a new instance of your custom CMM
func NewCustomedCryptographicMaterialsManager() *CustomedCryptographicMaterialsManager {
    return &CustomedCryptographicMaterialsManager{}
}

func (c *CustomedCryptographicMaterialsManager) DecryptMaterials(ctx context.Context, materials *types.EncryptionMaterials, opts ...func(*manager.EncryptionMaterialsDecryptOptions)) (*types.EncryptionMaterials, error) {
    // Implement decryption logic based on your requirements
    return nil, nil
}

func (c *CustomedCryptographicMaterialsManager) EncryptMaterials(ctx context.Context, materials *types.EncryptionMaterials, opts ...func(*manager.EncryptionMaterialsEncryptOptions)) (*types.EncryptionMaterials, error) {
    // Extract filename from context
    filename, ok := ctx.Value(FavContextKey("x")).([]byte)
    if !ok {
        return nil, fmt.Errorf("filename not found in context")
    }

    // Generate a key based on the filename (or any other method you prefer)
    hash := sha256.New()
    hash.Write(filename)
    encryptionKey := hash.Sum(nil)

    // Create a new EncryptionMaterials instance with the generated key
    materials = &types.EncryptionMaterials{
        MaterialDescription: map[string]string{
            "key": string(encryptionKey),
        },
        PlaintextKey: encryptionKey,
    }

    return materials, nil
}

Using the Custom CMM with the S3 Encryption Client

Next, integrate your custom CMM with the S3 encryption client and use the context to pass the filename.

package main

import (
    "bytes"
    "context"
    "fmt"
    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/config"
    "github.com/aws/aws-sdk-go-v2/service/s3"
    "github.com/aws/aws-sdk-go-v2/feature/s3/manager"
    "github.com/your-repo/your-package/MyMaterials" // Update the import path as necessary
)

func main() {
    // Load AWS configuration
    cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion("us-west-2"))
    if err != nil {
        fmt.Println("error loading configuration:", err)
        return
    }

    // Create an S3 client
    s3Client := s3.NewFromConfig(cfg)

    // Create your custom CMM
    cmm := MyMaterials.NewCustomedCryptographicMaterialsManager()

    // Create an S3 encryption client with your custom CMM
    encClient := manager.NewEncryptionClient(s3Client, func(o *manager.EncryptionClientOptions) {
        o.MaterialsManager = cmm
    })

    // Define bucket, key, and body
    bucket := "your-bucket-name"
    key := "your-object-key"
    body := []byte("your object data")
    filename := "your-filename"

    // Create a context with the filename
    ctx := context.TODO()
    ctx = context.WithValue(ctx, MyMaterials.FavContextKey("x"), []byte(filename))

    // Upload the object with encryption
    putObjectInput := &s3.PutObjectInput{
        Bucket: aws.String(bucket),
        Key:    aws.String(key),
        Body:   bytes.NewReader(body),
    }

    out, err := encClient.PutObject(ctx, putObjectInput)
    if err != nil {
        fmt.Println("error putting object:", err)
        return
    }

    fmt.Println("PutObject output:", out)
}

Explanation

1. Custom Cryptographic Materials Manager:

  • The EncryptMaterials method uses the filename from the context to generate a unique encryption key.
  • The key is created using a SHA-256 hash of the filename for simplicity, but you can use any method you prefer for key generation.

2. Context Usage:

  • The filename is added to the context using context.WithValue.
  • The custom CMM retrieves the filename from the context and uses it to generate the encryption key.

3. Integration:

  • The custom CMM is integrated with the S3 encryption client using the manager.NewEncryptionClient function.
  • The context with the filename is passed to the PutObject method to ensure the custom CMM can access it.

This approach ensures that your custom CMM can generate keys based on the filename or any other contextual information, providing flexibility for your client-side encryption needs.

EXPERT
answered a year ago
EXPERT
reviewed a year ago
EXPERT
reviewed a year ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.