github.com/hairyhenderson/gomplate/v4@v4.0.0-pre-2.0.20240520121557-362f058f0c93/crypto/rsa.go (about)

     1  package crypto
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/rand"
     6  	"crypto/rsa"
     7  	"crypto/x509"
     8  	"encoding/pem"
     9  	"fmt"
    10  	"strings"
    11  )
    12  
    13  // RSAEncrypt - use the given public key to encrypt the given plaintext. The key
    14  // should be a PEM-encoded RSA public key in PKIX, ASN.1 DER form, typically
    15  // beginning with "PUBLIC KEY". PKCS#1 format is also supported as a fallback.
    16  // The output will not be encoded, so consider base64-encoding it for display.
    17  func RSAEncrypt(key string, in []byte) ([]byte, error) {
    18  	block, _ := pem.Decode([]byte(key))
    19  	if block == nil {
    20  		return nil, fmt.Errorf("failed to read key %q: no key found", key)
    21  	}
    22  
    23  	pub, err := x509.ParsePKIXPublicKey(block.Bytes)
    24  	if err != nil {
    25  		if strings.Contains(err.Error(), "use ParsePKCS1PublicKey instead") {
    26  			pub, err = x509.ParsePKCS1PublicKey(block.Bytes)
    27  		}
    28  		if err != nil {
    29  			return nil, fmt.Errorf("failed to parse public key: %w", err)
    30  		}
    31  	}
    32  	pubKey, ok := pub.(*rsa.PublicKey)
    33  	if !ok {
    34  		return nil, fmt.Errorf("public key in wrong format, was %T", pub)
    35  	}
    36  
    37  	out, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, in)
    38  	return out, err
    39  }
    40  
    41  // RSADecrypt - decrypt the ciphertext with the given private key. The key
    42  // must be a PEM-encoded RSA private key in PKCS#1, ASN.1 DER form, typically
    43  // beginning with "RSA PRIVATE KEY". The input text must be plain ciphertext,
    44  // not base64-encoded.
    45  func RSADecrypt(key string, in []byte) ([]byte, error) {
    46  	block, _ := pem.Decode([]byte(key))
    47  	if block == nil {
    48  		return nil, fmt.Errorf("failed to read key %q: no key found", key)
    49  	}
    50  
    51  	priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
    52  	if err != nil {
    53  		return nil, fmt.Errorf("invalid private key: %w", err)
    54  	}
    55  
    56  	out, err := priv.Decrypt(nil, in, nil)
    57  	if err != nil {
    58  		return nil, fmt.Errorf("failed to decrypt: %w", err)
    59  	}
    60  	return out, nil
    61  }
    62  
    63  // RSAGenerateKey -
    64  func RSAGenerateKey(bits int) ([]byte, error) {
    65  	// Protect against CWE-326: Inadequate Encryption Strength
    66  	// https://cwe.mitre.org/data/definitions/326.html
    67  	if bits < 2048 {
    68  		return nil, fmt.Errorf("RSA key size must be at least 2048 bits")
    69  	}
    70  	priv, err := rsa.GenerateKey(rand.Reader, bits)
    71  	if err != nil {
    72  		return nil, fmt.Errorf("failed to generate RSA private key: %w", err)
    73  	}
    74  	block := &pem.Block{
    75  		Type:  "RSA PRIVATE KEY",
    76  		Bytes: x509.MarshalPKCS1PrivateKey(priv),
    77  	}
    78  	buf := &bytes.Buffer{}
    79  	err = pem.Encode(buf, block)
    80  	if err != nil {
    81  		return nil, fmt.Errorf("failed to encode generated RSA private key: pem encoding failed: %w", err)
    82  	}
    83  	return buf.Bytes(), nil
    84  }
    85  
    86  // RSADerivePublicKey -
    87  func RSADerivePublicKey(privateKey []byte) ([]byte, error) {
    88  	block, _ := pem.Decode(privateKey)
    89  	if block == nil {
    90  		return nil, fmt.Errorf("failed to read key: no key found")
    91  	}
    92  
    93  	priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
    94  	if err != nil {
    95  		return nil, fmt.Errorf("invalid private key: %w", err)
    96  	}
    97  
    98  	b, err := x509.MarshalPKIXPublicKey(&priv.PublicKey)
    99  	if err != nil {
   100  		return nil, fmt.Errorf("failed to marshal PKIX public key: %w", err)
   101  	}
   102  
   103  	block = &pem.Block{
   104  		Type:  "PUBLIC KEY",
   105  		Bytes: b,
   106  	}
   107  
   108  	return pem.EncodeToMemory(block), nil
   109  }