feature: Implements basic key generation.
This commit is contained in:
parent
768e17f840
commit
a317342aa6
6 changed files with 308 additions and 2 deletions
188
main.go
188
main.go
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue