1
1
Fork 0
mirror of https://github.com/schollz/croc.git synced 2025-10-11 13:21:00 +02:00

pake works between two clients

This commit is contained in:
Zack Scholl 2018-06-29 19:34:21 -07:00
parent f6751dadb9
commit 72e2d4d3d8
7 changed files with 124 additions and 108 deletions

View file

@ -9,15 +9,16 @@ import (
func main() { func main() {
var err error var err error
role := flag.Int("role", 0, "role number") role := flag.Int("role", 0, "role number")
passphrase := flag.String("code", "chou", "codephrase")
flag.Parse() flag.Parse()
c := croc.Init() c := croc.Init()
if *role == -1 { if *role == -1 {
err = c.Relay() err = c.Relay()
} else if *role == 0 { } else if *role == 0 {
err = c.Send("foo") err = c.Send("foo", *passphrase)
} else { } else {
err = c.Receive() err = c.Receive(*passphrase)
} }
if err != nil { if err != nil {
panic(err) panic(err)

View file

@ -10,13 +10,13 @@ func (c *Croc) Relay() error {
} }
// Send will take an existing file or folder and send it through the croc relay // Send will take an existing file or folder and send it through the croc relay
func (c *Croc) Send(fname string) (err error) { func (c *Croc) Send(fname string, codephrase string) (err error) {
err = c.client(0) err = c.client(0, codephrase)
return return
} }
// Receive will receive something through the croc relay // Receive will receive something through the croc relay
func (c *Croc) Receive() (err error) { func (c *Croc) Receive(codephrase string) (err error) {
err = c.client(1) err = c.client(1, codephrase)
return return
} }

View file

@ -9,14 +9,15 @@ import (
log "github.com/cihub/seelog" log "github.com/cihub/seelog"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"github.com/schollz/croc/src/pake"
) )
func (c *Croc) client(role int) (err error) { func (c *Croc) client(role int, codePhrase string) (err error) {
defer log.Flush() defer log.Flush()
codePhrase := "chou"
// initialize the channel data for this client // initialize the channel data for this client
c.cs.Lock() c.cs.Lock()
c.cs.channel.codePhrase = codePhrase c.cs.channel.codePhrase = codePhrase
if len(codePhrase) > 0 { if len(codePhrase) > 0 {
if len(codePhrase) < 4 { if len(codePhrase) < 4 {
@ -25,7 +26,13 @@ func (c *Croc) client(role int) (err error) {
} }
c.cs.channel.Channel = codePhrase[:3] c.cs.channel.Channel = codePhrase[:3]
c.cs.channel.passPhrase = codePhrase[3:] c.cs.channel.passPhrase = codePhrase[3:]
} else {
// TODO
// generate code phrase
c.cs.channel.Channel = "chou"
c.cs.channel.passPhrase = codePhrase[3:]
} }
channel := c.cs.channel.Channel
c.cs.Unlock() c.cs.Unlock()
interrupt := make(chan os.Signal, 1) interrupt := make(chan os.Signal, 1)
@ -55,7 +62,7 @@ func (c *Croc) client(role int) (err error) {
return return
} }
log.Debugf("recv: %s", cd) log.Debugf("recv: %s", cd)
err = c.processState(cd) err = c.processState(ws, cd)
if err != nil { if err != nil {
log.Warn(err) log.Warn(err)
return return
@ -66,7 +73,7 @@ func (c *Croc) client(role int) (err error) {
// initialize by joining as corresponding role // initialize by joining as corresponding role
// TODO: // TODO:
// allowing suggesting a channel // allowing suggesting a channel
p := payload{ p := channelData{
Open: true, Open: true,
Role: role, Role: role,
Channel: channel, Channel: channel,
@ -92,7 +99,7 @@ func (c *Croc) client(role int) (err error) {
// Cleanly close the connection by sending a close message and then // Cleanly close the connection by sending a close message and then
// waiting (with timeout) for the server to close the connection. // waiting (with timeout) for the server to close the connection.
log.Debug("sending close signal") log.Debug("sending close signal")
errWrite := ws.WriteJSON(payload{ errWrite := ws.WriteJSON(channelData{
Channel: channel, Channel: channel,
UUID: uuid, UUID: uuid,
Close: true, Close: true,
@ -111,7 +118,7 @@ func (c *Croc) client(role int) (err error) {
return return
} }
func (c *Croc) processState(cd channelData) (err error) { func (c *Croc) processState(ws *websocket.Conn, cd channelData) (err error) {
c.cs.Lock() c.cs.Lock()
defer c.cs.Unlock() defer c.cs.Unlock()
@ -130,6 +137,15 @@ func (c *Croc) processState(cd channelData) (err error) {
c.cs.channel.UUID = cd.UUID c.cs.channel.UUID = cd.UUID
c.cs.channel.Channel = cd.Channel c.cs.channel.Channel = cd.Channel
c.cs.channel.Role = cd.Role c.cs.channel.Role = cd.Role
c.cs.channel.Curve = cd.Curve
c.cs.channel.Pake, err = pake.Init([]byte(c.cs.channel.passPhrase), cd.Role, getCurve(cd.Curve))
c.cs.channel.Update = true
log.Debugf("updating channel")
errWrite := ws.WriteJSON(c.cs.channel)
if errWrite != nil {
log.Error(errWrite)
}
c.cs.channel.Update = false
log.Debugf("initialized client state") log.Debugf("initialized client state")
return return
} }
@ -138,6 +154,27 @@ func (c *Croc) processState(cd channelData) (err error) {
c.cs.channel.TransferReady = true c.cs.channel.TransferReady = true
} }
c.cs.channel.Ports = cd.Ports c.cs.channel.Ports = cd.Ports
if cd.Pake != nil && cd.Pake.Role != c.cs.channel.Role {
log.Debugf("updating pake from %d", cd.Pake.Role)
if c.cs.channel.Pake.HkA == nil {
err = c.cs.channel.Pake.Update(cd.Pake.Bytes())
if err != nil {
log.Error(err)
log.Debug("sending close signal")
c.cs.channel.Close = true
c.cs.channel.Error = err.Error()
ws.WriteJSON(c.cs.channel)
return
}
c.cs.channel.Update = true
log.Debugf("updating channel")
errWrite := ws.WriteJSON(c.cs.channel)
if errWrite != nil {
log.Error(errWrite)
}
c.cs.channel.Update = false
}
}
// TODO: // TODO:
// process the client state // process the client state

View file

@ -1,7 +1,6 @@
package croc package croc
import ( import (
"bytes"
"encoding/json" "encoding/json"
"net" "net"
"sync" "sync"
@ -45,6 +44,7 @@ func Init() (c *Croc) {
c.CurveType = "p521" c.CurveType = "p521"
c.rs.Lock() c.rs.Lock()
c.rs.channel = make(map[string]*channelData) c.rs.channel = make(map[string]*channelData)
c.cs.channel = new(channelData)
c.rs.Unlock() c.rs.Unlock()
return return
} }
@ -60,17 +60,27 @@ type clientState struct {
} }
type channelData struct { type channelData struct {
// Relay actions
// Open set to true when trying to open
Open bool `json:"open"`
// Update set to true when updating
Update bool `json:"update"`
// Close set to true when closing:
Close bool `json:"close"`
// Public // Public
// Channel is the name of the channel // Channel is the name of the channel
Channel string `json:"channel,omitempty"` Channel string `json:"channel,omitempty"`
// Pake contains the information for // Pake contains the information for
// generating the session key over an insecure channel // generating the session key over an insecure channel
Pake pake.Pake Pake *pake.Pake
// TransferReady is set by the relaying when both parties have connected // TransferReady is set by the relaying when both parties have connected
// with their credentials // with their credentials
TransferReady bool `json:"transfer_ready"` TransferReady bool `json:"transfer_ready"`
// Ports returns which TCP ports to connect to // Ports returns which TCP ports to connect to
Ports []string `json:"ports"` Ports []string `json:"ports"`
// Curve is the type of elliptic curve to use
Curve string `json:"curve"`
// Error is sent if there is an error // Error is sent if there is an error
Error string `json:"error"` Error string `json:"error"`
@ -90,6 +100,7 @@ type channelData struct {
passPhrase string passPhrase string
// sessionKey // sessionKey
sessionKey []byte sessionKey []byte
pakeDone bool
// relay parameters // relay parameters
// isopen determine whether or not the channel has been opened // isopen determine whether or not the channel has been opened
@ -105,38 +116,6 @@ type channelData struct {
} }
func (cd channelData) String2() string { func (cd channelData) String2() string {
for key := range cd.State {
if bytes.Equal(cd.State[key], []byte{}) {
delete(cd.State, key)
}
}
for key := range cd.secret {
if !bytes.Equal(cd.secret[key], []byte{}) {
cd.State[key] = cd.secret[key]
}
}
cdb, _ := json.Marshal(cd) cdb, _ := json.Marshal(cd)
return string(cdb) return string(cdb)
} }
type payload struct {
// Open set to true when trying to open
Open bool `json:"open"`
// Channel is used to designate the channel of interest
Channel string `json:"channel"`
// Role designates which role the person will take;
// 0 for sender and 1 for recipient.
Role int `json:"role"`
// Curve is the curve to be used.
Curve string `json:"curve"`
// Update set to true when updating
Update bool `json:"update"`
UUID string `json:"uuid"`
// State is the state information to be updated
State map[string][]byte `json:"state"`
// Close set to true when closing:
Close bool `json:"close"`
}

View file

@ -177,9 +177,9 @@ func (p *Pake) Update(qBytes []byte) (err error) {
return return
} }
// hashK generates a bcrypt hash of the password using work factor 14. // hashK generates a bcrypt hash of the password using work factor 12.
func hashK(k []byte) ([]byte, error) { func hashK(k []byte) ([]byte, error) {
return bcrypt.GenerateFromPassword(k, 14) return bcrypt.GenerateFromPassword(k, 12)
} }
// checkKHash securely compares a bcrypt hashed password with its possible // checkKHash securely compares a bcrypt hashed password with its possible

View file

@ -8,6 +8,7 @@ import (
"github.com/frankenbeanies/uuid4" "github.com/frankenbeanies/uuid4"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/schollz/croc/src/pake"
) )
// startServer initiates the server which listens for websocket connections // startServer initiates the server which listens for websocket connections
@ -29,8 +30,8 @@ func (c *Croc) startServer(tcpPorts []string, port string) (err error) {
var channel string var channel string
for { for {
log.Debug("waiting for next message") log.Debug("waiting for next message")
var p payload var cd channelData
err := ws.ReadJSON(&p) err := ws.ReadJSON(&cd)
if err != nil { if err != nil {
if _, ok := err.(*websocket.CloseError); ok { if _, ok := err.(*websocket.CloseError); ok {
// on forced close, delete the channel // on forced close, delete the channel
@ -41,10 +42,10 @@ func (c *Croc) startServer(tcpPorts []string, port string) (err error) {
} }
break break
} }
channel, err = c.processPayload(ws, p) channel, err = c.processPayload(ws, cd)
if err != nil { if err != nil {
// if error, send the error back and then delete the channel // if error, send the error back and then delete the channel
log.Warn("problem processing payload %+v: %s", p, err.Error()) log.Warn("problem processing payload %+v: %s", cd, err.Error())
ws.WriteJSON(channelData{Error: err.Error()}) ws.WriteJSON(channelData{Error: err.Error()})
c.closeChannel(channel) c.closeChannel(channel)
return return
@ -56,95 +57,95 @@ func (c *Croc) startServer(tcpPorts []string, port string) (err error) {
return return
} }
func (c *Croc) updateChannel(p payload) (err error) { func (c *Croc) updateChannel(cd channelData) (err error) {
c.rs.Lock() c.rs.Lock()
defer c.rs.Unlock() defer c.rs.Unlock()
// determine if channel is invalid // determine if channel is invalid
if _, ok := c.rs.channel[p.Channel]; !ok { if _, ok := c.rs.channel[cd.Channel]; !ok {
err = errors.Errorf("channel '%s' does not exist", p.Channel) err = errors.Errorf("channel '%s' does not exist", cd.Channel)
return return
} }
// determine if UUID is invalid for channel // determine if UUID is invalid for channel
if p.UUID != c.rs.channel[p.Channel].uuids[0] && if cd.UUID != c.rs.channel[cd.Channel].uuids[0] &&
p.UUID != c.rs.channel[p.Channel].uuids[1] { cd.UUID != c.rs.channel[cd.Channel].uuids[1] {
err = errors.Errorf("uuid '%s' is invalid", p.UUID) err = errors.Errorf("uuid '%s' is invalid", cd.UUID)
return return
} }
// assign each key provided // update each
assignedKeys := []string{} if c.rs.channel[cd.Channel].Pake == nil {
for key := range p.State { c.rs.channel[cd.Channel].Pake = new(pake.Pake)
// TODO:
// add a check that the value of key is not enormous
// add only if it is a valid key
if _, ok := c.rs.channel[p.Channel].State[key]; ok {
assignedKeys = append(assignedKeys, key)
c.rs.channel[p.Channel].State[key] = p.State[key]
}
} }
c.rs.channel[cd.Channel].Pake.HkA = cd.Pake.HkA
log.Debugf("assigned %d keys: %v", len(assignedKeys), assignedKeys) c.rs.channel[cd.Channel].Pake.HkB = cd.Pake.HkB
c.rs.channel[cd.Channel].Pake.Role = cd.Pake.Role
c.rs.channel[cd.Channel].Pake.Uᵤ = cd.Pake.Uᵤ
c.rs.channel[cd.Channel].Pake.Uᵥ = cd.Pake.Uᵥ
c.rs.channel[cd.Channel].Pake.Vᵤ = cd.Pake.Vᵤ
c.rs.channel[cd.Channel].Pake.Vᵥ = cd.Pake.Vᵥ
c.rs.channel[cd.Channel].Pake.Xᵤ = cd.Pake.Xᵤ
c.rs.channel[cd.Channel].Pake.Xᵥ = cd.Pake.Xᵥ
c.rs.channel[cd.Channel].Pake.Yᵤ = cd.Pake.Yᵤ
c.rs.channel[cd.Channel].Pake.Yᵥ = cd.Pake.Yᵥ
// TODO
return return
} }
func (c *Croc) joinChannel(ws *websocket.Conn, p payload) (channel string, err error) { func (c *Croc) joinChannel(ws *websocket.Conn, cd channelData) (channel string, err error) {
log.Debugf("joining channel %s", ws.RemoteAddr().String()) log.Debugf("joining channel %s", ws.RemoteAddr().String())
c.rs.Lock() c.rs.Lock()
defer c.rs.Unlock() defer c.rs.Unlock()
// determine if sender or recipient // determine if sender or recipient
if p.Role != 0 && p.Role != 1 { if cd.Role != 0 && cd.Role != 1 {
err = errors.Errorf("no such role of %d", p.Role) err = errors.Errorf("no such role of %d", cd.Role)
return return
} }
// determine channel // determine channel
if p.Channel == "" { if cd.Channel == "" {
// TODO: // TODO:
// find an empty channel // find an empty channel
p.Channel = "chou" cd.Channel = "chou"
} }
if _, ok := c.rs.channel[p.Channel]; ok { if _, ok := c.rs.channel[cd.Channel]; ok {
// channel is not empty // channel is not empty
if c.rs.channel[p.Channel].uuids[p.Role] != "" { if c.rs.channel[cd.Channel].uuids[cd.Role] != "" {
err = errors.Errorf("channel '%s' already occupied by role %d", p.Channel, p.Role) err = errors.Errorf("channel '%s' already occupied by role %d", cd.Channel, cd.Role)
return return
} }
} }
log.Debug("creating new channel") log.Debug("creating new channel")
if _, ok := c.rs.channel[p.Channel]; !ok { if _, ok := c.rs.channel[cd.Channel]; !ok {
c.rs.channel[p.Channel] = newChannelData(p.Channel) c.rs.channel[cd.Channel] = new(channelData)
} }
channel = p.Channel channel = cd.Channel
// assign UUID for the role in the channel // assign UUID for the role in the channel
c.rs.channel[p.Channel].uuids[p.Role] = uuid4.New().String() c.rs.channel[cd.Channel].uuids[cd.Role] = uuid4.New().String()
log.Debugf("(%s) %s has joined as role %d", p.Channel, c.rs.channel[p.Channel].uuids[p.Role], p.Role) log.Debugf("(%s) %s has joined as role %d", cd.Channel, c.rs.channel[cd.Channel].uuids[cd.Role], cd.Role)
// send Channel+UUID back to the current person // send Channel+UUID back to the current person
err = ws.WriteJSON(channelData{ err = ws.WriteJSON(channelData{
Channel: p.Channel, Channel: cd.Channel,
UUID: c.rs.channel[p.Channel].uuids[p.Role], UUID: c.rs.channel[cd.Channel].uuids[cd.Role],
Role: p.Role, Role: cd.Role,
}) })
if err != nil { if err != nil {
return return
} }
// if channel is not open, set initial parameters // if channel is not open, set initial parameters
if !c.rs.channel[p.Channel].isopen { if !c.rs.channel[cd.Channel].isopen {
c.rs.channel[p.Channel].isopen = true c.rs.channel[cd.Channel].isopen = true
c.rs.channel[p.Channel].Ports = c.TcpPorts c.rs.channel[cd.Channel].Ports = c.TcpPorts
c.rs.channel[p.Channel].startTime = time.Now() c.rs.channel[cd.Channel].startTime = time.Now()
p.Curve, _ = getCurve(p.Curve) c.rs.channel[cd.Channel].Curve = "p256"
log.Debugf("(%s) using curve '%s'", p.Channel, p.Curve)
c.rs.channel[p.Channel].State["curve"] = []byte(p.Curve)
} }
c.rs.channel[p.Channel].websocketConn[p.Role] = ws c.rs.channel[cd.Channel].websocketConn[cd.Role] = ws
log.Debugf("assigned role %d in channel '%s'", p.Role, p.Channel) log.Debugf("assigned role %d in channel '%s'", cd.Role, cd.Channel)
return return
} }
@ -166,20 +167,20 @@ func (c *Croc) closeChannel(channel string) {
delete(c.rs.channel, channel) delete(c.rs.channel, channel)
} }
func (c *Croc) processPayload(ws *websocket.Conn, p payload) (channel string, err error) { func (c *Croc) processPayload(ws *websocket.Conn, cd channelData) (channel string, err error) {
log.Debugf("processing payload from %s", ws.RemoteAddr().String()) log.Debugf("processing payload from %s", ws.RemoteAddr().String())
channel = p.Channel channel = cd.Channel
// if the request is to close, delete the channel // if the request is to close, delete the channel
if p.Close { if cd.Close {
log.Debugf("closing channel %s", p.Channel) log.Debugf("closing channel %s", cd.Channel)
c.closeChannel(p.Channel) c.closeChannel(cd.Channel)
return return
} }
// if request is to Open, try to open // if request is to Open, try to open
if p.Open { if cd.Open {
channel, err = c.joinChannel(ws, p) channel, err = c.joinChannel(ws, cd)
if err != nil { if err != nil {
return return
} }
@ -197,9 +198,9 @@ func (c *Croc) processPayload(ws *websocket.Conn, p payload) (channel string, er
c.rs.Unlock() c.rs.Unlock()
// if the request is to Update, then update the state // if the request is to Update, then update the state
if p.Update { if cd.Update {
// update // update
err = c.updateChannel(p) err = c.updateChannel(cd)
if err != nil { if err != nil {
return return
} }

View file

@ -70,8 +70,7 @@ func splitFile(fileName string, numPieces int) (err error) {
return nil return nil
} }
func getCurve(s string) (curveString string, curve elliptic.Curve) { func getCurve(s string) (curve elliptic.Curve) {
curveString = s
switch s { switch s {
case "p224": case "p224":
curve = elliptic.P224() curve = elliptic.P224()
@ -84,7 +83,6 @@ func getCurve(s string) (curveString string, curve elliptic.Curve) {
default: default:
// TODO: // TODO:
// add SIEC // add SIEC
curveString = "p256"
curve = elliptic.P256() curve = elliptic.P256()
} }
return return