use keypair to validate

This commit is contained in:
Zack Scholl 2018-06-23 09:18:35 -07:00
parent 60e31803c9
commit 30c9c3317f
3 changed files with 174 additions and 31 deletions

View File

@ -1,6 +1,7 @@
package main
import (
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
@ -18,6 +19,7 @@ import (
"time"
"github.com/dustin/go-humanize"
"github.com/schollz/messagebox/keypair"
"github.com/schollz/peerdiscovery"
"github.com/schollz/progressbar"
tarinator "github.com/schollz/tarinator-go"
@ -43,6 +45,8 @@ type Connection struct {
Wait bool
bar *progressbar.ProgressBar
rate int
keypair keypair.KeyPair
encryptedPassword string
}
type FileMetaData struct {
@ -73,6 +77,7 @@ func NewConnection(config *AppConfig) (*Connection, error) {
c.Yes = config.Yes
c.rate = config.Rate
c.Local = config.Local
c.keypair, _ = keypair.New()
if c.Local {
c.Yes = true
@ -213,6 +218,10 @@ func (c *Connection) Run() error {
if err := SplitFile(c.File.Name+".enc", c.NumberOfConnections); err != nil {
return err
}
// remove the file now since we still have pieces
if err := os.Remove(c.File.Name + ".enc"); err != nil {
return err
}
// get file hash
var err error
@ -221,14 +230,10 @@ func (c *Connection) Run() error {
return err
}
// get file size
c.File.Size, err = FileSize(c.File.Name + ".enc")
c.File.Size, err = FileSize(c.File.Name)
if err != nil {
return err
}
// remove the file now since we still have pieces
if err := os.Remove(c.File.Name + ".enc"); err != nil {
return err
}
// remove compressed archive
if c.File.IsDir {
@ -241,16 +246,19 @@ func (c *Connection) Run() error {
fmt.Fprintf(os.Stderr, "Code is: %s\n", c.Code)
// broadcast local connection from sender
log.Debug("settings payload to ", c.Code)
go func() {
go peerdiscovery.Discover(peerdiscovery.Settings{
Limit: 1,
TimeLimit: 600 * time.Second,
Delay: 50 * time.Millisecond,
Payload: []byte(c.Code),
})
runClientError <- c.runClient("localhost")
}()
if c.Server == "" {
log.Debug("settings payload to ", c.Code)
go func() {
go peerdiscovery.Discover(peerdiscovery.Settings{
Limit: 1,
TimeLimit: 600 * time.Second,
Delay: 50 * time.Millisecond,
Payload: []byte(c.Code),
})
runClientError <- c.runClient("localhost")
}()
}
}
log.Debug("checking code validity")
@ -330,19 +338,19 @@ func (c *Connection) runClient(serverName string) error {
log.Error(err)
}
encryptedMetaData, salt, iv := Encrypt(metaData, c.Code)
sendMessage("s."+c.HashedCode+"."+hex.EncodeToString(encryptedMetaData)+"-"+salt+"-"+iv, connection)
sendMessage("s."+c.keypair.Public+"."+c.HashedCode+"."+hex.EncodeToString(encryptedMetaData)+"-"+salt+"-"+iv, connection)
} else {
log.Debugf("telling relay (%s): %s", c.Server, "r."+c.Code)
if c.Wait {
// tell server to wait for sender
sendMessage("r."+c.HashedCode+".0.0.0", connection)
sendMessage("r."+c.keypair.Public+"."+c.HashedCode+".0.0.0", connection)
} else {
// tell server to cancel if sender doesn't exist
sendMessage("c."+c.HashedCode+".0.0.0", connection)
sendMessage("c."+c.keypair.Public+"."+c.HashedCode+".0.0.0", connection)
}
}
if c.IsSender { // this is a sender
log.Debug("waiting for ok from relay")
log.Debugf("[%d] waiting for ok from relay", id)
message = receiveMessage(connection)
if message == "timeout" {
responses.Lock()
@ -359,10 +367,33 @@ func (c *Connection) runClient(serverName string) error {
responses.gotConnectionInUse = true
responses.Unlock()
} else {
log.Debug("got ok from relay")
// message is IP address, lets check next message
log.Debugf("[%d] got ok from relay: %s", id, message)
publicKeyRecipient := receiveMessage(connection)
if id == 0 {
fmt.Fprintf(os.Stderr, "\nSending (->%s)..\n", message)
fmt.Fprintf(os.Stderr, "\nSending (->%s@%s)..\n", publicKeyRecipient, message)
// check if okay again
// TODO
encryptedPassword, err := c.keypair.Encrypt([]byte(RandStringBytesMaskImprSrc(20)), publicKeyRecipient)
if err != nil {
panic(err)
}
// encrypt files
c.encryptedPassword = base64.StdEncoding.EncodeToString(encryptedPassword)
}
log.Debugf("[%d] waiting for 0 thread to encrypt", id)
for {
if c.encryptedPassword != "" {
break
}
time.Sleep(10 * time.Millisecond)
}
log.Debugf("sending encrypted passphrase: %s", c.encryptedPassword)
sendMessage(c.encryptedPassword, connection)
// wait for relay go
receiveMessage(connection)
// wait for pipe to be made
time.Sleep(100 * time.Millisecond)
// Write data from file
@ -399,6 +430,9 @@ func (c *Connection) runClient(serverName string) error {
} else if strings.Split(sendersAddress, ":")[0] == "127.0.0.1" {
sendersAddress = strings.Replace(sendersAddress, "127.0.0.1", c.Server, 1)
}
// now get public key
publicKeySender := receiveMessage(connection)
// have the main thread ask for the okay
if id == 0 {
encryptedBytes, err := hex.DecodeString(encryptedData)
@ -436,6 +470,7 @@ func (c *Connection) runClient(serverName string) error {
fmt.Fprintf(os.Stderr, "Will not overwrite file!")
os.Exit(1)
}
fmt.Fprintf(os.Stderr, "incoming file from "+publicKeySender+"\n")
getOK := "y"
if !c.Yes {
getOK = getInput("ok? (y/n): ")
@ -466,6 +501,9 @@ func (c *Connection) runClient(serverName string) error {
if !gotOK {
sendMessage("not ok", connection)
} else {
sendMessage("ok", connection)
c.encryptedPassword = receiveMessage(connection)
log.Debugf("[%d] got encrypted passphrase: %s", id, c.encryptedPassword)
sendMessage("ok", connection)
log.Debug("receive file")
if id == 0 {

View File

@ -19,6 +19,10 @@ type connectionMap struct {
sender map[string]net.Conn
metadata map[string]string
potentialReceivers map[string]struct{}
rpublicKey map[string]string
spublicKey map[string]string
passphrase map[string]string
receiverReady map[string]bool
sync.RWMutex
}
@ -64,7 +68,11 @@ func (r *Relay) Run() {
r.connections.receiver = make(map[string]net.Conn)
r.connections.sender = make(map[string]net.Conn)
r.connections.metadata = make(map[string]string)
r.connections.spublicKey = make(map[string]string)
r.connections.rpublicKey = make(map[string]string)
r.connections.passphrase = make(map[string]string)
r.connections.potentialReceivers = make(map[string]struct{})
r.connections.receiverReady = make(map[string]bool)
r.connections.Unlock()
r.runServer()
}
@ -124,12 +132,13 @@ func (r *Relay) clientCommuncation(id int, connection net.Conn) {
sendMessage("who?", connection)
m := strings.Split(receiveMessage(connection), ".")
if len(m) < 3 {
if len(m) < 4 {
logger.Debug("exiting, not enough information")
sendMessage("not enough information", connection)
return
}
connectionType, codePhrase, metaData := m[0], m[1], m[2]
connectionType, publicKey, codePhrase, metaData := m[0], m[1], m[2], m[3]
logger.Debugf("got connection from %s", publicKey)
key := codePhrase + "-" + strconv.Itoa(id)
switch connectionType {
@ -142,9 +151,11 @@ func (r *Relay) clientCommuncation(id int, connection net.Conn) {
r.connections.Lock()
r.connections.metadata[key] = metaData
r.connections.sender[key] = connection
r.connections.spublicKey[key] = publicKey
r.connections.Unlock()
// wait for receiver
receiversAddress := ""
receiversPublicKey := ""
isTimeout := time.Duration(0)
for {
if CONNECTION_TIMEOUT <= isTimeout {
@ -154,16 +165,38 @@ func (r *Relay) clientCommuncation(id int, connection net.Conn) {
r.connections.RLock()
if _, ok := r.connections.receiver[key]; ok {
receiversAddress = r.connections.receiver[key].RemoteAddr().String()
logger.Debug("got receiver")
r.connections.RUnlock()
break
}
if _, ok := r.connections.rpublicKey[key]; ok {
receiversPublicKey = r.connections.rpublicKey[key]
}
r.connections.RUnlock()
if receiversAddress != "" && receiversPublicKey != "" {
break
}
time.Sleep(100 * time.Millisecond)
isTimeout += 100 * time.Millisecond
}
logger.Debug("telling sender ok")
sendMessage(receiversAddress, connection)
sendMessage(receiversPublicKey, connection)
// TODO ASK FOR OKAY HERE TOO
logger.Debug("waiting for encrypted passphrase")
encryptedPassphrase := receiveMessage(connection)
r.connections.Lock()
r.connections.passphrase[key] = encryptedPassphrase
r.connections.Unlock()
// wait for receiver ready
for {
r.connections.RLock()
if _, ok := r.connections.receiverReady[key]; ok {
r.connections.RUnlock()
break
}
r.connections.RUnlock()
}
// go reciever ready tell sender to go
sendMessage("go", connection)
logger.Debug("preparing pipe")
r.connections.Lock()
con1 := r.connections.sender[key]
@ -192,20 +225,28 @@ func (r *Relay) clientCommuncation(id int, connection net.Conn) {
// add as a potential receiver
r.connections.Lock()
r.connections.potentialReceivers[key] = struct{}{}
r.connections.rpublicKey[key] = publicKey
r.connections.receiver[key] = connection
r.connections.Unlock()
// wait for sender's metadata
sendersAddress := ""
sendersPublicKey := ""
for {
r.connections.RLock()
if _, ok := r.connections.metadata[key]; ok {
if _, ok2 := r.connections.sender[key]; ok2 {
sendersAddress = r.connections.sender[key].RemoteAddr().String()
logger.Debug("got sender meta data")
r.connections.RUnlock()
break
}
}
if _, ok := r.connections.spublicKey[key]; ok {
sendersPublicKey = r.connections.spublicKey[key]
logger.Debugf("got sender public key: %s", sendersPublicKey)
}
r.connections.RUnlock()
if sendersAddress != "" && sendersPublicKey != "" {
break
}
if connectionType == "c" {
sendMessage("0-0-0-0.0.0.0", connection)
// sender is not ready so delete connection
@ -219,16 +260,49 @@ func (r *Relay) clientCommuncation(id int, connection net.Conn) {
// send meta data
r.connections.RLock()
sendMessage(r.connections.metadata[key]+"-"+sendersAddress, connection)
sendMessage(sendersPublicKey, connection)
r.connections.RUnlock()
// now get passphrase
sendersPassphrase := ""
for {
r.connections.RLock()
if _, ok := r.connections.passphrase[key]; ok {
sendersPassphrase = r.connections.passphrase[key]
logger.Debugf("got sender passphrase: %s", sendersPassphrase)
}
r.connections.RUnlock()
if sendersPassphrase != "" {
break
}
}
// check for receiver's consent
consent := receiveMessage(connection)
logger.Debugf("consent: %s", consent)
if consent == "ok" {
logger.Debug("got consent")
r.connections.Lock()
r.connections.receiver[key] = connection
r.connections.Unlock()
// wait for encrypted passphrase
encryptedPassphrase := ""
for {
r.connections.RLock()
if _, ok := r.connections.passphrase[key]; ok {
encryptedPassphrase = r.connections.passphrase[key]
logger.Debugf("got passphrase: %s", r.connections.passphrase[key])
}
r.connections.RUnlock()
if encryptedPassphrase != "" {
break
}
time.Sleep(10 * time.Millisecond)
}
sendMessage(encryptedPassphrase, connection)
}
receiveMessage(connection)
time.Sleep(10 * time.Millisecond)
r.connections.Lock()
r.connections.receiverReady[key] = true
r.connections.Unlock()
default:
logger.Debugf("Got unknown protocol: '%s'", connectionType)
}

View File

@ -5,9 +5,11 @@ import (
"fmt"
"io"
"math"
math_rand "math/rand"
"net"
"os"
"strconv"
"time"
"github.com/pkg/errors"
)
@ -173,3 +175,32 @@ func GetLocalIP() string {
}
return bestIP
}
// src is seeds the random generator for generating random strings
var src = math_rand.NewSource(time.Now().UnixNano())
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
const (
letterIdxBits = 6 // 6 bits to represent a letter index
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
)
// RandStringBytesMaskImprSrc prints a random string
func RandStringBytesMaskImprSrc(n int) string {
b := make([]byte, n)
// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
if remain == 0 {
cache, remain = src.Int63(), letterIdxMax
}
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
b[i] = letterBytes[idx]
i--
}
cache >>= letterIdxBits
remain--
}
return string(b)
}