added experimental support for encrypted saves

This commit is contained in:
idk
2018-09-17 23:40:09 -04:00
parent 6bc7558bef
commit 3979d87390
16 changed files with 310 additions and 14 deletions

View File

@ -9,6 +9,8 @@ samhost = sam-host
samport = 7656
args = -r
#WEB_INTERFACE = -tags webface
echo:
@echo "$(GOPATH)"
find . -name "*.go" -exec gofmt -w {} \;
@ -24,6 +26,8 @@ test:
cd manager && go test
deps:
go get -u github.com/gtank/cryptopasta
go get -u golang.org/x/crypto/openpgp
go get -u github.com/zieckey/goini
go get -u github.com/eyedeekay/sam-forwarder
go get -u github.com/eyedeekay/sam-forwarder/udp
@ -31,6 +35,7 @@ deps:
go get -u github.com/eyedeekay/sam-forwarder/manager
go get -u github.com/kpetku/sam3
go get -u github.com/eyedeekay/sam3
go get -u github.com/eyedeekay/samcatd-web
build: clean bin/$(appname)
@ -48,7 +53,10 @@ daemon: clean-daemon bin/$(samcatd)
bin/$(samcatd):
mkdir -p bin
go build -a -tags netgo -ldflags '-w -extldflags "-static"' -o ./bin/$(samcatd) ./daemon/main.go
go build -a -tags netgo $(WEB_INTERFACE) \
-ldflags '-w -extldflags "-static"' \
-o ./bin/$(samcatd) \
./daemon/*.go
all: daemon build server

View File

@ -2,7 +2,7 @@
Forward a local port to i2p over the SAM API, or proxy a destination to a port
on the local host. This is a work-in-progress, but the basic functionality is,
there and it's already pretty useful. Everything TCP works, but UDP forwarding
is still not well tested, and UDP clients aren't enabled yet. I'm out of excuses
is still not well tested(I'm pretty sure it works though). I'm out of excuses
not to finish it now, too.
## building
@ -31,6 +31,11 @@ I need to document it better.
[Besides fixing up the comments, this should help for now.](USAGE.md). I also
need to control output verbosity better.
It doesn't encrypt the .i2pkeys file, so if someone can steal them, then they
can use them to construct tunnels to impersonate you. Experimental support for
encrypted saves has been added. The idea is that only the person with the key
will be able to decrypt and start the tunnels.
TCP is working very well. HTTP mode also exists, which just adds the X-I2P-DEST
headers in. It does this both ways, for applying the dest headers inbound to
identify clients to the server and outbound to identify servers to clients.

View File

@ -5,7 +5,7 @@ Hash: SHA256
Forward a local port to i2p over the SAM API, or proxy a destination to a port
on the local host. This is a work-in-progress, but the basic functionality is,
there and it's already pretty useful. Everything TCP works, but UDP forwarding
is still not well tested, and UDP clients aren't enabled yet. I'm out of excuses
is still not well tested(I'm pretty sure it works though). I'm out of excuses
not to finish it now, too.
## building
@ -34,6 +34,11 @@ I need to document it better.
[Besides fixing up the comments, this should help for now.](USAGE.md). I also
need to control output verbosity better.
It doesn't encrypt the .i2pkeys file, so if someone can steal them, then they
can use them to construct tunnels to impersonate you. Experimental support for
encrypted saves has been added. The idea is that only the person with the key
will be able to decrypt and start the tunnels.
TCP is working very well. HTTP mode also exists, which just adds the X-I2P-DEST
headers in. It does this both ways, for applying the dest headers inbound to
identify clients to the server and outbound to identify servers to clients.
@ -75,12 +80,12 @@ I'm eventually going to make the manager implement net.Conn. This won't be
exposed in the default application probably though, but rather as a library.
-----BEGIN PGP SIGNATURE-----
iQEzBAEBCAAdFiEEcNIGBzi++AUjrK/311wDs5teFOEFAlubSGUACgkQ11wDs5te
FOEiqQf7Bbhd2ibzTliceeIIFg5TbfFVa1TGmo978YxR4V7kFlfSnv4QlxzlX+E0
T8BYPOj353o7gWVF8dni61w9PJzc0+QVYbFoww+S5VTzwLDDb/pp2vxHHgUbQBdB
ziEbERMVxZw3ouHieGt1lG6vj5ol9vpH7r9qTfrKO2TaLk7YCjfX5IZPv4rVpDjR
AvM7IGWIaIMNTkvXLxMXSSbS0XgC/yf6w9cmW0OaJSHgSYQSuM/RETUyCa2lPRRC
0inVziTdYO/DMQ468sjaXLWrFM0bXfSjWCL4wCEXnPnRAzjhA6urXyuT5YVwE7k1
IHbbrDLhJur3SiqhO2mlGzEyMxGCrg==
=qo5s
iQEzBAEBCAAdFiEEcNIGBzi++AUjrK/311wDs5teFOEFAlugc5QACgkQ11wDs5te
FOGJ6gf+LMxjFYJJdATurdL2nA4XRfGUwCHQ6NcI2YaRl1ad6a89uJyoVupYcR5/
r+PJT7G0YPbKvdcbnuS8ybHtR1ZtKZwmZiuVuSzCI6CwTweeq4vQ1mcUJS63m4Fd
EtuRDXwzZEce9zdFKWjVl5r1owfgqWvN9m/RmM35DRZ4frPObuZyaLFNuOa7IMLD
lsgLjuVlmPGC4r6N6j13AE3hqNnxNwexcxvgdAMBFhIhyqPHmWz7WrX9clx5QZG2
4uli0I6TqhG0DA+JuUj+PDLArVEKDQaopDWAd7le+oGrfMG5qjguzEScDWKbgbZT
xEAjuk9JoW6DcS1bsuT03F33GVkFdg==
=lvbg
-----END PGP SIGNATURE-----

68
common.go Normal file
View File

@ -0,0 +1,68 @@
package samforwarder
import (
"github.com/gtank/cryptopasta"
"io/ioutil"
"os"
)
func bytes(k [32]byte) []byte {
var r []byte
for _, v := range k {
r = append(r, v)
}
return r
}
func key(k []byte) *[32]byte {
var r [32]byte
for i, v := range k {
r[i] = v
}
return &r
}
func Encrypt(i2pkeypath, aeskeypath string) error {
if aeskeypath != "" {
if r, e := ioutil.ReadFile(i2pkeypath); e != nil {
return e
} else {
var key *[32]byte
if _, err := os.Stat(aeskeypath); os.IsNotExist(err) {
key = cryptopasta.NewEncryptionKey()
ioutil.WriteFile(aeskeypath, bytes(*key), 644)
} else if err != nil {
return err
}
crypted, err := cryptopasta.Encrypt(r, key)
if err != nil {
return err
}
ioutil.WriteFile(i2pkeypath, crypted, 644)
}
}
return nil
}
func Decrypt(i2pkeypath, aeskeypath string) error {
if aeskeypath != "" {
if r, e := ioutil.ReadFile(i2pkeypath); e != nil {
return e
} else {
if _, err := os.Stat(aeskeypath); os.IsNotExist(err) {
return err
}
if ra, re := ioutil.ReadFile(aeskeypath); re != nil {
return e
} else {
crypted, err := cryptopasta.Decrypt(r, key(ra))
if err != nil {
return err
}
ioutil.WriteFile(i2pkeypath, crypted, 644)
}
//crypted
}
}
return nil
}

27
config/cryptsave.go Normal file
View File

@ -0,0 +1,27 @@
package i2ptunconf
// GetKeyFile takes an argument and a default. If the argument differs from the
// default, the argument is always returned. If the argument and default are
// the same and the key exists, the key is returned. If the key is absent, the
// default is returned.
func (c *Conf) GetKeyFile(arg, def string, label ...string) string {
if arg != def {
return arg
}
if c.config == nil {
return arg
}
if x, o := c.Get("keyfile", label...); o {
return x
}
return arg
}
// SetKeyFile sets the key save directory from the config file
func (c *Conf) SetKeyFile(label ...string) {
if v, ok := c.Get("keyfile", label...); ok {
c.KeyFilePath = v
} else {
c.KeyFilePath = "./"
}
}

View File

@ -18,6 +18,7 @@ import (
type Conf struct {
config *goini.INI
FilePath string
KeyFilePath string
Labels []string
Client bool
Type string
@ -194,6 +195,7 @@ func (c *Conf) I2PINILoad(iniFile string, label ...string) error {
c.SetAccessListType(label...)
c.SetTargetPort443(label...)
c.SetMessageReliability(label...)
c.SetKeyFile(label...)
if v, ok := c.Get("i2cp.accessList", label...); ok {
csv := strings.Split(v, ",")
for _, z := range csv {
@ -258,6 +260,7 @@ func NewSAMForwarderFromConf(config *Conf) (*samforwarder.SAMForwarder, error) {
samforwarder.SetAccessListType(config.AccessListType),
samforwarder.SetAccessList(config.AccessList),
samforwarder.SetMessageReliability(config.MessageReliability),
samforwarder.SetPassword(config.KeyFilePath),
//samforwarder.SetTargetForPort443(config.TargetForPort443),
)
}
@ -317,6 +320,7 @@ func NewSAMClientForwarderFromConf(config *Conf) (*samforwarder.SAMClientForward
samforwarder.SetClientAccessListType(config.AccessListType),
samforwarder.SetClientAccessList(config.AccessList),
samforwarder.SetClientMessageReliability(config.MessageReliability),
samforwarder.SetClientPassword(config.KeyFilePath),
)
}
return nil, nil
@ -375,6 +379,7 @@ func NewSAMSSUForwarderFromConf(config *Conf) (*samforwarderudp.SAMSSUForwarder,
samforwarderudp.SetAccessListType(config.AccessListType),
samforwarderudp.SetAccessList(config.AccessList),
samforwarderudp.SetMessageReliability(config.MessageReliability),
samforwarderudp.SetPassword(config.KeyFilePath),
)
}
return nil, nil
@ -433,6 +438,7 @@ func NewSAMSSUClientForwarderFromConf(config *Conf) (*samforwarderudp.SAMSSUClie
samforwarderudp.SetClientAccessListType(config.AccessListType),
samforwarderudp.SetClientAccessList(config.AccessList),
samforwarderudp.SetClientMessageReliability(config.MessageReliability),
samforwarderudp.SetClientPassword(config.KeyFilePath),
)
}
return nil, nil

View File

@ -9,6 +9,7 @@ import (
import (
"github.com/eyedeekay/sam-forwarder/config"
"github.com/eyedeekay/sam-forwarder/manager"
"github.com/eyedeekay/samcatd-web"
)
type flagOpts []string
@ -41,6 +42,8 @@ var (
"Start a tunnel with the passed parameters(Otherwise, they will be treated as default values.)")
encryptLeaseSet = flag.Bool("l", true,
"Use an encrypted leaseset(true or false)")
encryptKeyFiles = flag.String("cr", "",
"Encrypt/decrypt the key files with a passfile")
inAllowZeroHop = flag.Bool("zi", false,
"Allow zero-hop, non-anonymous tunnels in(true or false)")
outAllowZeroHop = flag.Bool("zo", false,
@ -57,6 +60,8 @@ var (
"Client proxy mode(true or false)")
injectHeaders = flag.Bool("ih", false,
"Inject X-I2P-DEST headers")
webAdmin = flag.Bool("w", false,
"Start web administration interface")
leaseSetKey = flag.String("k", "none",
"key for encrypted leaseset")
leaseSetPrivateKey = flag.String("pk", "none",
@ -107,9 +112,13 @@ var (
"Reduce idle tunnel quantity to X (0 to 5)")
)
var err error
var accessList flagOpts
var config *i2ptunconf.Conf
var (
webinterface *samcatweb.SAMWebConfig
webinterfaceerr error
err error
accessList flagOpts
config *i2ptunconf.Conf
)
func main() {
flag.Var(&accessList, "accesslist", "Specify an access list member(can be used multiple times)")
@ -151,6 +160,7 @@ func main() {
config.CloseIdleTime = config.GetCloseIdleTime(*closeIdleTime, 600000)
config.Type = config.GetType(*client, *udpMode, *injectHeaders, "server")
config.TargetForPort443 = config.GetPort443(*targetPort443, "")
config.KeyFilePath = config.GetKeyFile(*encryptKeyFiles, "")
if manager, err := sammanager.NewSAMManagerFromConf(
config,
@ -160,6 +170,9 @@ func main() {
config.SamPort,
*startUp,
); err == nil {
if *webAdmin {
samcatweb.Serve()
}
manager.Serve()
} else {
log.Fatal(err)

View File

@ -380,3 +380,11 @@ func SetClientAccessList(s []string) func(*SAMClientForwarder) error {
return nil
}
}
//SetPassword sets
func SetClientPassword(s string) func(*SAMClientForwarder) error {
return func(c *SAMClientForwarder) error {
c.passfile = s
return nil
}
}

View File

@ -34,6 +34,9 @@ type SAMClientForwarder struct {
file io.ReadWriter
save bool
// samcatd options
passfile string
// I2CP options
encryptLeaseSet string
leaseSetKey string
@ -231,6 +234,7 @@ func NewSAMClientForwarderFromOptions(opts ...func(*SAMClientForwarder) error) (
s.dest = "none"
s.Type = "client"
s.messageReliability = "none"
s.passfile = ""
for _, o := range opts {
if err := o(&s); err != nil {
return nil, err
@ -257,15 +261,27 @@ func NewSAMClientForwarderFromOptions(opts ...func(*SAMClientForwarder) error) (
if err != nil {
return nil, err
}
err = Encrypt(filepath.Join(s.FilePath, s.TunName+".i2pkeys"), s.passfile)
if err != nil {
return nil, err
}
}
s.file, err = os.Open(filepath.Join(s.FilePath, s.TunName+".i2pkeys"))
if err != nil {
return nil, err
}
err = Decrypt(filepath.Join(s.FilePath, s.TunName+".i2pkeys"), s.passfile)
if err != nil {
return nil, err
}
s.SamKeys, err = sam3.LoadKeysIncompat(s.file)
if err != nil {
return nil, err
}
err = Encrypt(filepath.Join(s.FilePath, s.TunName+".i2pkeys"), s.passfile)
if err != nil {
return nil, err
}
}
return &s, nil
}

View File

@ -401,3 +401,11 @@ func SetAccessList(s []string) func(*SAMForwarder) error {
}
}
*/
//SetPassword sets
func SetPassword(s string) func(*SAMForwarder) error {
return func(c *SAMForwarder) error {
c.passfile = s
return nil
}
}

