feature: Implements basic key generation.

This commit is contained in:
imterah 2024-11-22 07:25:17 -05:00
parent 768e17f840
commit a317342aa6
Signed by: imterah
GPG key ID: 8FA7DD57BA6CEA37
6 changed files with 308 additions and 2 deletions

188
main.go
View file

@ -1,7 +1,191 @@
package main
import "fmt"
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha1"
"crypto/x509"
"encoding/hex"
"encoding/pem"
"errors"
"fmt"
"log"
"os"
"os/signal"
"path"
"git.greysoh.dev/imterah/boron/bofs"
"github.com/hanwen/go-fuse/v2/fs"
"github.com/urfave/cli/v2"
)
func initializeFS(cCtx *cli.Context) error {
privKeyPath := cCtx.String("key")
allowKeyGeneration := cCtx.Bool("allow-keygeneration")
srcFolder := cCtx.String("source-folder")
destFolder := cCtx.String("dest-folder")
privKeyRaw, err := os.ReadFile(privKeyPath)
var privateKey *rsa.PrivateKey
if err != nil && errors.Is(err, os.ErrNotExist) && allowKeyGeneration {
log.Println("key not found. generating key...")
privateKey, err = rsa.GenerateKey(rand.Reader, 4096)
if err != nil {
return fmt.Errorf("could not generate private key: %s", err.Error())
}
log.Println("getting key signature...")
sha1Instance := sha1.New()
keySignature := sha1Instance.Sum(nil)
if _, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA1, keySignature); err != nil {
return fmt.Errorf("could not get key fingerprint/signature: %s", err.Error())
}
log.Println("saving public key...")
if err := os.Mkdir(path.Join(srcFolder, "keys"), os.ModePerm); err != nil && !errors.Is(err, os.ErrExist) {
return fmt.Errorf("failed to create keys folder: %s", err.Error())
}
pubKeyFile, err := os.Create(path.Join(srcFolder, "keys", hex.EncodeToString(keySignature)+".pub"))
if err != nil {
return fmt.Errorf("failed to open public key file: %s", err.Error())
}
// We're doing PCKS1 (todo: look into maybe changing to PCKS8?)
err = pem.Encode(
pubKeyFile,
&pem.Block{
Type: "PUBLIC KEY",
Bytes: x509.MarshalPKCS1PublicKey(&privateKey.PublicKey),
},
)
if err != nil {
return fmt.Errorf("failed to encode public key: %s", err.Error())
}
pubKeyFile.Close()
privKeyFile, err := os.Create(privKeyPath)
if err != nil {
return fmt.Errorf("failed to open public key file: %s", err.Error())
}
log.Println("saving private key...")
err = pem.Encode(
privKeyFile,
&pem.Block{
Type: "PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(privateKey),
},
)
if err != nil {
return fmt.Errorf("failed to encode private key: %s", err.Error())
}
privKeyFile.Close()
log.Println("finished key generation steps.")
} else if err == nil {
privKeyPem, _ := pem.Decode(privKeyRaw)
if privKeyPem.Type != "RSA PRIVATE KEY" && privKeyPem.Type != "PRIVATE KEY" {
return fmt.Errorf("decoded private key's header does not match RSA private key signature")
}
var parsedKey interface{}
if parsedKey, err = x509.ParsePKCS1PrivateKey(privKeyPem.Bytes); err != nil {
log.Println("failed to decode private key using PCKS1 format. trying PCKS8 next")
if parsedKey, err = x509.ParsePKCS8PrivateKey(privKeyPem.Bytes); err != nil {
return fmt.Errorf("failed to decode private key using PCKS8 format")
}
}
var ok bool // Hack to make Go not complain
privateKey, ok = parsedKey.(*rsa.PrivateKey)
if !ok {
return fmt.Errorf("failed to set privateKey variable (failed typecast)")
}
} else {
return fmt.Errorf("could not read private key: %s", err.Error())
}
opts := &fs.Options{}
log.Println("mounting filesystem...")
server, err := fs.Mount(destFolder, &bofs.BoronInode{}, opts)
if err != nil {
return err
}
log.Println("successfully mounted filesystem.")
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func() {
for _ = range c {
log.Println("unmounting filesystem...")
err := server.Unmount()
if err != nil {
log.Println("failed to unmount filesystem.")
}
os.Exit(0)
}
}()
server.Wait()
return nil
}
func main() {
fmt.Println("Hello, world!")
app := &cli.App{
Name: "boron",
Usage: "a collaborateive end-to-end-encrypted meta-filesystem",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "key",
Usage: "armored private key to use",
Required: true,
},
&cli.BoolFlag{
Name: "allow-keygeneration",
Usage: "if true, allows keys to be generated if the keys do not exist",
},
&cli.StringFlag{
Name: "source-folder",
Usage: "source folder to use",
Required: true,
},
&cli.StringFlag{
Name: "dest-folder",
Usage: "destination folder to use",
Required: true,
},
},
Action: initializeFS,
}
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}