mirror of https://github.com/schollz/croc.git
pake works between two clients
This commit is contained in:
parent
f6751dadb9
commit
72e2d4d3d8
5
main.go
5
main.go
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"`
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
115
src/server.go
115
src/server.go
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue