feature: Implements basic key generation.
This commit is contained in:
parent
768e17f840
commit
a317342aa6
6 changed files with 308 additions and 2 deletions
33
bofs/fs.go
Normal file
33
bofs/fs.go
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
package bofs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/hanwen/go-fuse/v2/fs"
|
||||||
|
"github.com/hanwen/go-fuse/v2/fuse"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BoronInode struct {
|
||||||
|
fs.Inode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *BoronInode) OnAdd(ctx context.Context) {
|
||||||
|
ch := r.NewPersistentInode(
|
||||||
|
ctx, &fs.MemRegularFile{
|
||||||
|
Data: []byte("file.txt"),
|
||||||
|
Attr: fuse.Attr{
|
||||||
|
Mode: 0644,
|
||||||
|
},
|
||||||
|
}, fs.StableAttr{Ino: 2})
|
||||||
|
|
||||||
|
r.AddChild("file.txt", ch, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *BoronInode) Getattr(ctx context.Context, fh fs.FileHandle, out *fuse.AttrOut) syscall.Errno {
|
||||||
|
out.Mode = 0755
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = (fs.NodeGetattrer)((*BoronInode)(nil))
|
||||||
|
var _ = (fs.NodeOnAdder)((*BoronInode)(nil))
|
10
go.mod
10
go.mod
|
@ -1,3 +1,13 @@
|
||||||
module git.greysoh.dev/imterah/boron
|
module git.greysoh.dev/imterah/boron
|
||||||
|
|
||||||
go 1.23.2
|
go 1.23.2
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
|
||||||
|
github.com/hanwen/go-fuse v1.0.0 // indirect
|
||||||
|
github.com/hanwen/go-fuse/v2 v2.7.0 // indirect
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
|
github.com/urfave/cli/v2 v2.27.5 // indirect
|
||||||
|
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
|
||||||
|
golang.org/x/sys v0.27.0 // indirect
|
||||||
|
)
|
||||||
|
|
15
go.sum
Normal file
15
go.sum
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
|
github.com/hanwen/go-fuse v1.0.0 h1:GxS9Zrn6c35/BnfiVsZVWmsG803xwE7eVRDvcf/BEVc=
|
||||||
|
github.com/hanwen/go-fuse v1.0.0/go.mod h1:unqXarDXqzAk0rt98O2tVndEPIpUgLD9+rwFisZH3Ok=
|
||||||
|
github.com/hanwen/go-fuse/v2 v2.7.0 h1:b3khst81C011GCwv9BF7PUa4lbbzIdRFPgAxRlgGUvw=
|
||||||
|
github.com/hanwen/go-fuse/v2 v2.7.0/go.mod h1:ugNaD/iv5JYyS1Rcvi57Wz7/vrLQJo10mmketmoef48=
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w=
|
||||||
|
github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
|
||||||
|
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
|
||||||
|
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
|
||||||
|
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
188
main.go
188
main.go
|
@ -1,7 +1,191 @@
|
||||||
package main
|
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() {
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
51
tmp/key
Normal file
51
tmp/key
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
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
|
||||||
|
-----END PRIVATE KEY-----
|
13
tmp/src/keys/da39a3ee5e6b4b0d3255bfef95601890afd80709.pub
Normal file
13
tmp/src/keys/da39a3ee5e6b4b0d3255bfef95601890afd80709.pub
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
-----BEGIN PUBLIC KEY-----
|
||||||
|
MIICCgKCAgEAp7kY9Pa64fgcwaI38bboLarFjsS2P6V93Kwt98bjC1avPrclaIUM
|
||||||
|
phYYVT4hRnhhkP2LNwS+Qk/rWr8QuRdaSPSjlospgMQ20VfDIZBRYYU/sTC4hhuC
|
||||||
|
IMStnukCyVTrFgHsWMT7A+dd7OWxiZOQbO7FeFdds2vs/5T5ZOGoXAXxTHA0+Bft
|
||||||
|
PtvUjm/Edz7csam73ItGlaF8zFZqSUQa6Zgl1+LYvTrEyOymTGlipo7p86cGveLF
|
||||||
|
/i9v3NfPB7QbjZHPaS4DIz+zzaSP3glHXudI8aZJB1lKKQOGl3JHRiY0PhIPwZRB
|
||||||
|
KyXkYfomAaK++Wvr78a1mYMYRvPoEZbUI7fNAQrewVSsYSr5PgnhTrcWR/6URUB9
|
||||||
|
/ys3OJHHQnhLYRrJfpSroUZuVKYFUSSVwJe74thJJUbbCgzhMDpHuRM6YLNwXtOy
|
||||||
|
53iyYY/N61bUlESg/VoVRRmMmR4srE2jfTkOhaX7nzLWxIJ+wc9SLMItEJwqn/57
|
||||||
|
OPdBU7AefEy9CER35XJjy6wku3VhdHISYKunCW3uS/kA+xlTEgrdAyBKWi870q5G
|
||||||
|
Sj6uCBmJyNCMwj+bCC+sWEbOhVKHBjXdOervyP4/CWF9XrCrqndzgcupXMdCGQG9
|
||||||
|
H+BmXN1bOgIosd38hjdjLo+yiKo4MmhLWjBCVs9WFW5Tm8m7LZ50/lUCAwEAAQ==
|
||||||
|
-----END PUBLIC KEY-----
|
Loading…
Add table
Add a link
Reference in a new issue