github.com/opendevstack/tailor@v1.3.5-0.20220119161809-cab064e60a67/pkg/utils/encryption.go (about)

     1  package utils
     2  
     3  import (
     4  	"bytes"
     5  	"crypto"
     6  	"encoding/base64"
     7  	"fmt"
     8  	"io"
     9  	"io/ioutil"
    10  	"os"
    11  
    12  	"golang.org/x/crypto/openpgp"
    13  	"golang.org/x/crypto/openpgp/armor"
    14  	"golang.org/x/crypto/openpgp/packet"
    15  )
    16  
    17  func CreateEntity(name, email string) (*openpgp.Entity, error) {
    18  	var e *openpgp.Entity
    19  	conf := &packet.Config{
    20  		RSABits:       4096,
    21  		DefaultHash:   crypto.SHA256,
    22  		DefaultCipher: packet.CipherFunction(packet.CipherAES128),
    23  	}
    24  	e, err := openpgp.NewEntity(name, "Generated by tailor", email, conf)
    25  	if err != nil {
    26  		return nil, err
    27  	}
    28  
    29  	// Sign all the identities
    30  	for _, id := range e.Identities {
    31  		err := id.SelfSignature.SignUserId(id.UserId.Id, e.PrimaryKey, e.PrivateKey, nil)
    32  		if err != nil {
    33  			return nil, err
    34  		}
    35  	}
    36  	return e, nil
    37  }
    38  
    39  func PrintPublicKey(entity *openpgp.Entity, filename string) error {
    40  	f, err := os.Create(filename)
    41  	if err != nil {
    42  		return err
    43  	}
    44  	w, err := armor.Encode(f, openpgp.PublicKeyType, nil)
    45  	if err != nil {
    46  		return err
    47  	}
    48  	defer w.Close()
    49  	err = entity.Serialize(w)
    50  	if err != nil {
    51  		return err
    52  	}
    53  	_, err = io.WriteString(f, "\n")
    54  	if err != nil {
    55  		return err
    56  	}
    57  	return nil
    58  }
    59  
    60  func PrintPrivateKey(entity *openpgp.Entity, filename string) error {
    61  	f, err := os.Create(filename)
    62  	if err != nil {
    63  		return err
    64  	}
    65  	w, err := armor.Encode(f, openpgp.PrivateKeyType, nil)
    66  	if err != nil {
    67  		return err
    68  	}
    69  	err = entity.SerializePrivate(w, nil)
    70  	if err != nil {
    71  		return err
    72  	}
    73  	w.Close()
    74  	_, err = io.WriteString(f, "\n")
    75  	if err != nil {
    76  		return err
    77  	}
    78  	return nil
    79  }
    80  
    81  // Assembles entity list from keys in given files
    82  func GetEntityList(keys []string, passphrase string) (openpgp.EntityList, error) {
    83  	entityList := openpgp.EntityList{}
    84  	for _, filename := range keys {
    85  		keyringFileBuffer, _ := os.Open(filename)
    86  		defer keyringFileBuffer.Close()
    87  		l, err := openpgp.ReadArmoredKeyRing(keyringFileBuffer)
    88  		if err != nil {
    89  			return entityList, fmt.Errorf(
    90  				"Reading key '%s' failed: %s",
    91  				filename,
    92  				err,
    93  			)
    94  		}
    95  		entity := l[0]
    96  
    97  		// Decrypt private key using passphrase
    98  		passphraseBytes := []byte(passphrase)
    99  		if entity.PrivateKey != nil && entity.PrivateKey.Encrypted {
   100  			err := entity.PrivateKey.Decrypt(passphraseBytes)
   101  			if err != nil {
   102  				return entityList, fmt.Errorf("Failed to decrypt key: %s", err)
   103  			}
   104  		}
   105  		for _, subkey := range entity.Subkeys {
   106  			if subkey.PrivateKey != nil && subkey.PrivateKey.Encrypted {
   107  				err := subkey.PrivateKey.Decrypt(passphraseBytes)
   108  				if err != nil {
   109  					return entityList, fmt.Errorf(
   110  						"Failed to decrypt subkey: %s", err,
   111  					)
   112  				}
   113  			}
   114  		}
   115  
   116  		entityList = append(entityList, entity)
   117  	}
   118  	return entityList, nil
   119  }
   120  
   121  // Encrypts secret with all public keys and base64-encodes the result.
   122  func Encrypt(secret string, entityList openpgp.EntityList) (string, error) {
   123  	// Encrypt message using public keys
   124  	buf := new(bytes.Buffer)
   125  	w, err := openpgp.Encrypt(buf, entityList, nil, nil, nil)
   126  	if err != nil {
   127  		return "", fmt.Errorf("Encrypting '%s' failed: %s", secret, err)
   128  	}
   129  	_, err = w.Write([]byte(secret))
   130  	if err != nil {
   131  		return "", err
   132  	}
   133  	err = w.Close()
   134  	if err != nil {
   135  		return "", err
   136  	}
   137  
   138  	// Return as base64 encoded string
   139  	bytes, err := ioutil.ReadAll(buf)
   140  	if err != nil {
   141  		return "", err
   142  	}
   143  	str := base64.StdEncoding.EncodeToString(bytes)
   144  	return str, nil
   145  }
   146  
   147  // Decrypts the base64-encoded string end decrypts with the private key.
   148  func Decrypt(encoded string, entityList openpgp.EntityList) (string, error) {
   149  	// Decode bas64-encoded string
   150  	encrypted, err := base64.StdEncoding.DecodeString(encoded)
   151  	if err != nil {
   152  		return "", fmt.Errorf("Decoding '%s' failed: %s", encoded, err)
   153  	}
   154  
   155  	// Decrypt encrypted message
   156  	buf := bytes.NewBuffer([]byte(encrypted))
   157  	md, err := openpgp.ReadMessage(buf, entityList, nil, nil)
   158  	if err != nil {
   159  		return "", fmt.Errorf("Decrypting '%s' failed: %s", encoded, err)
   160  	}
   161  	bytes, err := ioutil.ReadAll(md.UnverifiedBody)
   162  	return string(bytes), err
   163  }