mirror of
https://github.com/schollz/croc.git
synced 2025-10-11 13:21:00 +02:00
simplify setup
This commit is contained in:
parent
7d07ccfe40
commit
f64427f70d
6 changed files with 78 additions and 84 deletions
|
@ -13,10 +13,15 @@ import (
|
|||
|
||||
func (c *Croc) client(role int) (err error) {
|
||||
defer log.Flush()
|
||||
codePhrase := "chou"
|
||||
|
||||
// initialize the channel data for this client
|
||||
c.cs.Lock()
|
||||
c.cs.channel = newChannelData("")
|
||||
c.cs.channel.codePhrase = codePhrase
|
||||
c.cs.channel.Channel = codePhrase[:3]
|
||||
channel := codePhrase[:3]
|
||||
c.cs.channel.secret["pw"] = []byte(codePhrase[3:])
|
||||
c.cs.Unlock()
|
||||
|
||||
interrupt := make(chan os.Signal, 1)
|
||||
|
@ -45,7 +50,7 @@ func (c *Croc) client(role int) (err error) {
|
|||
log.Debugf("sender read error:", err)
|
||||
return
|
||||
}
|
||||
log.Debugf("recv: %+v", cd)
|
||||
log.Debugf("recv: %s", cd)
|
||||
err = c.processState(cd)
|
||||
if err != nil {
|
||||
log.Warn(err)
|
||||
|
@ -57,10 +62,13 @@ func (c *Croc) client(role int) (err error) {
|
|||
// initialize by joining as corresponding role
|
||||
// TODO:
|
||||
// allowing suggesting a channel
|
||||
err = ws.WriteJSON(payload{
|
||||
Open: true,
|
||||
Role: role,
|
||||
})
|
||||
p := payload{
|
||||
Open: true,
|
||||
Role: role,
|
||||
Channel: channel,
|
||||
}
|
||||
log.Debugf("sending opening payload: %+v", p)
|
||||
err = ws.WriteJSON(p)
|
||||
if err != nil {
|
||||
log.Errorf("problem opening: %s", err.Error())
|
||||
return
|
||||
|
@ -116,16 +124,16 @@ func (c *Croc) processState(cd channelData) (err error) {
|
|||
// initialize if has UUID
|
||||
if cd.UUID != "" {
|
||||
c.cs.channel.UUID = cd.UUID
|
||||
c.cs.channel.Ports = cd.Ports
|
||||
c.cs.channel.Channel = cd.Channel
|
||||
c.cs.channel.Role = cd.Role
|
||||
c.cs.channel.Ports = cd.Ports
|
||||
log.Debugf("initialized client state")
|
||||
return
|
||||
}
|
||||
// copy over the rest of the state
|
||||
if cd.TransferReady {
|
||||
c.cs.channel.TransferReady = true
|
||||
}
|
||||
c.cs.channel.Ports = cd.Ports
|
||||
for key := range cd.State {
|
||||
c.cs.channel.State[key] = cd.State[key]
|
||||
}
|
||||
|
@ -134,6 +142,6 @@ func (c *Croc) processState(cd channelData) (err error) {
|
|||
|
||||
// TODO:
|
||||
// process the client state
|
||||
log.Debugf("processing client state: %+v", c.cs.channel)
|
||||
log.Debugf("processing client state: %+v", c.cs.channel.String2())
|
||||
return
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"crypto/rand"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
mathrand "math/rand"
|
||||
|
@ -27,7 +26,7 @@ func init() {
|
|||
func getRandomName() string {
|
||||
result := []string{}
|
||||
bs := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(bs, mathrand.Uint32())
|
||||
rand.Read(bs)
|
||||
result = mnemonicode.EncodeWordList(result, bs)
|
||||
return strings.Join(result, "-")
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package croc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/elliptic"
|
||||
"encoding/json"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -15,9 +17,9 @@ const (
|
|||
)
|
||||
|
||||
var (
|
||||
// see PAKE setup for more info: https://play.golang.org/p/QLHvINK4qFG
|
||||
// see PAKE setup for more info: https://play.golang.org/p/Sd0eTuuEIWu
|
||||
// availableStates are the varaibles available to the parties involved
|
||||
availableStates = []string{"curve", "Xᵤ", "Xᵥ", "Yᵤ", "Yᵥ", "Uᵤ", "Uᵥ", "Vᵤ", "Vᵥ", "HHBk", "HAk"}
|
||||
availableStates = []string{"curve", "Xᵤ", "Xᵥ", "Yᵤ", "Yᵥ", "Uᵤ", "Uᵥ", "Vᵤ", "Vᵥ", "Bcrypt(Ak)", "Bcrypt(Bk)"}
|
||||
// availableSecrets are the variables available only to a specific client, and not shared
|
||||
availableSecrets = []string{"pw", "Upwᵤ", "Upwᵥ", "α", "αᵤ", "αᵥ", "Vpwᵤ", "Vpwᵥ", "β", "gβᵤ", "gβᵥ", "BZᵤ", "BZᵥ", "BZᵤ", "BZᵥ", "AZᵤ", "AZᵥ", "AZᵤ", "AZᵥ", "Bk", "Ak"}
|
||||
)
|
||||
|
@ -89,12 +91,12 @@ type channelData struct {
|
|||
|
||||
// Private
|
||||
// client parameters
|
||||
|
||||
// codePhrase uses the first 3 characters to establish a channel, and the rest
|
||||
// to form the passphrase
|
||||
codePhrase string
|
||||
// secret are the computed secretes
|
||||
// contains "curve", "h_k", "hh_k", "x", "y"
|
||||
secret map[string][]byte `json:"secret"`
|
||||
|
||||
// relay + client parameters
|
||||
secret map[string][]byte
|
||||
// curve is the type of elliptic curve used for PAKE
|
||||
curve elliptic.Curve
|
||||
|
||||
|
@ -111,15 +113,20 @@ type channelData struct {
|
|||
startTime time.Time
|
||||
}
|
||||
|
||||
type response struct {
|
||||
// various responses
|
||||
Channel string `json:"channel,omitempty"`
|
||||
UUID string `json:"uuid,omitempty"`
|
||||
Data *channelData `json:"data,omitempty"`
|
||||
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)
|
||||
|
||||
// constant responses
|
||||
Success bool `json:"success"`
|
||||
Message string `json:"message"`
|
||||
return string(cdb)
|
||||
}
|
||||
|
||||
type payload struct {
|
||||
|
|
|
@ -32,15 +32,10 @@ func (c *Croc) startServer(tcpPorts []string, port string) (err error) {
|
|||
if _, ok := err.(*websocket.CloseError); ok {
|
||||
// on forced close, delete the channel
|
||||
log.Debug("closed channel")
|
||||
c.rs.Lock()
|
||||
if _, ok := c.rs.channel[channel]; ok {
|
||||
delete(c.rs.channel, channel)
|
||||
}
|
||||
c.rs.Unlock()
|
||||
c.closeChannel(channel)
|
||||
} else {
|
||||
log.Debugf("read:", err)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
channel, err = c.processPayload(ws, p)
|
||||
|
@ -48,9 +43,7 @@ func (c *Croc) startServer(tcpPorts []string, port string) (err error) {
|
|||
// if error, send the error back and then delete the channel
|
||||
log.Warn("problem processing payload %+v: %s", p, err.Error())
|
||||
ws.WriteJSON(channelData{Error: err.Error()})
|
||||
c.rs.Lock()
|
||||
delete(c.rs.channel, p.Channel)
|
||||
c.rs.Unlock()
|
||||
c.closeChannel(channel)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -95,6 +88,7 @@ func (c *Croc) updateChannel(p payload) (err error) {
|
|||
}
|
||||
|
||||
func (c *Croc) joinChannel(ws *websocket.Conn, p payload) (channel string, err error) {
|
||||
log.Debugf("joining channel %s", ws.RemoteAddr().String())
|
||||
c.rs.Lock()
|
||||
defer c.rs.Unlock()
|
||||
|
||||
|
@ -117,6 +111,7 @@ func (c *Croc) joinChannel(ws *websocket.Conn, p payload) (channel string, err e
|
|||
return
|
||||
}
|
||||
}
|
||||
log.Debug("creating new channel")
|
||||
if _, ok := c.rs.channel[p.Channel]; !ok {
|
||||
c.rs.channel[p.Channel] = newChannelData(p.Channel)
|
||||
}
|
||||
|
@ -140,7 +135,7 @@ func (c *Croc) joinChannel(ws *websocket.Conn, p payload) (channel string, err e
|
|||
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, c.rs.channel[p.Channel].curve = getCurve(p.Curve)
|
||||
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)
|
||||
}
|
||||
|
@ -150,15 +145,32 @@ func (c *Croc) joinChannel(ws *websocket.Conn, p payload) (channel string, err e
|
|||
return
|
||||
}
|
||||
|
||||
// closeChannel will shut down current open websockets and delete the channel information
|
||||
func (c *Croc) closeChannel(channel string) {
|
||||
c.rs.Lock()
|
||||
defer c.rs.Unlock()
|
||||
// check if channel exists
|
||||
if _, ok := c.rs.channel[channel]; !ok {
|
||||
return
|
||||
}
|
||||
// close open connections
|
||||
for _, wsConn := range c.rs.channel[channel].websocketConn {
|
||||
if wsConn != nil {
|
||||
wsConn.Close()
|
||||
}
|
||||
}
|
||||
// delete
|
||||
delete(c.rs.channel, channel)
|
||||
}
|
||||
|
||||
func (c *Croc) processPayload(ws *websocket.Conn, p payload) (channel string, err error) {
|
||||
log.Debugf("processing payload from %s", ws.RemoteAddr().String())
|
||||
channel = p.Channel
|
||||
|
||||
// if the request is to close, delete the channel
|
||||
if p.Close {
|
||||
log.Debugf("closing channel %s", p.Channel)
|
||||
c.rs.Lock()
|
||||
delete(c.rs.channel, p.Channel)
|
||||
c.rs.Unlock()
|
||||
c.closeChannel(p.Channel)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -200,7 +212,7 @@ func (c *Croc) processPayload(ws *websocket.Conn, p payload) (channel string, er
|
|||
if wsConn == nil {
|
||||
continue
|
||||
}
|
||||
log.Debugf("writing latest data %+v to %d", c.rs.channel[channel], role)
|
||||
log.Debugf("writing latest data %+v to %d", c.rs.channel[channel].String2(), role)
|
||||
err = wsConn.WriteJSON(c.rs.channel[channel])
|
||||
if err != nil {
|
||||
log.Debugf("problem writing to role %d: %s", role, err.Error())
|
||||
|
@ -221,13 +233,18 @@ func (c *Croc) channelCleanup() {
|
|||
keys[i] = key
|
||||
i++
|
||||
}
|
||||
channelsToDelete := []string{}
|
||||
for _, key := range keys {
|
||||
if time.Since(c.rs.channel[key].startTime) > maximumWait {
|
||||
log.Debugf("channel %s has exceeded time, deleting", key)
|
||||
delete(c.rs.channel, key)
|
||||
channelsToDelete = append(channelsToDelete, key)
|
||||
}
|
||||
}
|
||||
c.rs.Unlock()
|
||||
|
||||
for _, channel := range channelsToDelete {
|
||||
log.Debugf("channel %s has exceeded time, deleting", channel)
|
||||
c.closeChannel(channel)
|
||||
}
|
||||
time.Sleep(1 * time.Minute)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
wiped from the relay server. The encrypted file data never is stored on the relay.
|
||||
|
||||
**Encryption**
|
||||
|
||||
Encryption uses AES-256 with a pbkdf2 derived key (see [RFC2898](http://www.ietf.org/rfc/rfc2898.txt)) where the code phrase shared between the sender and receiver is used as the passphrase. For each of the two encrypted data blocks (metadata stored on relay server, and file data transmitted), a random 8-byte salt is used and a IV is generated according to [NIST Recommendation for Block ciphers, Section 8.2](http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf).
|
||||
|
||||
**Decryption**
|
||||
|
||||
On the receiver's computer, each piece of received encrypted data is written to a separate file. These files are concatenated and then decrypted. The hash of the decrypted file is then checked against the hash transmitted from the sender (part of the meta data block).
|
||||
|
||||
## Run your own relay
|
||||
|
||||
*croc* relies on a TCP relay to staple the parallel incoming and outgoing connections. The relay temporarily stores connection information and the encrypted meta information. The default uses a public relay at, `cowyo.com`, which has a 30-day uptime of 99.989% ([click here to check the current status of the public relay](https://stats.uptimerobot.com/lOwJYIgRm)).
|
||||
|
||||
You can also run your own relay, it is very easy. On your server, `your-server.com`, just run
|
||||
|
||||
```
|
||||
$ croc -relay
|
||||
```
|
||||
|
||||
Now, when you use *croc* to send and receive you should add `-server your-server.com` to use your relay server. Make sure to open up TCP ports 27001-27009.
|
||||
|
||||
# Contribute
|
||||
|
||||
I am awed by all the [great contributions](#acknowledgements) made! If you feel like contributing, in any way, by all means you can send an Issue, a PR, ask a question, or tweet me ([@yakczar](http://ctt.ec/Rq054)).
|
||||
|
||||
# License
|
||||
|
||||
MIT
|
||||
|
||||
# Acknowledgements
|
||||
|
||||
Thanks...
|
||||
|
||||
- ...[@warner](https://github.com/warner) for the [idea](https://github.com/warner/magic-wormhole).
|
||||
- ...[@tscholl2](https://github.com/tscholl2) for the [encryption gists](https://gist.github.com/tscholl2/dc7dc15dc132ea70a98e8542fefffa28).
|
||||
- ...[@skorokithakis](https://github.com/skorokithakis) for [code on proxying two connections](https://www.stavros.io/posts/proxying-two-connections-go/).
|
||||
- ...for making pull requests [@Girbons](https://github.com/Girbons), [@techtide](https://github.com/techtide), [@heymatthew](https://github.com/heymatthew), [@Lunsford94](https://github.com/Lunsford94), [@lummie](https://github.com/lummie), [@jesuiscamille](https://github.com/jesuiscamille), [@threefjord](https://github.com/threefjord), [@marcossegovia](https://github.com/marcossegovia), [@csleong98](https://github.com/csleong98), [@afotescu](https://github.com/afotescu), [@callmefever](https://github.com/callmefever), [@El-JojA](https://github.com/El-JojA), [@anatolyyyyyy](https://github.com/anatolyyyyyy), [@goggle](https://github.com/goggle), [@smileboywtu](https://github.com/smileboywtu)!
|
Loading…
Add table
Add a link
Reference in a new issue