github.com/zntrio/harp/v2@v2.0.9/pkg/container/seal/v1/helpers.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 v1
    19  
    20  import (
    21  	"bytes"
    22  	"errors"
    23  	"fmt"
    24  	"io"
    25  
    26  	"github.com/awnumar/memguard"
    27  	"google.golang.org/protobuf/proto"
    28  
    29  	containerv1 "github.com/zntrio/harp/v2/api/gen/go/harp/container/v1"
    30  	"github.com/zntrio/harp/v2/pkg/sdk/security"
    31  
    32  	"golang.org/x/crypto/blake2b"
    33  	"golang.org/x/crypto/nacl/box"
    34  	"golang.org/x/crypto/nacl/secretbox"
    35  )
    36  
    37  func pskStretch(key, salt []byte) (*[preSharedKeySize]byte, error) {
    38  	pskh, err := blake2b.New512(key)
    39  	if err != nil {
    40  		return nil, fmt.Errorf("unable to prepare preshared key: %w", err)
    41  	}
    42  	pskh.Write(salt)
    43  	hashPsk := pskh.Sum(nil)
    44  
    45  	psk := &[preSharedKeySize]byte{}
    46  	copy(psk[:], hashPsk[:preSharedKeySize])
    47  
    48  	return psk, nil
    49  }
    50  
    51  func deriveSharedKeyFromRecipient(publicKey, privateKey *[privateKeySize]byte, preSharedKey *[preSharedKeySize]byte) (*[encryptionKeySize]byte, error) {
    52  	// Prepare nonce
    53  	var nonce [nonceSize]byte
    54  	copy(nonce[:], "harp_derived_id_sboxkey0")
    55  
    56  	// Prepare payload
    57  	zero := make([]byte, 32)
    58  	memguard.WipeBytes(zero)
    59  
    60  	// Use box as a key agreement function
    61  	var sharedKey [encryptionKeySize]byte
    62  	derivedKey := box.Seal(nil, zero, &nonce, publicKey, privateKey)
    63  	copy(sharedKey[:], derivedKey[len(derivedKey)-encryptionKeySize:])
    64  
    65  	// Apply psk, this will act as a second knowledge factor to allow container
    66  	// unseal
    67  	if preSharedKey != nil {
    68  		// Compute HMAC-Blakeb of the shared secret.
    69  		pskh, err := blake2b.New(encryptionKeySize, preSharedKey[:])
    70  		if err != nil {
    71  			return nil, fmt.Errorf("unable to initialize PSK derivation: %w", err)
    72  		}
    73  		pskh.Write([]byte{0x00, 0x00, 0x00, 0x01})
    74  		pskh.Write(sharedKey[:])
    75  		skHash := pskh.Sum(nil)
    76  		copy(sharedKey[:], skHash[:encryptionKeySize])
    77  	}
    78  
    79  	// No error
    80  	return &sharedKey, nil
    81  }
    82  
    83  func computeHeaderHash(headers *containerv1.Header) ([]byte, error) {
    84  	// Check arguments
    85  	if headers == nil {
    86  		return nil, errors.New("unable process with nil headers")
    87  	}
    88  
    89  	// Prepare signature
    90  	header, err := proto.Marshal(headers)
    91  	if err != nil {
    92  		return nil, fmt.Errorf("unable to marshal container headers")
    93  	}
    94  
    95  	// Hash serialized proto
    96  	hash := blake2b.Sum512(header)
    97  
    98  	// No error
    99  	return hash[:], nil
   100  }
   101  
   102  func computeProtectedHash(headerHash, content []byte) []byte {
   103  	// Prepare protected content
   104  	protected := bytes.Buffer{}
   105  	protected.Write([]byte(signatureDomainSeparation))
   106  	protected.WriteByte(0x00)
   107  	protected.Write(headerHash)
   108  	contentHash := blake2b.Sum512(content)
   109  	protected.Write(contentHash[:])
   110  
   111  	// No error
   112  	return protected.Bytes()
   113  }
   114  
   115  func packRecipient(rand io.Reader, payloadKey, ephPrivKey, peerPublicKey *[publicKeySize]byte, preSharedKey *[preSharedKeySize]byte) (*containerv1.Recipient, error) {
   116  	// Check arguments
   117  	if payloadKey == nil {
   118  		return nil, fmt.Errorf("unable to proceed with nil payload key")
   119  	}
   120  	if ephPrivKey == nil {
   121  		return nil, fmt.Errorf("unable to proceed with nil private key")
   122  	}
   123  	if peerPublicKey == nil {
   124  		return nil, fmt.Errorf("unable to proceed with nil public key")
   125  	}
   126  
   127  	// Create recipient key
   128  	recipientKey, err := deriveSharedKeyFromRecipient(peerPublicKey, ephPrivKey, preSharedKey)
   129  	if err != nil {
   130  		return nil, fmt.Errorf("unable to derive shared recipient encryption key: %w", err)
   131  	}
   132  
   133  	// Calculate identifier
   134  	identifier, err := keyIdentifierFromDerivedKey(recipientKey, preSharedKey)
   135  	if err != nil {
   136  		return nil, fmt.Errorf("unable to derive key identifier: %w", err)
   137  	}
   138  
   139  	// Generate recipient nonce
   140  	var recipientNonce [nonceSize]byte
   141  	if _, err := io.ReadFull(rand, recipientNonce[:]); err != nil {
   142  		return nil, fmt.Errorf("unable to generate recipient nonce for encryption")
   143  	}
   144  
   145  	// Pack recipient
   146  	recipient := &containerv1.Recipient{
   147  		Identifier: identifier,
   148  		Key:        secretbox.Seal(recipientNonce[:], payloadKey[:], &recipientNonce, recipientKey),
   149  	}
   150  
   151  	// Return recipient
   152  	return recipient, nil
   153  }
   154  
   155  func keyIdentifierFromDerivedKey(derivedKey *[encryptionKeySize]byte, preSharedKey *[preSharedKeySize]byte) ([]byte, error) {
   156  	// Hash the derived key
   157  	h, err := blake2b.New512([]byte("harp signcryption box key identifier"))
   158  	if err != nil {
   159  		return nil, fmt.Errorf("unable to generate recipient identifier hasher")
   160  	}
   161  	if _, err := h.Write(derivedKey[:]); err != nil {
   162  		return nil, fmt.Errorf("unable to generate recipient identifier")
   163  	}
   164  
   165  	// Apply psk if specified
   166  	if preSharedKey != nil {
   167  		if _, err := h.Write(preSharedKey[:]); err != nil {
   168  			return nil, fmt.Errorf("unable to generate recipient identifier")
   169  		}
   170  	}
   171  
   172  	// Return 32 bytes trucanted hash.
   173  	return h.Sum(nil)[0:keyIdentifierSize], nil
   174  }
   175  
   176  func tryRecipientKeys(derivedKey *[encryptionKeySize]byte, recipients []*containerv1.Recipient, preSharedKey *[preSharedKeySize]byte) ([]byte, error) {
   177  	// Calculate recipient identifier
   178  	identifier, err := keyIdentifierFromDerivedKey(derivedKey, preSharedKey)
   179  	if err != nil {
   180  		return nil, fmt.Errorf("unable to generate identifier: %w", err)
   181  	}
   182  
   183  	// Find matching recipient
   184  	for _, r := range recipients {
   185  		// Check recipient identifiers
   186  		if !security.SecureCompare(identifier, r.Identifier) {
   187  			continue
   188  		}
   189  
   190  		var nonce [nonceSize]byte
   191  		copy(nonce[:], r.Key[:nonceSize])
   192  
   193  		// Try to decrypt the secretbox with the derived key.
   194  		payloadKey, isValid := secretbox.Open(nil, r.Key[nonceSize:], &nonce, derivedKey)
   195  		if !isValid {
   196  			return nil, fmt.Errorf("invalid recipient encryption key")
   197  		}
   198  
   199  		// Encryption key found, return no error.
   200  		return payloadKey, nil
   201  	}
   202  
   203  	// No recipient found in list.
   204  	return nil, fmt.Errorf("no recipient found")
   205  }