github.com/hashicorp/terraform-plugin-sdk@v1.17.2/internal/vault/helper/pgpkeys/encrypt_decrypt.go (about)

     1  package pgpkeys
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/base64"
     6  	"fmt"
     7  
     8  	"github.com/hashicorp/errwrap"
     9  	"github.com/keybase/go-crypto/openpgp"
    10  	"github.com/keybase/go-crypto/openpgp/packet"
    11  )
    12  
    13  // EncryptShares takes an ordered set of byte slices to encrypt and the
    14  // corresponding base64-encoded public keys to encrypt them with, encrypts each
    15  // byte slice with the corresponding public key.
    16  //
    17  // Note: There is no corresponding test function; this functionality is
    18  // thoroughly tested in the init and rekey command unit tests
    19  func EncryptShares(input [][]byte, pgpKeys []string) ([]string, [][]byte, error) {
    20  	if len(input) != len(pgpKeys) {
    21  		return nil, nil, fmt.Errorf("mismatch between number items to encrypt and number of PGP keys")
    22  	}
    23  	encryptedShares := make([][]byte, 0, len(pgpKeys))
    24  	entities, err := GetEntities(pgpKeys)
    25  	if err != nil {
    26  		return nil, nil, err
    27  	}
    28  	for i, entity := range entities {
    29  		ctBuf := bytes.NewBuffer(nil)
    30  		pt, err := openpgp.Encrypt(ctBuf, []*openpgp.Entity{entity}, nil, nil, nil)
    31  		if err != nil {
    32  			return nil, nil, errwrap.Wrapf("error setting up encryption for PGP message: {{err}}", err)
    33  		}
    34  		_, err = pt.Write(input[i])
    35  		if err != nil {
    36  			return nil, nil, errwrap.Wrapf("error encrypting PGP message: {{err}}", err)
    37  		}
    38  		pt.Close()
    39  		encryptedShares = append(encryptedShares, ctBuf.Bytes())
    40  	}
    41  
    42  	fingerprints, err := GetFingerprints(nil, entities)
    43  	if err != nil {
    44  		return nil, nil, err
    45  	}
    46  
    47  	return fingerprints, encryptedShares, nil
    48  }
    49  
    50  // GetFingerprints takes in a list of openpgp Entities and returns the
    51  // fingerprints. If entities is nil, it will instead parse both entities and
    52  // fingerprints from the pgpKeys string slice.
    53  func GetFingerprints(pgpKeys []string, entities []*openpgp.Entity) ([]string, error) {
    54  	if entities == nil {
    55  		var err error
    56  		entities, err = GetEntities(pgpKeys)
    57  
    58  		if err != nil {
    59  			return nil, err
    60  		}
    61  	}
    62  	ret := make([]string, 0, len(entities))
    63  	for _, entity := range entities {
    64  		ret = append(ret, fmt.Sprintf("%x", entity.PrimaryKey.Fingerprint))
    65  	}
    66  	return ret, nil
    67  }
    68  
    69  // GetEntities takes in a string array of base64-encoded PGP keys and returns
    70  // the openpgp Entities
    71  func GetEntities(pgpKeys []string) ([]*openpgp.Entity, error) {
    72  	ret := make([]*openpgp.Entity, 0, len(pgpKeys))
    73  	for _, keystring := range pgpKeys {
    74  		data, err := base64.StdEncoding.DecodeString(keystring)
    75  		if err != nil {
    76  			return nil, errwrap.Wrapf("error decoding given PGP key: {{err}}", err)
    77  		}
    78  		entity, err := openpgp.ReadEntity(packet.NewReader(bytes.NewBuffer(data)))
    79  		if err != nil {
    80  			return nil, errwrap.Wrapf("error parsing given PGP key: {{err}}", err)
    81  		}
    82  		ret = append(ret, entity)
    83  	}
    84  	return ret, nil
    85  }