mirror of
https://github.com/andatoshiki/shikigrid.git
synced 2026-06-05 19:56:27 +00:00
174 lines
3.9 KiB
Go
174 lines
3.9 KiB
Go
package crypto
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"crypto/x509"
|
|
"encoding/pem"
|
|
"fmt"
|
|
"github.com/evilsocket/islazy/fs"
|
|
"github.com/evilsocket/islazy/log"
|
|
"os"
|
|
"path"
|
|
"strings"
|
|
)
|
|
|
|
type KeyPair struct {
|
|
Path string
|
|
Bits int
|
|
PrivatePath string
|
|
Private *rsa.PrivateKey
|
|
PrivatePEM []byte
|
|
PublicPath string
|
|
Public *rsa.PublicKey
|
|
PublicPEM []byte
|
|
// sha256 of PublicSSH
|
|
Fingerprint []byte
|
|
FingerprintHex string
|
|
}
|
|
|
|
func pubKeyToPEM(key *rsa.PublicKey) ([]byte, error) {
|
|
bytes, err := x509.MarshalPKIXPublicKey(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return pem.EncodeToMemory(
|
|
&pem.Block{
|
|
Type: "RSA PUBLIC KEY",
|
|
Bytes: bytes,
|
|
},
|
|
), nil
|
|
}
|
|
|
|
func FromPublicPEM(pubPEM string) (pair *KeyPair, err error) {
|
|
block, _ := pem.Decode([]byte(pubPEM))
|
|
if block == nil {
|
|
return nil, fmt.Errorf("failed to parse PEM block containing the public key")
|
|
}
|
|
|
|
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pair = &KeyPair{}
|
|
ok := false
|
|
|
|
if pair.Public, ok = pub.(*rsa.PublicKey); !ok {
|
|
return nil, fmt.Errorf("not an RSA key")
|
|
}
|
|
|
|
return pair, pair.setupPublic()
|
|
}
|
|
|
|
func PrivatePath(keysPath string) string {
|
|
return path.Join(keysPath, "id_rsa")
|
|
}
|
|
|
|
func Load(keysPath string) (pair *KeyPair, err error) {
|
|
privFile := PrivatePath(keysPath)
|
|
pair = &KeyPair{
|
|
Path: keysPath,
|
|
PrivatePath: privFile,
|
|
PublicPath: privFile + ".pub",
|
|
}
|
|
return pair, pair.Load()
|
|
}
|
|
|
|
func KeysExist(keysPath string) bool {
|
|
return fs.Exists(keysPath) && fs.Exists(PrivatePath(keysPath))
|
|
}
|
|
|
|
func LoadOrCreate(keysPath string, bits int) (pair *KeyPair, err error) {
|
|
privFile := PrivatePath(keysPath)
|
|
pair = &KeyPair{
|
|
Path: keysPath,
|
|
Bits: bits,
|
|
PrivatePath: privFile,
|
|
PublicPath: privFile + ".pub",
|
|
}
|
|
|
|
if !fs.Exists(pair.PrivatePath) {
|
|
if !fs.Exists(keysPath) {
|
|
log.Debug("creating %s", keysPath)
|
|
if err := os.MkdirAll(keysPath, os.ModePerm); err != nil {
|
|
return nil, fmt.Errorf("could not create %s: %v", keysPath, err)
|
|
}
|
|
}
|
|
log.Info("%s not found, generating keypair ...", pair.PrivatePath)
|
|
|
|
if pair.Private, err = rsa.GenerateKey(rand.Reader, bits); err != nil {
|
|
return nil, fmt.Errorf("could not generate private key: %v", err)
|
|
}
|
|
pair.Public = &pair.Private.PublicKey
|
|
|
|
if err = pair.Save(); err != nil {
|
|
return nil, fmt.Errorf("could not save keypair: %v", err)
|
|
}
|
|
} else if err = pair.Load(); err != nil {
|
|
return nil, fmt.Errorf("could not load keypair: %v", err)
|
|
}
|
|
|
|
return pair, nil
|
|
}
|
|
|
|
func (pair *KeyPair) setupPublic() (err error) {
|
|
if pair.PublicPEM, err = pubKeyToPEM(pair.Public); err != nil {
|
|
return fmt.Errorf("failed converting public key to PEM: %v", err)
|
|
}
|
|
|
|
cleanPEM := strings.TrimRight(string(pair.PublicPEM), "\n")
|
|
|
|
hash := Hasher.New()
|
|
hash.Write([]byte(cleanPEM))
|
|
|
|
pair.Fingerprint = hash.Sum(nil)
|
|
pair.FingerprintHex = fmt.Sprintf("%02x", pair.Fingerprint)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (pair *KeyPair) Save() (err error) {
|
|
prvKeyBytes := x509.MarshalPKCS1PrivateKey(pair.Private)
|
|
pair.PrivatePEM = pem.EncodeToMemory(
|
|
&pem.Block{
|
|
Type: "RSA PRIVATE KEY",
|
|
Bytes: prvKeyBytes,
|
|
},
|
|
)
|
|
|
|
if err = os.WriteFile(pair.PrivatePath, pair.PrivatePEM, os.ModePerm); err != nil {
|
|
return
|
|
}
|
|
|
|
log.Debug("%s created", pair.PrivatePath)
|
|
|
|
if err = pair.setupPublic(); err != nil {
|
|
return err
|
|
}
|
|
|
|
err = os.WriteFile(pair.PublicPath, pair.PublicPEM, os.ModePerm)
|
|
|
|
log.Debug("%s created", pair.PublicPath)
|
|
return
|
|
}
|
|
|
|
func (pair *KeyPair) Load() (err error) {
|
|
log.Debug("reading %s ...", pair.PrivatePath)
|
|
if pair.PrivatePEM, err = os.ReadFile(pair.PrivatePath); err != nil {
|
|
return
|
|
}
|
|
|
|
block, _ := pem.Decode(pair.PrivatePEM)
|
|
if block == nil {
|
|
return fmt.Errorf("failed decoding PEM from %s", pair.PrivatePath)
|
|
}
|
|
|
|
if pair.Private, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil {
|
|
return fmt.Errorf("failed parsing %s: %v", pair.PrivatePath, err)
|
|
}
|
|
|
|
pair.Public = &pair.Private.PublicKey
|
|
return pair.setupPublic()
|
|
}
|