go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/os/connection/ssh/keypair/keygen.go (about)

     1  // Copyright (c) Mondoo, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package keypair
     5  
     6  import (
     7  	"bytes"
     8  	"crypto/ed25519"
     9  	"crypto/rand"
    10  	"crypto/rsa"
    11  	"crypto/x509"
    12  	"encoding/pem"
    13  
    14  	"golang.org/x/crypto/ssh"
    15  )
    16  
    17  const DefaultRsaBits = 4096
    18  
    19  // SSH holds an SSH keys pair
    20  type SSH struct {
    21  	// PrivateKey contains PEM encoded private key
    22  	PrivateKey []byte
    23  
    24  	// PublicKey serializes key for inclusion in an OpenSSH authorized_keys file
    25  	// https://datatracker.ietf.org/doc/html/rfc4253#section-6.6
    26  	PublicKey []byte
    27  
    28  	// Optional Passphrase
    29  	Passphrase []byte
    30  }
    31  
    32  // NewEd25519Keys creates EdD25519 key pair
    33  func NewEd25519Keys() (*SSH, error) {
    34  	pubKey, privateKey, err := ed25519.GenerateKey(rand.Reader)
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  
    39  	publicKey, err := ssh.NewPublicKey(pubKey)
    40  	if err != nil {
    41  		return nil, err
    42  	}
    43  
    44  	return &SSH{
    45  		PrivateKey: pem.EncodeToMemory(&pem.Block{
    46  			Type:  "OPENSSH PRIVATE KEY",
    47  			Bytes: MarshalED25519PrivateKey(privateKey),
    48  		}),
    49  		PublicKey: MarshalPublicKey(publicKey, ""),
    50  	}, nil
    51  }
    52  
    53  // NewRSAKeys creates RSA key pair
    54  func NewRSAKeys(bits int, passphrase []byte) (*SSH, error) {
    55  	// generate rsa private key
    56  	privateKey, err := rsa.GenerateKey(rand.Reader, bits)
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  
    61  	err = privateKey.Validate()
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  
    66  	block := &pem.Block{
    67  		Type:    "RSA PRIVATE KEY",
    68  		Headers: nil,
    69  		Bytes:   x509.MarshalPKCS1PrivateKey(privateKey), // ASN.1 DER format
    70  	}
    71  
    72  	// optional: encrypt private key with passphrase
    73  	if len(passphrase) > 0 {
    74  		block, err = x509.EncryptPEMBlock(rand.Reader, block.Type, block.Bytes, passphrase, x509.PEMCipherAES256)
    75  		if err != nil {
    76  			return nil, err
    77  		}
    78  	}
    79  
    80  	// generate rsa public key
    81  	publicRSAKey, err := ssh.NewPublicKey(privateKey.Public())
    82  	if err != nil {
    83  		return nil, err
    84  	}
    85  
    86  	return &SSH{
    87  		PrivateKey: pem.EncodeToMemory(block), // PEM encoded
    88  		PublicKey:  MarshalPublicKey(publicRSAKey, ""),
    89  		Passphrase: passphrase,
    90  	}, nil
    91  }
    92  
    93  func MarshalPublicKey(pubKey ssh.PublicKey, note string) []byte {
    94  	return append(bytes.TrimRight(ssh.MarshalAuthorizedKey(pubKey), "\n"), []byte(note)...)
    95  }