View File

@ -38,6 +38,9 @@ type SAMForwarder struct {
Type string
// samcatd options
passfile string
// I2CP options
encryptLeaseSet string
leaseSetKey string
@ -328,6 +331,7 @@ func NewSAMForwarderFromOptions(opts ...func(*SAMForwarder) error) (*SAMForwarde
s.clientLock = false
s.connLock = false
s.messageReliability = "none"
s.passfile = ""
for _, o := range opts {
if err := o(&s); err != nil {
return nil, err
@ -351,15 +355,27 @@ func NewSAMForwarderFromOptions(opts ...func(*SAMForwarder) error) (*SAMForwarde
if err != nil {
return nil, err
}
err = Encrypt(filepath.Join(s.FilePath, s.TunName+".i2pkeys"), s.passfile)
if err != nil {
return nil, err
}
}
s.file, err = os.Open(filepath.Join(s.FilePath, s.TunName+".i2pkeys"))
if err != nil {
return nil, err
}
err = Decrypt(filepath.Join(s.FilePath, s.TunName+".i2pkeys"), s.passfile)
if err != nil {
return nil, err
}
s.SamKeys, err = sam3.LoadKeysIncompat(s.file)
if err != nil {
return nil, err
}
err = Encrypt(filepath.Join(s.FilePath, s.TunName+".i2pkeys"), s.passfile)
if err != nil {
return nil, err
}
}
return &s, nil
}

68
udp/common.go Normal file
View File

@ -0,0 +1,68 @@
package samforwarderudp
import (
"github.com/gtank/cryptopasta"
"io/ioutil"
"os"
)
func bytes(k [32]byte) []byte {
var r []byte
for _, v := range k {
r = append(r, v)
}
return r
}
func key(k []byte) *[32]byte {
var r [32]byte
for i, v := range k {
r[i] = v
}
return &r
}
func Encrypt(i2pkeypath, aeskeypath string) error {
if aeskeypath != "" {
if r, e := ioutil.ReadFile(i2pkeypath); e != nil {
return e
} else {
var key *[32]byte
if _, err := os.Stat(aeskeypath); os.IsNotExist(err) {
key = cryptopasta.NewEncryptionKey()
ioutil.WriteFile(aeskeypath, bytes(*key), 644)
} else if err != nil {
return err
}
crypted, err := cryptopasta.Encrypt(r, key)
if err != nil {
return err
}
ioutil.WriteFile(i2pkeypath, crypted, 644)
}
}
return nil
}
func Decrypt(i2pkeypath, aeskeypath string) error {
if aeskeypath != "" {
if r, e := ioutil.ReadFile(i2pkeypath); e != nil {
return e
} else {
if _, err := os.Stat(aeskeypath); os.IsNotExist(err) {
return err
}
if ra, re := ioutil.ReadFile(aeskeypath); re != nil {
return e
} else {
crypted, err := cryptopasta.Decrypt(r, key(ra))
if err != nil {
return err
}
ioutil.WriteFile(i2pkeypath, crypted, 644)
}
//crypted
}
}
return nil
}

View File

@ -372,3 +372,11 @@ func SetClientAccessList(s []string) func(*SAMSSUClientForwarder) error {
return nil
}
}
//SetPassword sets
func SetClientPassword(s string) func(*SAMSSUClientForwarder) error {
return func(c *SAMSSUClientForwarder) error {
c.passfile = s
return nil
}
}

View File

@ -36,6 +36,9 @@ type SAMSSUClientForwarder struct {
file io.ReadWriter
save bool
// samcatd options
passfile string
// I2CP options
encryptLeaseSet string
leaseSetKey string
@ -235,6 +238,7 @@ func NewSAMSSUClientForwarderFromOptions(opts ...func(*SAMSSUClientForwarder) er
s.dest = "none"
s.Type = "udpclient"
s.messageReliability = "none"
s.passfile = ""
for _, o := range opts {
if err := o(&s); err != nil {
return nil, err
@ -261,15 +265,27 @@ func NewSAMSSUClientForwarderFromOptions(opts ...func(*SAMSSUClientForwarder) er
if err != nil {
return nil, err
}
err = Encrypt(filepath.Join(s.FilePath, s.TunName+".i2pkeys"), s.passfile)
if err != nil {
return nil, err
}
}
s.file, err = os.Open(filepath.Join(s.FilePath, s.TunName+".i2pkeys"))
if err != nil {
return nil, err
}
err = Decrypt(filepath.Join(s.FilePath, s.TunName+".i2pkeys"), s.passfile)
if err != nil {
return nil, err
}
s.SamKeys, err = sam3.LoadKeysIncompat(s.file)
if err != nil {
return nil, err
}
err = Encrypt(filepath.Join(s.FilePath, s.TunName+".i2pkeys"), s.passfile)
if err != nil {
return nil, err
}
}
return &s, nil
}

View File

@ -372,3 +372,11 @@ func SetAccessList(s []string) func(*SAMSSUForwarder) error {
return nil
}
}
//SetPassword sets
func SetPassword(s string) func(*SAMSSUForwarder) error {
return func(c *SAMSSUForwarder) error {
c.passfile = s
return nil
}
}

View File

@ -34,6 +34,9 @@ type SAMSSUForwarder struct {
file io.ReadWriter
save bool
// samcatd options
passfile string
// I2CP options
encryptLeaseSet string
leaseSetKey string
@ -236,6 +239,7 @@ func NewSAMSSUForwarderFromOptions(opts ...func(*SAMSSUForwarder) error) (*SAMSS
s.reduceIdleQuantity = "4"
s.Type = "udpserver"
s.messageReliability = "none"
s.passfile = ""
for _, o := range opts {
if err := o(&s); err != nil {
return nil, err
@ -259,15 +263,27 @@ func NewSAMSSUForwarderFromOptions(opts ...func(*SAMSSUForwarder) error) (*SAMSS
if err != nil {
return nil, err
}
err = Encrypt(filepath.Join(s.FilePath, s.TunName+".i2pkeys"), s.passfile)
if err != nil {
return nil, err
}
}
s.file, err = os.Open(filepath.Join(s.FilePath, s.TunName+".i2pkeys"))
if err != nil {
return nil, err
}
err = Decrypt(filepath.Join(s.FilePath, s.TunName+".i2pkeys"), s.passfile)
if err != nil {
return nil, err
}
s.SamKeys, err = sam3.LoadKeysIncompat(s.file)
if err != nil {
return nil, err
}
err = Encrypt(filepath.Join(s.FilePath, s.TunName+".i2pkeys"), s.passfile)
if err != nil {
return nil, err
}
}
return &s, nil
}