github.com/zntrio/harp/v2@v2.0.9/pkg/sdk/value/encryption/envelope/transformer.go (about)

     1  // Licensed to Elasticsearch B.V. under one or more contributor
     2  // license agreements. See the NOTICE file distributed with
     3  // this work for additional information regarding copyright
     4  // ownership. Elasticsearch B.V. licenses this file to you under
     5  // the Apache License, Version 2.0 (the "License"); you may
     6  // not use this file except in compliance with the License.
     7  // You may obtain a copy of the License at
     8  //
     9  //     http://www.apache.org/licenses/LICENSE-2.0
    10  //
    11  // Unless required by applicable law or agreed to in writing,
    12  // software distributed under the License is distributed on an
    13  // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    14  // KIND, either express or implied.  See the License for the
    15  // specific language governing permissions and limitations
    16  // under the License.
    17  
    18  package envelope
    19  
    20  import (
    21  	"context"
    22  	"crypto/rand"
    23  	"encoding/base64"
    24  	"fmt"
    25  
    26  	"github.com/zntrio/harp/v2/pkg/sdk/value"
    27  	"github.com/zntrio/harp/v2/pkg/sdk/value/encryption"
    28  
    29  	"golang.org/x/crypto/cryptobyte"
    30  )
    31  
    32  // Transformer returns an envelope encryption value transformer.
    33  func Transformer(envelopeService Service, transformerFactory encryption.TransformerFactoryFunc) (value.Transformer, error) {
    34  	return &envelopeTransformer{
    35  		envelopeService:        envelopeService,
    36  		transformerFactoryFunc: transformerFactory,
    37  	}, nil
    38  }
    39  
    40  // -----------------------------------------------------------------------------
    41  
    42  type envelopeTransformer struct {
    43  	envelopeService        Service
    44  	transformerFactoryFunc encryption.TransformerFactoryFunc
    45  }
    46  
    47  func (t *envelopeTransformer) To(ctx context.Context, input []byte) ([]byte, error) {
    48  	// Generate a random 32 byte length key
    49  	newKey := make([]byte, 32)
    50  	if _, err := rand.Read(newKey); err != nil {
    51  		return nil, fmt.Errorf("envelope: unable to generate dek key: %w", err)
    52  	}
    53  
    54  	// Encrypt DEK with envelope service
    55  	encKey, err := t.envelopeService.Encrypt(ctx, newKey)
    56  	if err != nil {
    57  		return nil, fmt.Errorf("envelope: unable to encrypt dek: %w", err)
    58  	}
    59  
    60  	// Build a transformer using key
    61  	transformer, err := t.transformerFactoryFunc(base64.URLEncoding.EncodeToString(newKey))
    62  	if err != nil {
    63  		return nil, fmt.Errorf("envelope: unable to initialize payload transformer: %w", err)
    64  	}
    65  
    66  	// Encrypt input using DEK
    67  	payload, err := transformer.To(ctx, input)
    68  	if err != nil {
    69  		return nil, fmt.Errorf("envelope: unable to encrypt data using dek: %w", err)
    70  	}
    71  
    72  	// Append the length of the encrypted DEK as the first 2 bytes.
    73  	b := cryptobyte.NewBuilder(nil)
    74  	b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
    75  		b.AddBytes(encKey)
    76  	})
    77  	b.AddBytes(payload)
    78  
    79  	// No error
    80  	return b.Bytes()
    81  }
    82  
    83  func (t *envelopeTransformer) From(ctx context.Context, input []byte) ([]byte, error) {
    84  	// Extract encrypted Data Encryption Key from input
    85  	var encKey cryptobyte.String
    86  
    87  	s := cryptobyte.String(input)
    88  	if ok := s.ReadUint16LengthPrefixed(&encKey); !ok {
    89  		return nil, fmt.Errorf("envelope: unable to read prefix")
    90  	}
    91  
    92  	// Encoded payload
    93  	payload := []byte(s)
    94  
    95  	// Decrypt DEK with envelope service
    96  	key, err := t.envelopeService.Decrypt(ctx, encKey)
    97  	if err != nil {
    98  		return nil, fmt.Errorf("envelope: unable to decrypt dek: %w", err)
    99  	}
   100  
   101  	// Build a transformer using decoded key
   102  	transformer, err := t.transformerFactoryFunc(base64.URLEncoding.EncodeToString(key))
   103  	if err != nil {
   104  		return nil, fmt.Errorf("envelope: unable to initialize payload transformer: %w", err)
   105  	}
   106  
   107  	// Delegate to transformer
   108  	return transformer.From(ctx, payload)
   109  }