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 }