github.com/zntrio/harp/v2@v2.0.9/pkg/sdk/value/encryption/aead/builders.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 aead
    19  
    20  import (
    21  	"crypto/aes"
    22  	"crypto/cipher"
    23  	"encoding/base64"
    24  	"fmt"
    25  	"strings"
    26  
    27  	miscreant "github.com/miscreant/miscreant.go"
    28  
    29  	"github.com/zntrio/harp/v2/build/fips"
    30  	"github.com/zntrio/harp/v2/pkg/sdk/value"
    31  	"github.com/zntrio/harp/v2/pkg/sdk/value/encryption"
    32  
    33  	"golang.org/x/crypto/chacha20poly1305"
    34  )
    35  
    36  var (
    37  	aesgcmPrefix     = "aes-gcm"
    38  	aespmacsivPrefix = "aes-pmac-siv"
    39  	aessivPrefix     = "aes-siv"
    40  	chachaPrefix     = "chacha"
    41  	xchachaPrefix    = "xchacha"
    42  )
    43  
    44  func init() {
    45  	encryption.Register(aesgcmPrefix, AESGCM)
    46  
    47  	if !fips.Enabled() {
    48  		encryption.Register(aespmacsivPrefix, AESPMACSIV)
    49  		encryption.Register(aessivPrefix, AESSIV)
    50  		encryption.Register(chachaPrefix, Chacha20Poly1305)
    51  		encryption.Register(xchachaPrefix, XChacha20Poly1305)
    52  	}
    53  }
    54  
    55  // AESGCM returns an AES-GCM value transformer instance.
    56  func AESGCM(key string) (value.Transformer, error) {
    57  	// Remove the prefix
    58  	key = strings.TrimPrefix(key, "aes-gcm:")
    59  
    60  	// Decode key
    61  	k, err := base64.URLEncoding.DecodeString(key)
    62  	if err != nil {
    63  		return nil, fmt.Errorf("aes: unable to decode transformer key: %w", err)
    64  	}
    65  
    66  	// Check key length
    67  	switch len(k) {
    68  	case 16, 24, 32:
    69  	default:
    70  		return nil, fmt.Errorf("aes: invalid key length, use 16 bytes (AES128) or 24 bytes (AES192) or 32 bytes (AES256)")
    71  	}
    72  
    73  	// Create AES block cipher
    74  	block, err := aes.NewCipher(k)
    75  	if err != nil {
    76  		return nil, fmt.Errorf("aes: unable to initialize block cipher: %w", err)
    77  	}
    78  
    79  	// Initialize AEAD cipher chain
    80  	aead, err := cipher.NewGCM(block)
    81  	if err != nil {
    82  		return nil, fmt.Errorf("aes: unable to initialize aead chain : %w", err)
    83  	}
    84  
    85  	// Return transformer
    86  	return &aeadTransformer{
    87  		aead: aead,
    88  	}, nil
    89  }
    90  
    91  // AESSIV returns an AES-SIV/AES-CMAC-SIV value transformer instance.
    92  func AESSIV(key string) (value.Transformer, error) {
    93  	// Remove the prefix
    94  	key = strings.TrimPrefix(key, "aes-siv:")
    95  
    96  	// Decode key
    97  	k, err := base64.URLEncoding.DecodeString(key)
    98  	if err != nil {
    99  		return nil, fmt.Errorf("aes: unable to decode transformer key: %w", err)
   100  	}
   101  	if l := len(k); l != 64 {
   102  		return nil, fmt.Errorf("aes: invalid secret key length (%d)", l)
   103  	}
   104  
   105  	// Initialize AEAD
   106  	aead, err := miscreant.NewAEAD("AES-SIV", k, 16)
   107  	if err != nil {
   108  		return nil, fmt.Errorf("aes: unable to initialize aes-pmac-siv: %w", err)
   109  	}
   110  
   111  	// Return transformer
   112  	return &aeadTransformer{
   113  		aead: aead,
   114  	}, nil
   115  }
   116  
   117  // AESPMACSIV returns an AES-PMAC-SIV value transformer instance.
   118  func AESPMACSIV(key string) (value.Transformer, error) {
   119  	// Remove the prefix
   120  	key = strings.TrimPrefix(key, "aes-pmac-siv:")
   121  
   122  	// Decode key
   123  	k, err := base64.URLEncoding.DecodeString(key)
   124  	if err != nil {
   125  		return nil, fmt.Errorf("aes: unable to decode transformer key: %w", err)
   126  	}
   127  	if l := len(k); l != 64 {
   128  		return nil, fmt.Errorf("aes: invalid secret key length (%d)", l)
   129  	}
   130  
   131  	// Initialize AEAD
   132  	aead, err := miscreant.NewAEAD("AES-PMAC-SIV", k, 16)
   133  	if err != nil {
   134  		return nil, fmt.Errorf("aes: unable to initialize aes-pmac-siv: %w", err)
   135  	}
   136  
   137  	// Return transformer
   138  	return &aeadTransformer{
   139  		aead: aead,
   140  	}, nil
   141  }
   142  
   143  // Chacha20Poly1305 returns an ChaCha20Poly1305 value transformer instance.
   144  func Chacha20Poly1305(key string) (value.Transformer, error) {
   145  	// Remove the prefix
   146  	key = strings.TrimPrefix(key, "chacha:")
   147  
   148  	// Decode key
   149  	k, err := base64.URLEncoding.DecodeString(key)
   150  	if err != nil {
   151  		return nil, fmt.Errorf("chacha: unable to decode transformer key: %w", err)
   152  	}
   153  	if l := len(k); l != keyLength {
   154  		return nil, fmt.Errorf("chacha: invalid secret key length (%d)", l)
   155  	}
   156  
   157  	// Create Chacha20-Poly1305 aead cipher
   158  	aead, err := chacha20poly1305.New(k)
   159  	if err != nil {
   160  		return nil, fmt.Errorf("chacha: unable to initialize chacha cipher: %w", err)
   161  	}
   162  
   163  	// Return transformer
   164  	return &aeadTransformer{
   165  		aead: aead,
   166  	}, nil
   167  }
   168  
   169  // XChacha20Poly1305 returns an XChaCha20Poly1305 value transformer instance.
   170  func XChacha20Poly1305(key string) (value.Transformer, error) {
   171  	// Remove the prefix
   172  	key = strings.TrimPrefix(key, "xchacha:")
   173  
   174  	// Decode key
   175  	k, err := base64.URLEncoding.DecodeString(key)
   176  	if err != nil {
   177  		return nil, fmt.Errorf("xchacha: unable to decode transformer key: %w", err)
   178  	}
   179  	if l := len(k); l != keyLength {
   180  		return nil, fmt.Errorf("xchacha: invalid secret key length (%d)", l)
   181  	}
   182  
   183  	// Create Chacha20-Poly1305 aead cipher
   184  	aead, err := chacha20poly1305.NewX(k)
   185  	if err != nil {
   186  		return nil, fmt.Errorf("xchacha: unable to initialize chacha cipher: %w", err)
   187  	}
   188  
   189  	// Return transformer
   190  	return &aeadTransformer{
   191  		aead: aead,
   192  	}, nil
   193  }