commit 4c2df57ff8ed2fc7ace7672bcaec533f4ada671d Author: Zorchenhimer Date: Sun Aug 4 17:34:41 2024 -0400 Initial commit diff --git a/ciphertext/.gitignore b/ciphertext/.gitignore new file mode 100644 index 0000000..8a18982 --- /dev/null +++ b/ciphertext/.gitignore @@ -0,0 +1 @@ +*.pgp diff --git a/cleartext/.gitignore b/cleartext/.gitignore new file mode 100644 index 0000000..4e083f8 --- /dev/null +++ b/cleartext/.gitignore @@ -0,0 +1,2 @@ +*.txt +!dummy-text.txt diff --git a/cleartext/dummy-text.txt b/cleartext/dummy-text.txt new file mode 100644 index 0000000..0ebbdfe --- /dev/null +++ b/cleartext/dummy-text.txt @@ -0,0 +1,46 @@ +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi consequat +egestas mi sed rhoncus. Duis et nulla nec neque mattis bibendum. Ut volutpat +erat vitae velit sodales suscipit. Nunc malesuada dolor a dolor tempor feugiat. +Donec ut pretium elit, nec malesuada turpis. Aliquam gravida, augue sit amet +pretium ullamcorper, erat ex euismod augue, eleifend consequat massa odio vel +justo. Donec non lacinia sem. Nullam eu est pulvinar, gravida urna eu, +fermentum felis. Fusce sodales pharetra diam, a vehicula elit varius nec. +Suspendisse eget augue eget nunc placerat pulvinar auctor sed enim. + +Nulla malesuada scelerisque semper. Proin et mi a odio ornare sodales in id +sapien. Integer eget quam imperdiet, blandit mi sed, mattis est. Nam nec libero +dolor. Aenean varius magna vitae risus imperdiet, iaculis volutpat erat +faucibus. Phasellus aliquam luctus nisi, vitae ullamcorper elit ultricies nec. +Etiam eu felis non dui fermentum iaculis. Vestibulum volutpat, justo id pretium +pharetra, lorem nisi luctus metus, sed hendrerit nulla sem eget sapien. +Suspendisse ipsum purus, fermentum ut felis et, ultricies vulputate lectus. Sed +eget molestie metus. Quisque vel sem eget felis faucibus viverra. Interdum et +malesuada fames ac ante ipsum primis in faucibus. Morbi varius ullamcorper leo +sed volutpat. Cras varius ipsum mauris, a efficitur neque sodales at. Nunc eget +mauris dui. + +Aenean euismod lectus sit amet justo convallis, sit amet molestie nisi luctus. +Maecenas arcu nulla, rhoncus vel odio vitae, iaculis facilisis nibh. Ut +interdum ex a libero tristique, id eleifend nunc bibendum. Pellentesque +hendrerit nisl enim, vehicula tincidunt dui faucibus vitae. Nulla a facilisis +justo. Quisque vehicula diam at nisi facilisis efficitur. Pellentesque rhoncus +ipsum id ligula aliquet, rhoncus vehicula neque malesuada. Ut felis felis, +pretium non accumsan a, vulputate feugiat dolor. Nullam gravida risus sem, +vitae rhoncus mauris facilisis ac. Nullam iaculis non quam nec dignissim. Nam +sagittis fringilla pharetra. + +Quisque in nunc felis. Sed ut risus convallis nibh sodales luctus. Sed lobortis +sem eros, sit amet lacinia ex sagittis vitae. Vestibulum at dolor pharetra, +aliquam lacus ut, consequat nulla. Nulla nulla metus, scelerisque et porttitor +id, blandit elementum purus. Mauris sagittis sit amet lacus vitae luctus. Etiam +nisl urna, ornare a tincidunt eu, pretium vitae mi. Nam rutrum blandit mollis. +Donec eu tortor sollicitudin, fermentum lorem eu, euismod odio. In hac +habitasse platea dictumst. + +Aliquam pulvinar arcu non ex aliquet, non facilisis nibh lacinia. Praesent id +dictum purus. Morbi nec velit posuere, aliquam arcu sit amet, gravida urna. +Etiam blandit ligula et nibh suscipit ultricies. Quisque lorem mauris, interdum +ut nisl id, tincidunt dignissim leo. Suspendisse potenti. Phasellus et urna +quis ipsum gravida sagittis. Sed id consectetur odio. Pellentesque elit eros, +dignissim sit amet sodales sit amet, mollis nec tellus. Cras consectetur nec +ante porttitor condimentum. diff --git a/client.go b/client.go new file mode 100644 index 0000000..649e9c0 --- /dev/null +++ b/client.go @@ -0,0 +1,294 @@ +package main + +import ( + "fmt" + "os" + //"bytes" + "io" + //_ "embed" + "net/http" + "path/filepath" + "strings" + //"encoding/json" + //"crypto/rsa" + + "github.com/ProtonMail/go-crypto/openpgp" + "github.com/ProtonMail/go-crypto/openpgp/packet" + "github.com/alexflint/go-arg" +) + +const ( + KeyServer string = "127.0.0.1:8080" +) + +type Arguments struct { + CmdEncrypt *ArgEncrypt `arg:"subcommand:encrypt"` + CmdDecrypt *ArgDecrypt `arg:"subcommand:decrypt"` +} + +type ArgEncrypt struct { + Input string `arg:"positional,required"` + Recipient string `arg:"--recipient,required"` + Output string `arg:"--output,required"` +} + +type ArgDecrypt struct { + Input string `arg:"positional,required"` + Output string `arg:"positional,required"` +} + +func run(args *Arguments) error { + var err error + + switch { + case args.CmdEncrypt != nil: + err = encrypt(args.CmdEncrypt) + case args.CmdDecrypt != nil: + err = decrypt(args.CmdDecrypt) + default: + err = fmt.Errorf("unknown command") + } + + return err +} + +type KeyType string + +const ( + PublicKey KeyType = "pubkey" + PrivateKey KeyType = "privkey" +) + +func getKey(search string, keytype KeyType) (openpgp.EntityList, error) { + resp, err := http.Get(fmt.Sprintf("http://%s/%s/%s", + KeyServer, + keytype, + search, + )) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode != 200 { + errstr := &strings.Builder{} + fmt.Fprintf(errstr, "Error getting public key: %s\n", resp.Status) + + content, err := io.ReadAll(resp.Body) + if err != nil { + fmt.Fprintf(errstr, "error reading error response: %s\n", err) + return nil, fmt.Errorf(errstr.String()) + } + + fmt.Fprintln(errstr, content) + return nil, fmt.Errorf(errstr.String()) + } + + return openpgp.ReadKeyRing(resp.Body) +} + +func encrypt(args *ArgEncrypt) error { + info, err := os.Stat(args.Input) + if err != nil { + return err + } + + infile, err := os.Open(args.Input) + if err != nil { + return err + } + defer infile.Close() + + keyring, err := getKey(args.Recipient, PublicKey) + + hints := &openpgp.FileHints{ + IsBinary: true, + FileName: filepath.Base(args.Input), + ModTime: info.ModTime(), + } + + outfile, err := os.Create(args.Output) + if err != nil { + return err + } + defer outfile.Close() + + writer, err := openpgp.Encrypt(outfile, keyring, nil, hints, nil) + if err != nil { + return err + } + defer writer.Close() + + _, err = io.Copy(writer, infile) + return err +} + +func decrypt(args *ArgDecrypt) error { + infile, err := os.Open(args.Input) + if err != nil { + return err + } + defer infile.Close() + + var keyring openpgp.EntityList + for { + p, err := packet.Read(infile) + if err == io.EOF { + break + } else if err != nil { + //fmt.Println("packet read error:", err) + continue + } + + keypacket, ok := p.(*packet.EncryptedKey) + if !ok { + continue + } + + keys, err := getKey(fmt.Sprintf("%X", keypacket.KeyId), PrivateKey) + if err != nil { + fmt.Println(err) + continue + } + + keyring = append(keyring, keys...) + } + + if len(keyring) == 0 { + return fmt.Errorf("No decryption keys found") + } + + _, err = infile.Seek(0, 0) + if err != nil { + return err + } + + msg, err := openpgp.ReadMessage(infile, keyring, nil, nil) + if err != nil { + return err + } + + outfile, err := os.Create(args.Output) + if err != nil { + return err + } + defer outfile.Close() + + _, err = io.Copy(outfile, msg.UnverifiedBody) + return err +} + +//func getKeys(filename string) ([]string, error) { +// file, err := os.Open(filename) +// if err != nil { +// return nil, err +// } +// defer file.Close() +// +// keys := []string{} +// for { +// p, err := packet.Read(file) +// if err != nil { +// if err == io.EOF { +// break +// } +// //fmt.Println("err:", err.Error()) +// continue +// } +// +// enckey, ok := p.(*packet.EncryptedKey) +// if !ok { +// continue +// } +// +// keys = append(keys, fmt.Sprintf("%X", enckey.KeyId)) +// fmt.Println("KeyId:", enckey.KeyId) +// //fmt.Printf("%#v\n", p) +// } +// +// return keys, nil +//} +// +//func decrypt(input, output string, keys openpgp.EntityList) error { +// infile, err := os.Open(input) +// if err != nil { +// return err +// } +// defer infile.Close() +// +// detail, err := openpgp.ReadMessage(infile, keys, nil, nil) +// if err != nil { +// return err +// } +// +// if detail.SignatureError != nil { +// return detail.SignatureError +// } +// +// outfile, err := os.Create(output) +// if err != nil { +// return err +// } +// defer outfile.Close() +// +// _, err = io.Copy(outfile, detail.UnverifiedBody) +// return err +//} +// +//func encrypt(input, output string, keys openpgp.EntityList) error { +// info, err := os.Stat(input) +// if err != nil { +// return err +// } +// +// hints := &openpgp.FileHints{ +// IsBinary: true, +// FileName: input, +// ModTime: info.ModTime(), +// } +// +// infile, err := os.Open(input) +// if err != nil { +// return err +// } +// defer infile.Close() +// +// outraw, err := os.Create(output) +// if err != nil { +// return err +// } +// defer outraw.Close() +// +// writer, err := openpgp.Encrypt(outraw, keys, nil, hints, nil) +// if err != nil { +// return err +// } +// defer writer.Close() +// +// _, err = io.Copy(writer, infile) +// if err != nil { +// return err +// } +// +// return nil +//} +// +//func loadKey() (openpgp.EntityList, error) { +// reader := bytes.NewReader(PrivateKey) +// return openpgp.ReadArmoredKeyRing(reader) +//} +// +//func loadPub() (openpgp.EntityList, error) { +// reader := bytes.NewReader(PublicKey) +// return openpgp.ReadArmoredKeyRing(reader) +//} + +func main() { + args := &Arguments{} + arg.MustParse(args) + + if err := run(args); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..1a20123 --- /dev/null +++ b/go.mod @@ -0,0 +1,15 @@ +module main + +go 1.22.4 + +require ( + github.com/ProtonMail/go-crypto v1.0.0 + github.com/alexflint/go-arg v1.5.1 +) + +require ( + github.com/alexflint/go-scalar v1.2.0 // indirect + github.com/cloudflare/circl v1.3.3 // indirect + golang.org/x/crypto v0.7.0 // indirect + golang.org/x/sys v0.6.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..69db3cd --- /dev/null +++ b/go.sum @@ -0,0 +1,61 @@ +github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= +github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +github.com/alexflint/go-arg v1.5.1 h1:nBuWUCpuRy0snAG+uIJ6N0UvYxpxA0/ghA/AaHxlT8Y= +github.com/alexflint/go-arg v1.5.1/go.mod h1:A7vTJzvjoaSTypg4biM5uYNTkJ27SkNTArtYXnlqVO8= +github.com/alexflint/go-scalar v1.2.0 h1:WR7JPKkeNpnYIOfHRa7ivM21aWAdHD0gEWHCx+WQBRw= +github.com/alexflint/go-scalar v1.2.0/go.mod h1:LoFvNMqS1CPrMVltza4LvnGKhaSpc3oyLEBUZVhhS2o= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= +github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/keys/aliases.sh b/keys/aliases.sh new file mode 100644 index 0000000..375c96e --- /dev/null +++ b/keys/aliases.sh @@ -0,0 +1,2 @@ +alias gpg-customer="gpg --no-default-keyring --keyring=/home/nick/code/pgp/keys/customer-pub.gpg" +alias gpg-internal="gpg --no-default-keyring --keyring=/home/nick/code/pgp/keys/internal.gpg" diff --git a/keys/customer-pub.gpg b/keys/customer-pub.gpg new file mode 100644 index 0000000..2ee1f9d Binary files /dev/null and b/keys/customer-pub.gpg differ diff --git a/keys/generate-keys.go b/keys/generate-keys.go new file mode 100644 index 0000000..cb4395c --- /dev/null +++ b/keys/generate-keys.go @@ -0,0 +1,123 @@ +package main + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "fmt" + "os" + "path/filepath" + //"io" + + //"github.com/ProtonMail/go-crypto/openpgp/armor" +) + +func main() { + err := run() + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +func run() error { + names := []string{ + "internal-A", + "internal-B", + + "customer-A", + "customer-B", + "customer-C", + } + + for _, name := range names { + fmt.Println("Generating keypair for", name) + err := keypair(name) + if err != nil { + return err + } + } + + return nil +} + +const ( + keyDir string = "./" +) + +func keypair(name string) error { + const bitSize int = 4096 + + key, err := rsa.GenerateKey(rand.Reader, bitSize) + if err != nil { + return err + } + + pub := key.Public() + + keyPem := pem.EncodeToMemory( + &pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: x509.MarshalPKCS1PrivateKey(key), + }, + ) + + pubPem := pem.EncodeToMemory( + &pem.Block{ + Type: "RSA PUBLIC KEY", + Bytes: x509.MarshalPKCS1PublicKey(pub.(*rsa.PublicKey)), + }, + ) + + err = os.WriteFile(filepath.Join(keyDir, "public", name+".pem"), pubPem, 0644) + if err != nil { + return err + } + + err = os.WriteFile(filepath.Join(keyDir, "private", name+".pem"), keyPem, 0644) + if err != nil { + return err + } + + pubDerRaw, err := x509.MarshalPKIXPublicKey(pub.(*rsa.PublicKey)) + if err != nil { + return err + } + + pubDer := pem.EncodeToMemory( + &pem.Block{ + Type: "RSA PUBLIC KEY", + Bytes: pubDerRaw, + }, + ) + + err = os.WriteFile(filepath.Join(keyDir, "public", name+".asc"), pubDer, 0644) + if err != nil { + return err + } + + //err = encodeToArmor(filepath.Join(keyDir, "public", name+".asc"), pub.(*rsa.PublicKey)) + //if err != nil { + // return err + //} + + return nil +} + +//func encodeToArmor(filename string, key *rsa.PublicKey) error { +// outfile, err := os.Create(filename) +// if err != nil { +// return err +// } +// defer outfile.Close() +// +// writer, err := armor.Encode(outfile, "PGP PUBLIC KEY", nil) +// if err != nil { +// return err +// } +// defer writer.Close() +// +// _, err = writer.Write(key.) +// return err +//} diff --git a/keys/gpg-generated/cust-a.pub b/keys/gpg-generated/cust-a.pub new file mode 100644 index 0000000..b5b243b --- /dev/null +++ b/keys/gpg-generated/cust-a.pub @@ -0,0 +1,41 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQGNBGavoXABDADdBu6RBZvnE/G8z3xpZTRkPYpGpzdJnh3fnYLxFoCDRfFf6wxt +y6l4NnI33jzty3p9zFCNHc8sBSvYlTTZvMESkIuxsEh7n1qsj14DMXuvdCxg+vYT +1ogfkN30Du9afCC76zWboxxEdpsBj8b/SkuSQUApSVnNL8XU3/xQeX+0DIAKtqsv +4l0hcsc6w4O0xUORwkIsBPFwtYpCrJGc2pIDpveDlaIH9UG6SHkq/JFjyKN3GaHd +qpuVriEXIRqSJ7bH+zlnAysW8N8ckWjtUSef4C6ENxdQ/qvmprsILMhbpkHCoiII +V6gmoRkenIOjAuVuDfXBWNA/qilHUlw8QlfmfHW769D3DQhncTTQO4dcGR0/4T9r +hTAJ467i3nRKpuZTRwql3xPuMdB9JSWKmWqYDvOxP5y+qfRM68OWTtwCCHUn1KxT +mFK3EBh7Q7kiKgN4mZBFvfvWItq1QeMaHrcbo8Ak/ETxIOFdE7w8zK6GSyMxvolz +rzF2UBgSvKrPhdsAEQEAAbQfQ3VzdG9tZXIgQSA8Y3VzdC1hQGV4YW1wbGUuY29t +PokB0QQTAQgAOxYhBDWyJkZ8oMl3eLoyCDhKtMml2hZkBQJmr6FwAhsDBQsJCAcC +AiICBhUKCQgLAgQWAgMBAh4HAheAAAoJEDhKtMml2hZkOh8MAKeIDnbIZNRKomzp +nxEi7/1vROBwzZ1dL9o7lgmYhcjm0OVOQTl3g2Xg9F3doiisoPyd5+KQhQQfGQh+ +bDWuhg2An5Br6+sb8xmX1cYtUeTnuQFhy+hZ0FWOJNoTRfQZqtidlE62njT/TNuX +tm2zMBEf+HRayYzxTznr990dmos3NrPCZGx/DJZTdDEHPlk1es+kfyh26Bigk5wT +LV5W7q1TcDEjFkRfMyLXpvIsz2KKDcRYxJFlH6p2P1iQWi8fcrKyNKphjTs3OMjE ++S9Ug0o+ufNwtpnloZKT0UcwxcPrJgCAUNOnuOVcE+12yc868Gsl//ZvLT77Yn5q +H6sQIEJXObSpmqH4r8pxe++5/96yFllhMBiKoM9XPh6jvDnYM40zdKa2HiFj3Fc6 +RcYef90StI63H9uZoIl8o1/oyQsH851CuGPl0V6i9f2lNzfMHEqMZvjtu0HUUw3U +4p4E5Y9dTWx6O9xZuGHymsOrVNq6kEE8gaujC+EQhxgE2YIq6LkBjQRmr6FwAQwA +s8MLHMQDxDOWWG6PFe0tCRSrQGq1rbsRpfkYKp7l5uG1cJaAlU6Hi57BK884eaMf +IcxmezuSnvWfAa4FzkZ+97621XZ1jQfAOrxaEaA59hWdjXm0kaDCGQsv7gl0YNZk +JMxVehQ6TeYA0et6QsIKIXpRMwylmqNZ6tbEi3MaKvaGLc5OgDmJkrQ0EE1ODjgZ +CZfRQ+tHIdn/A88A73fDtxkNAE48R/45W1oBuufqZ7YAwW5MT7Ib4/QpZrttD87q +BgMF47Sgz5SdD5jOAUzjWptPJwK8bhadagT1M4kljAAjs6TtfOAPjuYe4nJ/29jT +hjF7XH+AAo/ZCSRodA2SkcboysKCuPAsPTih9t9DhxA2LAEpmTzt6uaPdv6ce0m7 +gB3uPT7APbYXo2wXt1O2LI+mlmqdLNv/kTeUt/CGvxSbPRYi4qfrqTSwth7dj3Kk +xnNSuOshF6zRN4sG8fJqdGWy99kfM3TE351GoVOKsZF1zBBreJdm9ADWegVZTJtl +ABEBAAGJAbYEGAEIACAWIQQ1siZGfKDJd3i6Mgg4SrTJpdoWZAUCZq+hcAIbDAAK +CRA4SrTJpdoWZC9nC/0Vq99CQRu/pLJe3UhrANxGzm7dzAbtLvZX+mO//5p+X30/ +NofYX8PckZAowTcveWIpomOM9yJJZPOwhFbx0zt0BidVyAqKYX2V09zXLqWLdJx9 +gvpHAh6VF4eyer1ZRyrYXcrGTOsunFDC3tnLVQ/xA88q5ZYRqM6fiGhXFHITQD3n +BjdxqcyqUOGk69Y5grWyRvwfWULXRnLAtcep7LCwvInsHvA/9a+/QMdFSAE/Tmbv ++USZJMTMSvWQ+hpTl0mnXJ/836KaZgD6BcKuwTi7aNRfprYVxVZ6/yG5SOkrLhDS +2Ep8Gr6sUsoaX19XrMKVde1tJx4fCHHa7Cb//kHAlH/4Vf/61OzhOqKg4/dZLdmN +gZj9UBAGxAswHxDEztfD1EcpCclcACC6qFajxU1nzXjf1DKfaa0bmuj0xtkIAv/e +ZN3DerrdQPNWmnQsdBOfWv0DPCSZcCteWlWEC6lYTdFFHT2v7JYPfSiRBlNTM5eB +scgQ1rzjpddT6YkUojc= +=gNhC +-----END PGP PUBLIC KEY BLOCK----- diff --git a/keys/gpg-generated/cust-b.pub b/keys/gpg-generated/cust-b.pub new file mode 100644 index 0000000..eb56065 --- /dev/null +++ b/keys/gpg-generated/cust-b.pub @@ -0,0 +1,51 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +=wrGn +-----END PGP PUBLIC KEY BLOCK----- diff --git a/keys/gpg-generated/internal-private.asc b/keys/gpg-generated/internal-private.asc new file mode 100644 index 0000000..902c5cd --- /dev/null +++ b/keys/gpg-generated/internal-private.asc @@ -0,0 +1,105 @@ +-----BEGIN PGP PRIVATE KEY BLOCK----- + +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 +=x751 +-----END PGP PRIVATE KEY BLOCK----- diff --git a/keys/gpg-generated/internal-public.asc b/keys/gpg-generated/internal-public.asc new file mode 100644 index 0000000..c34854e --- /dev/null +++ b/keys/gpg-generated/internal-public.asc @@ -0,0 +1,52 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +TKL8 +=C9ti +-----END PGP PUBLIC KEY BLOCK----- diff --git a/keys/internal.gpg b/keys/internal.gpg new file mode 100644 index 0000000..7187ea0 Binary files /dev/null and b/keys/internal.gpg differ diff --git a/server.go b/server.go new file mode 100644 index 0000000..5876370 --- /dev/null +++ b/server.go @@ -0,0 +1,245 @@ +package main + +import ( + "fmt" + "os" + "net/http" + "syscall" + "os/signal" + "time" + "context" + //"encoding/json" + "strings" + + "github.com/ProtonMail/go-crypto/openpgp" + //"github.com/ProtonMail/go-crypto/openpgp/packet" +) + +type Server struct { + PublicKeys openpgp.EntityList + PrivateKeys openpgp.EntityList + + //PubkeyGroups []*openpgp.Entity +} + +func NewServer(publicKeys, privateKeys []string) (*Server, error) { + pub, err := loadKeysFromFiles(publicKeys) + if err != nil { + return nil, err + } + + priv, err := loadKeysFromFiles(privateKeys) + if err != nil { + return nil, err + } + + return &Server{PublicKeys: pub, PrivateKeys: priv}, nil +} + +func loadKeysFromFiles(filenames []string) (openpgp.EntityList, error) { + var keyring openpgp.EntityList + + for _, f := range filenames { + file, err := os.Open(f) + if err != nil { + return nil, err + } + + keys, err := openpgp.ReadArmoredKeyRing(file) + if err != nil { + file.Close() + return nil, err + } + file.Close() + + keyring = append(keyring, keys...) + } + + return keyring, nil +} + +func (s *Server) handler_publickey(w http.ResponseWriter, r *http.Request) { + path := strings.Split(strings.Trim(r.URL.Path, "/"), "/") + if len(path) < 2 { + fmt.Fprintln(w, "missing path stuff") + return + } + fmt.Println(r.URL.Path) + + search := strings.ToLower(path[1]) + fmt.Println("searching for", search) + + key := s.findPubKey(search) + if key == nil { + http.Error(w, "Key not found", 500) + return + } + + err := key.Serialize(w) + if err != nil { + fmt.Printf("Serialization error: %s\n", err) + } +} + +func (s *Server) findPubKey(search string) *openpgp.Entity { + for _, k := range s.PublicKeys { + for _, id := range k.Identities { + if strings.ToLower(id.UserId.Name) == search { + return k + } + + if strings.ToLower(id.UserId.Email) == search { + return k + } + } + } + + return nil +} + +func (s *Server) handler_privatekey(w http.ResponseWriter, r *http.Request) { + path := strings.Split(strings.Trim(r.URL.Path, "/"), "/") + if len(path) < 2 { + fmt.Fprintln(w, "missing path stuff") + return + } + fmt.Println(r.URL.Path) + + search := strings.ToLower(path[1]) + fmt.Println("searching for", search) + + key := s.findPrivKey(search) + if key == nil { + http.Error(w, "Key not found", 500) + return + } + + err := key.SerializePrivate(w, nil) + if err != nil { + fmt.Printf("Serialization error: %s\n", err) + } +} + +func (s *Server) findPrivKey(search string) *openpgp.Entity { + for _, k := range s.PrivateKeys { + for _, id := range k.Identities { + if strings.ToLower(id.UserId.Name) == search { + return k + } + + if strings.ToLower(id.UserId.Email) == search { + return k + } + } + + for _, sub := range k.Subkeys { + if fmt.Sprintf("%x", sub.PrivateKey.KeyId) == search { + return k + } + } + } + + return nil +} + +func (s *Server) handler_debug(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, "Public Keys:") + for _, key := range s.PublicKeys { + //fmt.Fprintf(w, "%#v\n", key.PrimaryIdentity()) + fmt.Fprintf(w,"%s\n\t%X\n\t%X\n", + key.PrimaryIdentity().Name, + key.PrimaryKey.Fingerprint, + key.PrimaryKey.KeyId, + ) + + //j, err := json.Marshal(key) + //if err != nil { + // fmt.Fprintf(w, "ERROR: %s", err) + // return + //} + + //fmt.Fprintf(w,"\t\t%s\n", j) + } + + fmt.Fprintln(w, "\nPrivate Keys:") + for _, key := range s.PrivateKeys { + //fmt.Fprintf(w, "%#v\n", key.PrimaryIdentity()) + fmt.Fprintf(w,"%s\n\t%X\n\t%X\n", + key.PrimaryIdentity().Name, + key.PrimaryKey.Fingerprint, + key.PrivateKey.KeyId, + ) + + for _, sub := range key.Subkeys { + fmt.Fprintf(w, "\t>%X\n\t>%X\n", + sub.PublicKey.KeyId, + sub.PrivateKey.KeyId, + ) + } + } +} + +func handler_default(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, "henlo") +} + +func run() error { + sv, err := NewServer( + []string{ + "keys/gpg-generated/cust-a.pub", + "keys/gpg-generated/cust-b.pub", + "keys/gpg-generated/internal-public.asc", + }, + []string{ + "keys/gpg-generated/internal-private.asc", + }, + ) + if err != nil { + return err + } + + mux := http.NewServeMux() + mux.HandleFunc("/pubkey/", sv.handler_publickey) + mux.HandleFunc("/privkey/", sv.handler_privatekey) + mux.HandleFunc("/debug/", sv.handler_debug) + mux.HandleFunc("/", handler_default) + + server := &http.Server{ + Addr: ":8080", + Handler: mux, + ReadTimeout: 10 * time.Second, + WriteTimeout: 10 * time.Second, + MaxHeaderBytes: 1 << 20, + } + + done := make(chan os.Signal, 1) + signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) + + go func() { + fmt.Println("listening on", server.Addr) + if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { + fmt.Println("Listen: ", err) + } + }() + + <-done + fmt.Println("stopping") + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + if err := server.Shutdown(ctx); err != nil { + fmt.Println("Clean shutdown failed: ", err) + } + fmt.Println("goodbye") + + return nil +} + +func main() { + err := run() + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +}