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() {
var err error
role := flag.Int("role", 0, "role number")
passphrase := flag.String("code", "chou", "codephrase")
flag.Parse()
c := croc.Init()
if *role == -1 {
err = c.Relay()
} else if *role == 0 {
err = c.Send("foo")
err = c.Send("foo", *passphrase)
} else {
err = c.Receive()
err = c.Receive(*passphrase)
}
if err != nil {
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
func (c *Croc) Send(fname string) (err error) {
err = c.client(0)
func (c *Croc) Send(fname string, codephrase string) (err error) {
err = c.client(0, codephrase)
return
}
// Receive will receive something through the croc relay
func (c *Croc) Receive() (err error) {
err = c.client(1)
func (c *Croc) Receive(codephrase string) (err error) {
err = c.client(1, codephrase)
return
}

View File

@ -9,14 +9,15 @@ import (
log "github.com/cihub/seelog"
"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()
codePhrase := "chou"
// initialize the channel data for this client
c.cs.Lock()
c.cs.channel.codePhrase = codePhrase
if len(codePhrase) > 0 {
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.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()
interrupt := make(chan os.Signal, 1)
@ -55,7 +62,7 @@ func (c *Croc) client(role int) (err error) {
return
}
log.Debugf("recv: %s", cd)
err = c.processState(cd)
err = c.processState(ws, cd)
if err != nil {
log.Warn(err)
return
@ -66,7 +73,7 @@ func (c *Croc) client(role int) (err error) {
// initialize by joining as corresponding role
// TODO:
// allowing suggesting a channel
p := payload{
p := channelData{
Open: true,
Role: role,
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
// waiting (with timeout) for the server to close the connection.
log.Debug("sending close signal")
errWrite := ws.WriteJSON(payload{
errWrite := ws.WriteJSON(channelData{
Channel: channel,
UUID: uuid,
Close: true,
@ -111,7 +118,7 @@ func (c *Croc) client(role int) (err error) {
return
}
func (c *Croc) processState(cd channelData) (err error) {
func (c *Croc) processState(ws *websocket.Conn, cd channelData) (err error) {
c.cs.Lock()
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.Channel = cd.Channel
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")
return
}
@ -138,6 +154,27 @@ func (c *Croc) processState(cd channelData) (err error) {
c.cs.channel.TransferReady = true
}
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:
// process the client state

View File

@ -1,7 +1,6 @@
package croc
import (
"bytes"
"encoding/json"
"net"
"sync"
@ -45,6 +44,7 @@ func Init() (c *Croc) {
c.CurveType = "p521"
c.rs.Lock()
c.rs.channel = make(map[string]*channelData)
c.cs.channel = new(channelData)
c.rs.Unlock()
return
}
@ -60,17 +60,27 @@ type clientState 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
// Channel is the name of the channel
Channel string `json:"channel,omitempty"`
// Pake contains the information for
// 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
// with their credentials
TransferReady bool `json:"transfer_ready"`
// Ports returns which TCP ports to connect to
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 string `json:"error"`
@ -90,6 +100,7 @@ type channelData struct {
passPhrase string
// sessionKey
sessionKey []byte
pakeDone bool
// relay parameters
// isopen determine whether or not the channel has been opened
@ -105,38 +116,6 @@ type channelData struct {
}
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)
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
}
// 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) {
return bcrypt.GenerateFromPassword(k, 14)
return bcrypt.GenerateFromPassword(k, 12)
}
// checkKHash securely compares a bcrypt hashed password with its possible

View File

@ -8,6 +8,7 @@ import (
"github.com/frankenbeanies/uuid4"
"github.com/gorilla/websocket"
"github.com/pkg/errors"
"github.com/schollz/croc/src/pake"
)
// 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
for {
log.Debug("waiting for next message")
var p payload
err := ws.ReadJSON(&p)
var cd channelData
err := ws.ReadJSON(&cd)
if err != nil {
if _, ok := err.(*websocket.CloseError); ok {
// on forced close, delete the channel
@ -41,10 +42,10 @@ func (c *Croc) startServer(tcpPorts []string, port string) (err error) {
}
break
}
channel, err = c.processPayload(ws, p)
channel, err = c.processPayload(ws, cd)
if err != nil {
// 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()})
c.closeChannel(channel)
return
@ -56,95 +57,95 @@ func (c *Croc) startServer(tcpPorts []string, port string) (err error) {
return
}
func (c *Croc) updateChannel(p payload) (err error) {
func (c *Croc) updateChannel(cd channelData) (err error) {
c.rs.Lock()
defer c.rs.Unlock()
// determine if channel is invalid
if _, ok := c.rs.channel[p.Channel]; !ok {
err = errors.Errorf("channel '%s' does not exist", p.Channel)
if _, ok := c.rs.channel[cd.Channel]; !ok {
err = errors.Errorf("channel '%s' does not exist", cd.Channel)
return
}
// determine if UUID is invalid for channel
if p.UUID != c.rs.channel[p.Channel].uuids[0] &&
p.UUID != c.rs.channel[p.Channel].uuids[1] {
err = errors.Errorf("uuid '%s' is invalid", p.UUID)
if cd.UUID != c.rs.channel[cd.Channel].uuids[0] &&
cd.UUID != c.rs.channel[cd.Channel].uuids[1] {
err = errors.Errorf("uuid '%s' is invalid", cd.UUID)
return
}
// assign each key provided
assignedKeys := []string{}
for key := range p.State {
// 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]
}
// update each
if c.rs.channel[cd.Channel].Pake == nil {
c.rs.channel[cd.Channel].Pake = new(pake.Pake)
}
log.Debugf("assigned %d keys: %v", len(assignedKeys), assignedKeys)
c.rs.channel[cd.Channel].Pake.HkA = cd.Pake.HkA
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
}
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())
c.rs.Lock()
defer c.rs.Unlock()
// determine if sender or recipient
if p.Role != 0 && p.Role != 1 {
err = errors.Errorf("no such role of %d", p.Role)
if cd.Role != 0 && cd.Role != 1 {
err = errors.Errorf("no such role of %d", cd.Role)
return
}
// determine channel
if p.Channel == "" {
if cd.Channel == "" {
// TODO:
// 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
if c.rs.channel[p.Channel].uuids[p.Role] != "" {
err = errors.Errorf("channel '%s' already occupied by role %d", p.Channel, p.Role)
if c.rs.channel[cd.Channel].uuids[cd.Role] != "" {
err = errors.Errorf("channel '%s' already occupied by role %d", cd.Channel, cd.Role)
return
}
}
log.Debug("creating new channel")
if _, ok := c.rs.channel[p.Channel]; !ok {
c.rs.channel[p.Channel] = newChannelData(p.Channel)
if _, ok := c.rs.channel[cd.Channel]; !ok {
c.rs.channel[cd.Channel] = new(channelData)
}
channel = p.Channel
channel = cd.Channel
// assign UUID for the role in the channel
c.rs.channel[p.Channel].uuids[p.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)
c.rs.channel[cd.Channel].uuids[cd.Role] = uuid4.New().String()
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
err = ws.WriteJSON(channelData{
Channel: p.Channel,
UUID: c.rs.channel[p.Channel].uuids[p.Role],
Role: p.Role,
Channel: cd.Channel,
UUID: c.rs.channel[cd.Channel].uuids[cd.Role],
Role: cd.Role,
})
if err != nil {
return
}
// if channel is not open, set initial parameters
if !c.rs.channel[p.Channel].isopen {
c.rs.channel[p.Channel].isopen = true
c.rs.channel[p.Channel].Ports = c.TcpPorts
c.rs.channel[p.Channel].startTime = time.Now()
p.Curve, _ = getCurve(p.Curve)
log.Debugf("(%s) using curve '%s'", p.Channel, p.Curve)
c.rs.channel[p.Channel].State["curve"] = []byte(p.Curve)
if !c.rs.channel[cd.Channel].isopen {
c.rs.channel[cd.Channel].isopen = true
c.rs.channel[cd.Channel].Ports = c.TcpPorts
c.rs.channel[cd.Channel].startTime = time.Now()
c.rs.channel[cd.Channel].Curve = "p256"
}
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
}
@ -166,20 +167,20 @@ func (c *Croc) closeChannel(channel string) {
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())
channel = p.Channel
channel = cd.Channel
// if the request is to close, delete the channel
if p.Close {
log.Debugf("closing channel %s", p.Channel)
c.closeChannel(p.Channel)
if cd.Close {
log.Debugf("closing channel %s", cd.Channel)
c.closeChannel(cd.Channel)
return
}
// if request is to Open, try to open
if p.Open {
channel, err = c.joinChannel(ws, p)
if cd.Open {
channel, err = c.joinChannel(ws, cd)
if err != nil {
return
}
@ -197,9 +198,9 @@ func (c *Croc) processPayload(ws *websocket.Conn, p payload) (channel string, er
c.rs.Unlock()
// if the request is to Update, then update the state
if p.Update {
if cd.Update {
// update
err = c.updateChannel(p)
err = c.updateChannel(cd)
if err != nil {
return
}

View File

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